Merge pull request 'Add LifeCycleLogLabel Test Case Modular and Manager, Merge Logger to core' (#7) from dev-mrkbear into master

Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/7
This commit is contained in:
MrKBear 2021-12-01 10:55:54 +08:00
commit ce7d6c74f0
18 changed files with 1082 additions and 430 deletions

View File

@ -0,0 +1,17 @@
page {
background-color: #f4f0f1;
color: rgba(0, 0, 0, .55);
font-weight: 500;
font-size: .9em;
font-family: 'Lucida Sans',
'Lucida Sans Regular', 'Lucida Grande',
'Lucida Sans Unicode', 'Geneva', 'Verdana', 'sans-serif';
}
@media (prefers-color-scheme: dark){
page {
background-color: #1f1f1f;
color: rgba(255, 255, 255, .55);
}
}

View File

@ -1,4 +1,6 @@
import { Logger, LevelLogLabel } from "./logger/index"; import { Logger } from "./logger/Logger";
import { LevelLogLabel } from "./logger/LevelLogLabel";
import { LifeCycleLogLabel } from "./logger/LifeCycleLogLabel";
App<IAppOption>({ App<IAppOption>({
@ -12,25 +14,7 @@ App<IAppOption>({
* *
*/ */
onLaunch() { onLaunch() {
Logger.log("小程序启动...",
console.log(Logger.l({val:"hh"}, LevelLogLabel.TraceLabel, LifeCycleLogLabel.OnLaunchLabel);
LevelLogLabel.FatalLabel,LevelLogLabel.ErrorLabel,LevelLogLabel.WarnLabel,
LevelLogLabel.InfoLabel,LevelLogLabel.DebugLabel,LevelLogLabel.TraceLabel
));
console.log(Logger.m(
[LevelLogLabel.FatalLabel,LevelLogLabel.ErrorLabel,LevelLogLabel.WarnLabel,
LevelLogLabel.InfoLabel,LevelLogLabel.DebugLabel,LevelLogLabel.TraceLabel], {val:"hh"}, "hh"
));
console.log(Logger.ll({val:"hh"},
LevelLogLabel.FatalLabel,LevelLogLabel.ErrorLabel,LevelLogLabel.WarnLabel,
LevelLogLabel.InfoLabel,LevelLogLabel.DebugLabel,LevelLogLabel.TraceLabel
));
console.log(Logger.lm(
[LevelLogLabel.FatalLabel,LevelLogLabel.ErrorLabel,LevelLogLabel.WarnLabel,
LevelLogLabel.InfoLabel,LevelLogLabel.DebugLabel,LevelLogLabel.TraceLabel], {val:"hh"}, "hh"
));
} }
}) })

View File

@ -134,5 +134,94 @@ class LogStyle {
} }
} }
export default LogStyle; /**
export {LogStyle}; *
*/
class LogLabel {
/**
*
*
*/
public key:string;
/**
*
*/
public style:LogStyle;
/**
*
*/
public checked:boolean;
/**
*
*/
public display:boolean;
/**
*
*
*/
public attach:boolean;
/**
* @param key
* @param style
*/
constructor(key:string, style:LogStyle,
checked?:boolean, display?:boolean, attach?:boolean) {
this.key = key;
this.style = style;
this.checked = checked ?? true;
this.display = display ?? true;
this.attach = attach ?? false;
}
/**
* Logger 使
*/
public getLoggerOutput():string {
if(!this.display) return "";
return `%c${ this.key }`;
}
/**
* Text
*/
public getTextOutput():string {
if(!this.display) return "";
return `[${ this.key }]`;
}
/**
* style
*/
public getStyleOutput():string {
if(!this.display) return "";
return this.style.stringify();
}
/**
*
*/
public checking(src:RegExp | string):boolean {
let pass = false;
// 关闭校验
if(!this.checked) return pass;
if(src instanceof RegExp) {
pass = (src as RegExp).test(this.key)
} else {
pass = (src as string) === this.key;
}
return pass;
}
}
export default LogLabel;
export {LogLabel, LogStyle}

View File

