Skip to content

Commit

Permalink
fix: 测试load功能
Browse files Browse the repository at this point in the history
  • Loading branch information
missannil committed Dec 6, 2023
1 parent 7c4ec47 commit bb3f0fd
Show file tree
Hide file tree
Showing 73 changed files with 722 additions and 563 deletions.
2 changes: 1 addition & 1 deletion doc/demo/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { User } from "./types";

const compA = SubComponent<Root, CompA>()({
computed: {
subA_user() {
subA_user(): User {
return this.data.user;
},
},
Expand Down
4 changes: 2 additions & 2 deletions jest/computed/asyncProperties/asyncProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { type CompDoc, type User, user } from "../../common";
const subA = SubComponent<Root, CompDoc>()({
computed: {
// 可引用根组件properties、data和计算字段
compA_num() {
compA_num(): number {
return (this.data.requiredUser?.age || 0) + this.data.num + (this.data.copyPropUser?.age || 0);
},
compA_user() {
compA_user(): User | null {
return this.data.copyPropUser;
},
},
Expand Down
4 changes: 2 additions & 2 deletions jest/computed/syncProperties/syncProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { type CompDoc, type User, user } from "../../common";
const subA = SubComponent<Root, CompDoc>()({
computed: {
// 可引用根组件properties、data和计算字段
compA_num() {
compA_num(): number {
return this.data.optionalUser!.age! + this.data.num + (this.data.CoptionalUser?.age || 0);
},
compA_user() {
compA_user(): User | null {
return this.data.copyPropUser;
},
},
Expand Down
2 changes: 1 addition & 1 deletion jest/computed/userInstance/userInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { type CompDoc } from "../../common";

const subA = SubComponent<Root, CompDoc>()({
computed: {
compA_num() {
compA_num(): number {
return this.increase(2) + this.data.num;
},
},
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
},
"homepage": "https://github.com/missannil/annil.git",
"scripts": {
"test": "jest --watch",
"coverage": "jest --coverage",
"prepare": "husky install",
"lint": "eslint . --fix && npm run fmt",
"fmt": "dprint fmt",
"test:jest": "jest --watch",
"test:type": "tsc --watch",
"type": "npm run test:type",
"jest": "npm run test:jest",
"build": "tsc -p tsconfig.build.json"
},
"devDependencies": {
Expand Down
115 changes: 99 additions & 16 deletions src/api/DefineComponent/collectOptionsForComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
import type { EventsConstraint } from "../RootComponent/Events/EventsConstraint";
import type { PageInstance } from "../RootComponent/Instance/RootComponentInstance";
import type { SubComponentTrueOptions } from "../SubComponent";
import type { FinalOptionsForComponent, FuncOptions } from ".";
import type { FinalOptionsOfComponent, FuncOptions } from ".";
/**
* 针对通过 navigateTo传过来的数据解析
* @param option - option中的url是拼接了encodeURIComponent转码的data对象的,key为INNERMARKER.url
Expand Down Expand Up @@ -49,7 +49,7 @@ function onLoadReceivedDataHandle(
*/
/* istanbul ignore next */
function onLoadHijack(
options: FinalOptionsForComponent,
options: FinalOptionsOfComponent,
before: Func[],
after: Func[] = [],
) {
Expand All @@ -70,18 +70,47 @@ function onLoadHijack(
});
};
}
/**
* attached生命周期劫持函数
*/
/* istanbul ignore next */
function attachedHijack(
options: FinalOptionsOfComponent,
before: Func[],
after: Func[] = [],
) {
/* istanbul ignore next */
options.lifetimes ||= {};

const originalAttached: Func | undefined = options.lifetimes.attached;

options.lifetimes.attached = function() {
before.forEach((func) => {
func.call(this, options);
});

originalAttached?.call(this);

/* istanbul ignore next */
after.forEach((func) => {
func.call(this, options);
});
};
}
/**
* 内部保护字段 即不允许配置的字段名(所有方法下)
*/
const INNERFIELDS = ["disposer"];
// const INNERFIELDS = ["disposer"];

/**
* 报错的形式避免输入字段和内部字段冲突
* 保护config下不被配置keys包含的内部预定字段
*/
/* istanbul ignore next */
function InternalFieldProtection(methodsConfig: object) {
const methodsConfigKeys = Object.keys(methodsConfig);
for (const key of INNERFIELDS) {
function InternalFieldProtection(config: object | undefined, keys: string[]) {
if (!config) return;
const methodsConfigKeys = Object.keys(config);
for (const key of keys) {
if (methodsConfigKeys.includes(key)) {
throw Error(`${key}已被内部字段占用`);
}
Expand All @@ -99,7 +128,7 @@ function _funcConfigHandle(methodsConfig: object, configList: Record<string, Fun
}

function funcConfigHandle(
finalOptionsForComponent: FinalOptionsForComponent,
finalOptionsForComponent: FinalOptionsOfComponent,
isPage: boolean | undefined,
funcOptions: FuncOptions,
) {
Expand Down Expand Up @@ -138,7 +167,7 @@ function funcFieldsCollect(

// 其他字段加入到componentOptions对应字段配置中
function otherFieldsHandle(
finalOptions: FinalOptionsForComponent,
finalOptions: FinalOptionsOfComponent,
rootComponentOptions: RootComponentTrueOptions,
) {
for (const key in rootComponentOptions) {
Expand All @@ -155,14 +184,14 @@ function otherFieldsHandle(
/**
* 把events字段配置变成函数放入到componentOptions.methods中
*/
function eventsHandle(componentOptions: FinalOptionsForComponent, eventsConfig: EventsConstraint) {
function eventsHandle(componentOptions: FinalOptionsOfComponent, eventsConfig: EventsConstraint) {
/* istanbul ignore next */
componentOptions.methods ||= {};

Object.assign(componentOptions.methods, eventsConfig);
}
function subComponentsHandle(
componentOptions: FinalOptionsForComponent,
componentOptions: FinalOptionsOfComponent,
subComponents: SubComponentTrueOptions[],
funcOptions: FuncOptions,
) {
Expand All @@ -186,7 +215,7 @@ function IsFullCustomEvents(
* 把customEvents字段配置变成函数放入到componentOptions.methods中
*/
function customEventsHandle(
componentOptions: FinalOptionsForComponent,
componentOptions: FinalOptionsOfComponent,
customEventsConfig: CustomEventConstraint,
) {
/* istanbul ignore next */
Expand All @@ -206,18 +235,68 @@ function customEventsHandle(
}
}
}
/**
* 触发各个组件的页面load事件
*/
/* istanbul ignore next */
function triggerCompLoad(this: Instance, props: object) {
if (!this.__compLoadList__) return;
this.__compLoadList__.forEach((loadFunc) => {
loadFunc(props);
});
}
/* istanbul ignore next */
function getPageInstance(pageId: string): Instance {
const pagestack = getCurrentPages() as unknown as Instance[];
let pageInstance: Instance;
pagestack.some((instance) => {
if (instance.getPageId() === pageId) {
pageInstance = instance;

return true;
}

return false;
});

// @ts-ignore pagestack中一定赋值了
return pageInstance;
}
/**
* 收集组件pageLifetimes下的load周期函数到页面实例的__loadFunList__
*/
/* istanbul ignore next */
function collectLoadLifetimesOfComponent(this: Instance, finalOptionsForComponent: FinalOptionsOfComponent) {
const loadFunc = finalOptionsForComponent.pageLifetimes?.load;

console.log(loadFunc, finalOptionsForComponent);

if (!loadFunc) return;

const pageInstance = getPageInstance(this.getPageId());
const __compLoadList__: Function[] = (pageInstance.__compLoadList__ ||= []);

__compLoadList__.push(loadFunc.bind(this));
}
/**
* 收集 rootComponentOptions 配置到 finalOptions 和 funcOptions 中
* @param finalOptions - 收集配置对象
* @param funcOptions - 收集特殊配置对象字段
* @param rootComponentOptions - 被收集的源配置对象
*/
function collectRootComponentOption(
finalOptions: FinalOptionsForComponent,
finalOptions: FinalOptionsOfComponent,
funcOptions: FuncOptions,
rootComponentOptions: RootComponentTrueOptions,
) {
console.log("-------------------------");

InternalFieldProtection(rootComponentOptions.customEvents, ["load"]);

InternalFieldProtection(rootComponentOptions.methods, ["load"]);

InternalFieldProtection(rootComponentOptions.events, ["load"]);

rootComponentOptions.customEvents && customEventsHandle(finalOptions, rootComponentOptions.customEvents);

delete rootComponentOptions.customEvents;
Expand All @@ -239,8 +318,8 @@ function collectRootComponentOption(
export function collectOptionsForComponent(
rootComponentOption: RootComponentTrueOptions | undefined,
subComponentsList: SubComponentTrueOptions[] | undefined,
): FinalOptionsForComponent {
const finalOptionsForComponent: FinalOptionsForComponent = {
): FinalOptionsOfComponent {
const finalOptionsForComponent: FinalOptionsOfComponent = {
// default options
options: {
// addGlobalClass: true,
Expand Down Expand Up @@ -273,12 +352,16 @@ export function collectOptionsForComponent(
funcConfigHandle(finalOptionsForComponent, rootComponentOption?.isPage, funcOptions);
}

finalOptionsForComponent.methods && InternalFieldProtection(finalOptionsForComponent.methods);
finalOptionsForComponent.methods && InternalFieldProtection(finalOptionsForComponent.methods, ["disposer"]);

// BBeforeCreate在最后面
finalOptionsForComponent.behaviors!.push(BBeforeCreate);

onLoadHijack(finalOptionsForComponent, [onLoadReceivedDataHandle, initComputed], []);
console.log(finalOptionsForComponent, 999, funcOptions);

attachedHijack(finalOptionsForComponent, [collectLoadLifetimesOfComponent], []);

onLoadHijack(finalOptionsForComponent, [onLoadReceivedDataHandle, initComputed], [triggerCompLoad]);

// 框架无法测试页面
/* istanbul ignore next */
Expand Down
4 changes: 2 additions & 2 deletions src/api/DefineComponent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type FuncOptions = Record<"pageLifetimes" | "lifetimes" | "watch", Record
/**
* 最终传入原生Component的配置项
*/
export type FinalOptionsForComponent = {
export type FinalOptionsOfComponent = {
isPage?: boolean;
options?: WMComponent.Options;
properties?: Record<string, any>;
Expand All @@ -66,7 +66,7 @@ export type FinalOptionsForComponent = {
methods?: Record<string, Func> & { __storeConfig__?: Func };
watch?: Record<string, Func>;
lifetimes?: LifetimesConstraint;
pageLifetimes?: Partial<WMCompPageLifetimes & { load: Func } & WMPageLifetimes>;
pageLifetimes?: Partial<WMCompPageLifetimes & { load: (prop: unknown) => void } & WMPageLifetimes>;
};

export const DefineComponent: DefineComponentConstructor = function(options): any {
Expand Down
26 changes: 23 additions & 3 deletions src/api/RootComponent/Computed/ComputedOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,31 @@ import type { DuplicateFieldValidator } from "hry-types/src/Generic/DuplicateFie

import type { ComputedConstraint } from "./ComputedConstraint";

export type ComputedOption<TComputed extends ComputedConstraint, OtherData extends object> = {
export type ComputedOption<TComputed extends ComputedConstraint, CompareKeys extends PropertyKey> = {
/**
* 计算属性字段,可通过this.data获取其他数据
* computed字段, [类型约束ComputedConstraint](ComputedConstraint.ts)
* @remarks
*
* 函数体内,可通过this.data获取实例其他数据(依赖),setData发生时,若数据(依赖)发生变化则重新运行函数体并setData。
*
* 带重复字段检测(与properties、data、store字段比较)
*
* @example
*
* ```ts
* {
* data:{
* count:1
* },
* computed:{
* return this.data.count + 1
* }
* }
*
* ```
*/
computed?:
& TComputed
& DuplicateFieldValidator<TComputed, keyof OtherData>;
& DuplicateFieldValidator<TComputed, CompareKeys>;
};
4 changes: 1 addition & 3 deletions src/api/RootComponent/Computed/GetComputedDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@ import type { ComputedConstraint } from "./ComputedConstraint";
* @param T - ComputedConstraint
* @returns object
*/
export type GetComputedDoc<TComputed extends ComputedConstraint> = TComputed extends unknown
? { [k in keyof TComputed]: ReturnType<TComputed[k]> }
: never;
export type GetComputedDoc<TComputed extends ComputedConstraint> = { [k in keyof TComputed]: ReturnType<TComputed[k]> };
28 changes: 9 additions & 19 deletions src/api/RootComponent/Computed/test/normal.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import { Checking, type Test } from "hry-types";
import type { ReadonlyDeep } from "hry-types/src/Any/_api";
import type { DetailedType } from "../../../../types/DetailedType";
import { RootComponent } from "../..";
import type { Mock_User } from "../../Properties/test/normalRequired.test";

/**
* computed字段约束为 [ComputedConstraint](../ComputedConstraint.ts)
*/
const RootDoc = RootComponent()({
properties: {
firstName: String,
},
data: {
lastName: "lastName",
},
store: {
prefix: () => "hry-", // 模拟而已
},
computed: {
fullName() {
// 1 计算属性字段可以通过this.data 引用properties、data
return this.data.firstName + this.data.lastName;
// 1 计算属性字段可以通过this.data 引用properties、data、store字段
return this.data.prefix + this.data.firstName + this.data.lastName;
},
user() {
return {} as Mock_User;
Expand All @@ -35,12 +34,16 @@ const RootDoc = RootComponent()({
lastName: string;
fullName: string;
user: Mock_User;
prefix: string;
id_fullName: string;
readOnly: "str";
}>,
Test.Pass
>;

// @ts-expect-error 深度只读 不可赋值
this.data.user.id = "xxx";

return "str";
},
},
Expand Down Expand Up @@ -84,16 +87,3 @@ const EmptyComputedFieldDoc = RootComponent()({
});

Checking<typeof EmptyComputedFieldDoc, { methods: { M1: () => void } }, Test.Pass>;

RootComponent()({
isPage: true,
properties: {
obj: Object as DetailedType<{ name: string; age: number }>,
},
computed: {
age() {
// 页面实例对象不添加Null,因为计算属性初始化在onLoad之后(即properties已传入时,且不会传入Null)
return this.data.obj.age;
},
},
});

0 comments on commit bb3f0fd

Please sign in to comment.