@ -1,7 +1,33 @@
import {LOGGER_CONSOLE, LOGGER_FILTER} from "../Config"; import { LOGGER_FILTER, LOGGER_CONSOLE } from "./Config";
import { InternalLogLabel } from "./InternalLogLabel"; import { StackLogLabel } from "./PresetLogLabel";
import { LogLabel } from "./LogLabel"; import { LogLabel } from "./LogLabel";
import { MultipleLogContent } from "./MultipleLogContent";
/**
*
* log
*/
class MultipleLogContent<T extends Array<any>> {
/**
*
*/
private readonly content:T;
/**
* @param content
*/
public constructor(...content:T) {
this.content = content;
}
/**
*
*/
public getContent():T {
return this.content;
}
}
/** /**
* *
@ -93,7 +119,7 @@ class Logger {
// TODO: 这里可以添加一些钩子作为中间件处理日志输出 // TODO: 这里可以添加一些钩子作为中间件处理日志输出
// 测试是否输出内容 // 测试是否输出内容
if(!Logger.testLog(...labels, ...attachLabel, InternalLogLabel.filterUrlLabel)) if(!Logger.testLog(...labels, ...attachLabel, StackLogLabel.filterUrlLabel))
return content.getContent(); return content.getContent();
// 计算收集样式 // 计算收集样式
@ -113,7 +139,7 @@ class Logger {
public static log<T>(content:T, ...labels:LogLabel[]):T { public static log<T>(content:T, ...labels:LogLabel[]):T {
return Logger.logBase<Array<T>>( return Logger.logBase<Array<T>>(
new MultipleLogContent<Array<T>>(content), labels, new MultipleLogContent<Array<T>>(content), labels,
[InternalLogLabel.fileNameLabel] [StackLogLabel.fileNameLabel]
)[0]; )[0];
} }
@ -130,7 +156,7 @@ class Logger {
public static logMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T { public static logMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T {
return Logger.logBase<T>( return Logger.logBase<T>(
new MultipleLogContent<T>(...content), labels, new MultipleLogContent<T>(...content), labels,
[InternalLogLabel.fileNameLabel] [StackLogLabel.fileNameLabel]
); );
} }
@ -147,12 +173,12 @@ class Logger {
public static logLine<T>(content:T, ...labels:LogLabel[]):T { public static logLine<T>(content:T, ...labels:LogLabel[]):T {
return Logger.logBase<Array<T>>( return Logger.logBase<Array<T>>(
new MultipleLogContent<Array<T>>(content), labels, new MultipleLogContent<Array<T>>(content), labels,
[InternalLogLabel.urlLabel, InternalLogLabel.blankLabel] [StackLogLabel.fileNameLabel, StackLogLabel.blankLabel]
)[0]; )[0];
} }
/** /**
* Logger.logMultiple * Logger.logLine
*/ */
public static ll:typeof Logger.logLine = Logger.logLine; public static ll:typeof Logger.logLine = Logger.logLine;
@ -164,7 +190,7 @@ class Logger {
public static logLineMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T { public static logLineMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T {
return Logger.logBase<T>( return Logger.logBase<T>(
new MultipleLogContent<T>(...content), labels, new MultipleLogContent<T>(...content), labels,
[InternalLogLabel.urlLabel, InternalLogLabel.blankLabel] [StackLogLabel.fileNameLabel, StackLogLabel.blankLabel]
); );
} }

356
miniprogram/core/Module.ts Normal file
View File

@ -0,0 +1,356 @@
/**
*
*/
type IAnyTypeObject<T = any> = {
[x:string]: T;
};
// 微信 Data 类型
type Data<D> = WechatMiniprogram.Page.Data<D>;
// 微信生命周期类型
type ILifetime = WechatMiniprogram.Page.ILifetime;
// 继承的方法
type InstanceMethods<D> = WechatMiniprogram.Page.InstanceMethods<D>;
// 继承的属性
type InstanceProperties = WechatMiniprogram.Page.InstanceProperties;
/**
*
*
* @template TD data
* @template TC MinIn
*
* Partial<ILifetime>
* Partial<Data<TD>> data
* InstanceMethods<TD>
* InstanceProperties
*/
type WXContext<TD, TC> = Partial<ILifetime> & Partial<Data<TD>>
& InstanceMethods<TD> & InstanceProperties & TC;
/**
*
*
* 使
*/
type AnyWXContext = WXContext<IAnyTypeObject, IAnyTypeObject>;
/**
*
* 注意: 这是一个递给类型
* @template M 使 manager
*/
type Depends<M extends Manager<AnyWXContext>> = {
[x:string]: Modular<M, Depends<M>>;
};
/**
*
* @template M Manager
* @template DEP
* @template TD Data
*/
class Modular<
M extends Manager<AnyWXContext> = Manager<AnyWXContext>,
DEP extends Depends<M> = Depends<M>,
TD extends IAnyTypeObject = IAnyTypeObject>
implements WXContext<TD, IAnyTypeObject> {
// [x:string]: any;
/**
*
*/
private manager:M;
/**
* Manager
*/
private get context():M["context"] {
return this.manager.context;
}
/**
*
*/
protected depends?:DEP
/**
*
*/
public data?:TD;
/**
* 使
*/
private functionList:Set<string>;
/**
* 使
*/
private paramList:Set<string>;
/**
*
*/
private nameSpace:string;
// 映射主上下文属性
public get is():string { return this.context.is };
public get route():string { return this.context.route };
public get options():Record<string, string | undefined> {
return this.context.options;
};
/**
*
*
* @param manager
* @param nameSpace
* @param depend
*/
public constructor(manager:M, nameSpace:string, depend?: DEP) {
// 保存微信上下文
this.manager = manager;
// 保存模块依赖
this.depends = depend;
// 初始化内部属性
this.functionList = new Set<string>();
this.paramList = new Set<string>();
this.nameSpace = nameSpace;
}
public setData(data:Partial<TD>, callback?: () => void):void {
if(this.data === void 0) {
this.data = {} as TD;
}
let reportData:IAnyTypeObject = {};
for(let key in data) {
(this.data as IAnyTypeObject)[key] = data[key];
reportData[`${ this.nameSpace }$${ key }`] = data[key];
this.paramList.add(key);
}
return this.context.setData(reportData, callback);
}
/**
*
* @param fn
* @param name
*/
public setFunc(fn:Function, name:string):void {
this.functionList.add(name);
(this.context as IAnyTypeObject)
[`${ this.nameSpace }$${ name }`] = fn.bind(this);
}
//#region 映射微信的继承函数
public hasBehavior(behavior: string): void {
return this.context.hasBehavior(behavior);
}
public triggerEvent<DetailType>(name: string, detail?: DetailType,
options?: WechatMiniprogram.Component.TriggerEventOption): void {
return this.context.triggerEvent<DetailType>(name, detail, options);
}
public createSelectorQuery(): WechatMiniprogram.SelectorQuery {
return this.context.createSelectorQuery();
}
public createIntersectionObserver(options: WechatMiniprogram.CreateIntersectionObserverOption):
WechatMiniprogram.IntersectionObserver {
return this.context.createIntersectionObserver(options);
}
public selectComponent(selector: string): WechatMiniprogram.Component.TrivialInstance {
return this.context.selectComponent(selector);
}
public selectAllComponents(selector: string): WechatMiniprogram.Component.TrivialInstance[] {
return this.context.selectAllComponents(selector);
}
public selectOwnerComponent(): WechatMiniprogram.Component.TrivialInstance {
return this.context.selectOwnerComponent();
}
public getRelationNodes(relationKey: string): WechatMiniprogram.Component.TrivialInstance[] {
return this.context.getRelationNodes(relationKey);
}
public groupSetData(callback?: () => void): void {
return this.context.groupSetData(callback);
}
public getTabBar(): WechatMiniprogram.Component.TrivialInstance {
return this.context.getTabBar();
}
public getPageId(): string {
return this.context.getPageId();
}
public animate(selector: string, keyFrames: WechatMiniprogram.Component.KeyFrame[],
duration: number, callback?: () => void): void;
public animate(selector: string, keyFrames: WechatMiniprogram.Component.ScrollTimelineKeyframe[],
duration: number, scrollTimeline: WechatMiniprogram.Component.ScrollTimelineOption): void;
public animate(selector: any, keyFrames: any, duration: any, scrollTimeline?: any): void {
return this.context.animate(selector, keyFrames, duration, scrollTimeline);
}
public clearAnimation(selector: string, callback: () => void): void;
public clearAnimation(selector: string, options?: WechatMiniprogram.Component.ClearAnimationOptions,
callback?: () => void): void;
public clearAnimation(selector: any, options?: any, callback?: any): void {
return this.context.clearAnimation(selector, options, callback);
}
public getOpenerEventChannel(): WechatMiniprogram.EventChannel {
return this.context.getOpenerEventChannel();
}
//#endregion
}
/**
*
*
*/
class Manager<WXC extends AnyWXContext = AnyWXContext> {
/**
*
*/
static readonly WxLifeCycle:(keyof ILifetime)[] = [
"onShow",
"onReady",
"onHide",
"onUnload",
"onPullDownRefresh",
"onReachBottom",
"onShareAppMessage",
"onShareTimeline",
"onAddToFavorites",
"onPageScroll",
"onResize",
"onTabItemTap"
]
/**
*
*/
public context:WXC;
/**
*
*
*/
public constructor(context:WXC) {
// 保存微信上下文
this.context = context;
// 初始化模组列表
this.modules = [];
}
/**
*
*/
public modules:Modular[];
/**
*
* @param mode
* @param nameSpace
* @param depend
* @returns
*/
public addModule<DEP extends Depends<this>, M extends Modular<this, DEP>>
(mode: new (manager:Manager<WXC>, nameSpace:string, depend?:DEP) => M,
nameSpace:string, depend?:DEP):M {
let mod = new mode(this, nameSpace, depend);
this.modules.push(mod);
return mod;
}
/**
*
* @param key
*/
public creatHooks(key:keyof ILifetime):ILifetime[keyof ILifetime] {
return (...arg: any[]) => {
let hooks:Promise<any>[] = [];
let simple:any;
for(let i = 0; i < this.modules.length; i++) {
let res: Promise<any> | any =
(this.modules[i] as IAnyTypeObject)[key](...arg);
if (res instanceof Promise) {
hooks.push(res);
} else {
hooks.push(Promise.resolve(res));
}
if (
key === "onShareAppMessage" ||
key === "onShareTimeline" ||
key === "onAddToFavorites"
) {
// 如果返回值有特殊含义在处理时进行 MinIn
simple = Object.assign({}, simple, res);
} else {
simple = res;
}
}
if(hooks.length === 0) return;
if(hooks.length === 1) return simple;
return Promise.all(hooks);
}
}
/**
*
*/
public creatAllHooks() {
for(let i = 0; i < Manager.WxLifeCycle.length; i++) {
(this.context as IAnyTypeObject)[Manager.WxLifeCycle[i]] =
this.creatHooks(Manager.WxLifeCycle[i]);
}
}
/**
*
*/
public loadAllModule(query:Record<string, string | undefined>) {
this.creatAllHooks();
let res = this.creatHooks("onLoad")(query as any);
return res;
}
}
export { Manager, Modular, AnyWXContext, WXContext, ILifetime}

View File

@ -0,0 +1,313 @@
import { LogLabel, LogStyle } from "./LogLabel";
/**
*
*/
class StackInfo {
/**
*
*/
public functionName:string | undefined;
/**
*
*/
public fileName:string | undefined;
/**
*
*/
public url:string | undefined;
/**
*
*/
public fileNameLine: string | undefined;
/**
*
* @param functionName
* @param fileName
* @param url
*/
public setInfo(functionName:string, fileNameLine:string, url:string):StackInfo {
this.functionName = functionName;
this.fileNameLine = fileNameLine;
this.url = url;
return this;
}
/**
*
*/
public calcFileName():string | undefined {
let replaceToTs = this.fileNameLine?.replace(".js", ".ts");
let matched = replaceToTs?.match(/^(.+\.(js|ts)):\d+:\d+$/);
return matched ? matched[1] : undefined;
}
/**
*
*/
public calcPathName():string | undefined {
let replaceToTs = this.url?.replace(".js", ".ts");
let matched = replaceToTs?.match(/^https?:\/\/(\d+\.){3}\d+:\d+\/(.+):\d+:\d+$/);
return matched ? matched[2] : undefined;
}
/**
*
*/
public static getCallStack():StackInfo[] {
// 获取堆栈信息
let stack:string | undefined = new Error().stack;
if (stack === void 0) return [];
// 去除 Error
stack = stack.replace(/^(Error)\s/, "");
// 获取堆栈信息
let stackList:string[] = stack.split(/\n/);
let callStack:StackInfo[] = [];
for(let i = 0; i < stackList.length; i++) {
let matcher = stackList[i].match(/^\s+at\s+(.+)\s(\(.+\))/);
if (matcher === null || matcher.length < 3) continue;
let fileName = matcher[2].match(/.+\/(.+\..+:\d+:\d+)\)/);
if (fileName === null || matcher.length < 2) continue;
callStack.push(new StackInfo().setInfo(
matcher[1], fileName[1], matcher[2]?.replace(/(\(|\))/g, "")
))
}
// console.log(callStack);
return callStack;
}
/**
*
*/
public static readonly excludeFile:RegExp = /^.*(\\|\/)logger(\\|\/).+\.js:\d+:\d+/;
/**
*
*/
public static getFirstStack():StackInfo | undefined {
let callStack = this.getCallStack();
for(let i = 0; i < callStack.length; i++) {
if(!callStack[i].url) continue;
if(!StackInfo.excludeFile.test(callStack[i].url ?? "")) {
return callStack[i];
}
}
return;
}
}
/**
* LogLabel
*/
class StackLogLabel {
/**
*
*/
public static readonly normalStyle:LogStyle = new LogStyle()
.setColor("#979797").setBorder("4px", "1px solid #979797").setBlank("0 5px");
/**
*
*/
public static readonly blankLabel = new LogLabel("\n\r",
new LogStyle(), false, true, true);
/**
* label
*/
public static get fileNameLabel():LogLabel {
// 获得调用堆栈
let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.calcFileName() ?? "Unknown file name",
StackLogLabel.normalStyle, false, true, true);
}
/**
* URL label
*/
public static get urlLabel():LogLabel {
// 获得调用堆栈
let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.calcPathName() ?? "Unknown url",
StackLogLabel.normalStyle, false, true, true);
}
/**
* filter URL label
*/
public static get filterUrlLabel():LogLabel {
// 获得调用堆栈
let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.calcPathName() ?? "Unknown url",
StackLogLabel.normalStyle, true, false, true);
}
}
/**
*
*/
const normalLevelStyleGen = (color:string):LogStyle => {
return new LogStyle().setBorder("4px", `1px solid ${color}`)
.setColor(color).setBlank("0 5px");
}
/**
*
*/
class LevelLogLabel {
/**
*
*/
static readonly FatalLabel = new LogLabel(
"FATAL", normalLevelStyleGen("#FF00CC")
);
/**
*
*/
static readonly ErrorLabel = new LogLabel(
"ERROR", normalLevelStyleGen("#FF0000")
);
/**
*
*/
static readonly WarnLabel = new LogLabel(
"WARN", normalLevelStyleGen("#FF9900")
);
/**
*
*/
static readonly InfoLabel = new LogLabel(
"INFO", normalLevelStyleGen("#99FF00")
);
/**
*
*/
static readonly DebugLabel = new LogLabel(
"DEBUG", normalLevelStyleGen("#00FF99")
);
/**
*
*/
static readonly TraceLabel = new LogLabel(
"TRACE", normalLevelStyleGen("#00CCFF")
);
}
/**
*
*/
const normalLifeStyleGen = (r:number, g:number, b:number):LogStyle => {
return new LogStyle().setBorder("4px", `1px solid rgb(${ r }, ${ g }, ${ b })`)
.setColor(`rgb(${ r }, ${ g }, ${ b })`, `rgba(${ r }, ${ g }, ${ b }, .1)`)
.setBlank("0 5px");
}
/**
*
*/
class LifeCycleLogLabel {
/**
*
*/
static readonly OnLaunchLabel = new LogLabel(
"onLaunch", normalLifeStyleGen(160, 32, 240)
);
/**
* --
*/
static readonly OnLoadLabel = new LogLabel(
"onLoad", normalLifeStyleGen(255, 140, 105)
);
/**
* --
*/
static readonly OnReadyLabel = new LogLabel(
"onReady", normalLifeStyleGen(255, 127, 36)
);
/**
* --
*/
static readonly OnShowLabel = new LogLabel(
"onShow", normalLifeStyleGen(255, 215, 0)
)
/**
* --
*/
static readonly OnHideLabel = new LogLabel(
"onHide", normalLifeStyleGen(173, 255, 47)
);
/**
* --
*/
static readonly OnUnloadLabel = new LogLabel(
"onUnload", normalLifeStyleGen(127, 255, 212)
);
/**
* --
*/
static readonly OnPullDownRefreshLabel = new LogLabel(
"onPullDownRefresh", normalLifeStyleGen(0, 191, 255)
);
/**
*
*/
static readonly OnReachBottomLabel = new LogLabel(
"onReachBottom", normalLifeStyleGen(84, 255, 159)
);
/**
*
*/
static readonly OnShareAppMessageLabel = new LogLabel(
"onShareAppMessage", normalLifeStyleGen(147, 112, 219)
);
}
export { StackInfo, StackLogLabel, LevelLogLabel, LifeCycleLogLabel };

View File

@ -0,0 +1,205 @@
// import { Logger } from "../logger/Logger";
import { LogStyle, LogLabel } from "./LogLabel";
/**
*
*/
class TestResult {
/**
*
*/
public caseName:string;
/**
*
*/
public result:boolean;
/**
*
*/
public message:string;
/**
*
*/
public attach:string;
/**
*
* @param caseName
*/
constructor(caseName:string) {
this.caseName = caseName;
this.result = false;
this.message = "";
this.attach = "";
}
/**
*
*/
public setResult(result:boolean, message?:string, attach?:string) {
this.result = result;
this.message = message ?? (result ? "success!" : "failed!");
this.attach = attach ?? this.attach;
return this;
}
}
/**
*
*/
type TestFunction = () => TestResult | Promise<TestResult>;
/**
*
*/
class CaseCollect {
/**
*
*/
public key:string;
/**
*
*/
public caseFunction:TestFunction;
/**
*
*/
result: Promise<TestResult> | undefined;
/**
* @param key
* @param caseFunction
*/
public constructor(key:string, caseFunction:TestFunction) {
this.key = key;
this.caseFunction = caseFunction;
}
/**
*
*/
public async runTestCase():Promise<CaseCollect> {
let result = this.caseFunction();
if(result instanceof Promise) {
this.result = result;
} else {
this.result = Promise.resolve(result);
}
return this;
}
public static readonly baseStyle = new LogStyle().setBlank();
public static readonly successLabel:LogLabel = new LogLabel("√",
new LogStyle().setBlank("0 4px").setBorder("1000px", "1px solid green")
);
/**
*
* @param current
* @param total
*/
public printResult(current?:number, total?:number) {
// 如果测试没有运行,先运行它
if(this.result === void 0) this.runTestCase();
this.result?.then((res) => {
if(res.result) {
console.log(
`%c√%c %c1/1%c %c${ this.key }%c ` + res.message,
"padding:0 4px; border-radius:1000px; border:1px solid green; color:green",
"", "padding:0 4px; border-radius:4px; border:1px solid green; color:green",
"", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797",
""
)
} else {
console.log(
`%c√%c %c1/1%c %c${ this.key }%c ` + res.message,
"padding:0 4px; border-radius:1000px; border:1px solid red; color:red",
"", "padding:0 4px; border-radius:4px; border:1px solid red; color:red",
"", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797",
""
)
}
console.log(res)
})
}
/**
*
* @param testCaseClass
*/
public static collectCase(testCaseClass:ITestCase):CaseCollect[] {
// 获取静态方法 key
let key = Object.getOwnPropertyNames(testCaseClass);
// 过滤掉通用的方法和属性
key = key.filter((key) => !/(length|name|prototype)/.test(key) );
// 生成 CaseCollect
let caseCollect = [];
for (let i = 0; i < key.length; i++) {
caseCollect.push(new CaseCollect(key[i], testCaseClass[key[i]]))
}
return caseCollect;
}
/**
*
*/
public static async runCollectCase(cases:CaseCollect[]):Promise<CaseCollect[]> {
let running:Promise<CaseCollect>[] = [];
for(let i = 0; i < cases.length; i++) {
running.push(cases[i].runTestCase());
}
return Promise.all(running);
}
/**
*
*/
public static runUnitTest(testCaseClass:ITestCase) {
let caseCollect = this.collectCase(testCaseClass);
CaseCollect.runCollectCase(caseCollect).then((caseCollect:CaseCollect[]) => {
for(let i = 0; i < caseCollect.length; i++) {
caseCollect[i].printResult()
}
})
}
}
/**
*
*/
interface ITestCase {
/**
*
*/
[key:string]:TestFunction;
}
export default ITestCase;
export { ITestCase, TestResult, TestFunction, CaseCollect };

View File

@ -1,61 +0,0 @@
import { LogStyle } from "./LogStyle";
import { LogLabel } from "./LogLabel";
import { StackInfo } from "./StackInfo";
/**
* LogLabel
*/
class InternalLogLabel {
/**
*
*/
public static readonly normalStyle:LogStyle = new LogStyle()
.setColor("#CCCCCC").setBorder("4px", "1px solid #979797").setBlank("0 5px");
/**
*
*/
public static readonly blankLabel = new LogLabel("\n\r",
new LogStyle(), false, true, true);
/**
* label
*/
public static get fileNameLabel():LogLabel {
// 获得调用堆栈
let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.fileName ?? "Unknown file name",
InternalLogLabel.normalStyle, false, true, true);
}
/**
* URL label
*/
public static get urlLabel():LogLabel {
// 获得调用堆栈
let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.url ?? "Unknown url",
InternalLogLabel.normalStyle, false, true, true);
}
/**
* filter URL label
*/
public static get filterUrlLabel():LogLabel {
// 获得调用堆栈
let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.url ?? "Unknown url",
InternalLogLabel.normalStyle, true, false, true);
}
}
export default InternalLogLabel;
export {InternalLogLabel};

View File

@ -1,61 +0,0 @@
import { LogStyle } from "./LogStyle";
import { LogLabel } from "./LogLabel";
/**
*
*/
const normalStyleGen = (color:string):LogStyle => {
return new LogStyle().setBorder("4px", `1px solid ${color}`)
.setColor(color).setBlank("0 5px");
}
/**
*
*/
class LevelLogLabel {
/**
*
*/
static readonly FatalLabel = new LogLabel(
"FATAL", normalStyleGen("#FF00CC")
);
/**
*
*/
static readonly ErrorLabel = new LogLabel(
"ERROR", normalStyleGen("#FF0000")
);
/**
*
*/
static readonly WarnLabel = new LogLabel(
"WARN", normalStyleGen("#FF9900")
);
/**
*
*/
static readonly InfoLabel = new LogLabel(
"INFO", normalStyleGen("#99FF00")
);
/**
*
*/
static readonly DebugLabel = new LogLabel(
"DEBUG", normalStyleGen("#00FF99")
);
/**
*
*/
static readonly TraceLabel = new LogLabel(
"TRACE", normalStyleGen("#00CCFF")
);
}
export default LevelLogLabel;
export { LevelLogLabel };

View File

@ -1,93 +0,0 @@
import { LogStyle } from "./LogStyle";
/**
*
*/
class LogLabel {
/**
*
*
*/
public key:string;
/**
*
*/
public style:LogStyle;
/**
*
*/
public checked:boolean;
/**
*
*/
public display:boolean;
/**
*
*
*/
public attach:boolean;
/**
* @param key
* @param style
*/
constructor(key:string, style:LogStyle,
checked?:boolean, display?:boolean, attach?:boolean) {
this.key = key;
this.style = style;
this.checked = checked ?? true;
this.display = display ?? true;
this.attach = attach ?? false;
}
/**
* Logger 使
*/
public getLoggerOutput():string {
if(!this.display) return "";
return `%c${ this.key }`;
}
/**
* Text
*/
public getTextOutput():string {
if(!this.display) return "";
return `[${ this.key }]`;
}
/**
* style
*/
public getStyleOutput():string {
if(!this.display) return "";
return this.style.stringify();
}
/**
*
*/
public checking(src:RegExp | string):boolean {
let pass = false;
// 关闭校验
if(!this.checked) return pass;
if(src instanceof RegExp) {
pass = (src as RegExp).test(this.key)
} else {
pass = (src as string) === this.key;
}
return pass;
}
}
export default LogLabel;
export {LogLabel}

View File

@ -1,29 +0,0 @@
/**
*
* log
*/
class MultipleLogContent<T extends Array<any>> {
/**
*
*/
private readonly content:T;
/**
* @param content
*/
public constructor(...content:T) {
this.content = content;
}
/**
*
*/
public getContent():T {
return this.content;
}
}
export default MultipleLogContent;
export { MultipleLogContent };

View File

@ -1,91 +0,0 @@
/**
*
*/
class StackInfo {
/**
*
*/
public functionName:string | undefined;
/**
*
*/
public fileName:string | undefined;
/**
*
*/
public url:string | undefined;
public setInfo(functionName:string, fileName:string, url:string):StackInfo {
this.functionName = functionName;
this.fileName = fileName;
this.url = url;
return this;
}
/**
*
*/
public static getCallStack():StackInfo[] {
// 获取堆栈信息
let stack:string | undefined = new Error().stack;
if (stack === void 0) return [];
// 去除 Error
stack = stack.replace(/^(Error)\s/, "");
// 获取堆栈信息
let stackList:string[] = stack.split(/\n/);
let callStack:StackInfo[] = [];
for(let i = 0; i < stackList.length; i++) {
let matcher = stackList[i].match(/^\s+at\s+(.+)\s(\(.+\))/);
if (matcher === null || matcher.length < 3) continue;
let fileName = matcher[2].match(/.+\/(.+\..+:\d+:\d+)\)/);
if (fileName === null || matcher.length < 2) continue;
callStack.push(new StackInfo().setInfo(
matcher[1], fileName[1], matcher[2]?.replace(/(\(|\))/g, "")
))
}
// console.log(callStack);
return callStack;
}
/**
*
*/
public static readonly excludeFile:RegExp = /^Logger\.js:\d+:\d+/;
/**
*
*/
public static getFirstStack():StackInfo | undefined {
let callStack = this.getCallStack();
for(let i = 0; i < callStack.length; i++) {
if(!callStack[i].fileName) continue;
if(!StackInfo.excludeFile.test(callStack[i].fileName ?? "")) {
return callStack[i];
}
}
return;
}
}
export default StackInfo;
export { StackInfo };

View File

@ -1,11 +0,0 @@
import Logger from "./Logger";
export default Logger;
export { Logger };
export { InternalLogLabel } from "./InternalLogLabel";
export { MultipleLogContent } from "./MultipleLogContent";
export { LevelLogLabel } from "./LevelLogLabel";
export { LogLabel } from "./LogLabel";
export { LogStyle } from "./LogStyle";
export { StackInfo } from "./StackInfo";

View File

@ -1,3 +1,4 @@
{ {
"usingComponents": {} "usingComponents": {},
"navigationStyle": "custom"
} }

View File

@ -0,0 +1,3 @@
// view.status-bar {
// // background-color: antiquewhite;
// }

View File

@ -1,66 +1,68 @@
// pages/Timetable/Timetable.ts import { Logger } from "../../core/Logger";
import { LevelLogLabel, LifeCycleLogLabel } from "../../core/PresetLogLabel";
import { Manager, Modular, AnyWXContext, ILifetime } from "../../core/Module";
Page({ Page({
/** /**
* *
*/ */
data: { onLoad: async function () {
}, this;
/** let manager = new Manager(this);
* -- let m1 = manager.addModule(M1, "m1");
*/ let m2 = manager.addModule(M2, "m2", {m1});
onLoad() {
}, let manager2 = new Manager(this);
let m22 = manager.addModule(M2, "m1", {m1});
/** this.setData;
* --
*/
onReady() {
}, Logger.log("课程表 (Timetable) 页面加载...",
LevelLogLabel.TraceLabel, LifeCycleLogLabel.OnLoadLabel);
/** let systemInfo = wx.getSystemInfoSync();
* --
*/
onShow() {
}, //状态栏高度
let statusBarHeight = Number(systemInfo.statusBarHeight);
/** let menu = wx.getMenuButtonBoundingClientRect()
* --
*/
onHide() {
}, //导航栏高度
let navBarHeight = menu.height + (menu.top - statusBarHeight) * 2
/** //状态栏加导航栏高度
* -- let navStatusBarHeight = statusBarHeight + menu.height + (menu.top - statusBarHeight) * 2
*/
onUnload() {
}, console.log('状态栏高度',statusBarHeight)
/** console.log('导航栏高度',navBarHeight)
* --
*/
onPullDownRefresh() {
}, console.log('状态栏加导航栏高度',navStatusBarHeight)
/** this.setData({barh: navStatusBarHeight});
*
*/
onReachBottom() {
},
/**
*
*/
onShareAppMessage() {
} }
}) })
class M1<M extends Manager> extends Modular<M, {}> {
public onLoad(){
}
}
class M2<M extends Manager> extends Modular<M, {m1:M1<M>}> {
public onLoad() {
// this.setData();
}
// hhh(){
// }
hh(){}
}

View File

@ -1 +1,3 @@
<view class="status-bar" style="height:{{barh}}px"></view>
<text>pages/Timetable/Timetable.wxml</text> <text>pages/Timetable/Timetable.wxml</text>