Skip to content

Commit bd8dd4a

Browse files
committed
update
1 parent 2326dad commit bd8dd4a

File tree

10 files changed

+1107
-1011
lines changed

10 files changed

+1107
-1011
lines changed

packages/core/src/schema/manager.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { AutoStore } from "../store/store";
33
import type { Dict } from "../types";
44
import { isSchemaBuilder, markRaw, pathStartsWith, setVal } from "../utils";
55
import { getVal } from "../utils/getVal";
6+
import { isFuncDefine } from "../utils/isFuncDefine";
67
import { parseFunc } from "../utils/parseFunc";
78
import type {
89
SchemaOptions,
@@ -52,11 +53,24 @@ export class SchemaManager<
5253
value: descriptor.value,
5354
}) as unknown as SchemaDescriptor["options"];
5455

55-
if (typeof finalDescriptor.onValidate === "string") {
56-
finalDescriptor.onValidate = markRaw(parseFunc(finalDescriptor.onValidate)) as any;
57-
}
56+
Object.entries(finalDescriptor).forEach(([key, value]) => {
57+
if (isFuncDefine(value)) {
58+
(finalDescriptor as any)[key] =
59+
key === "onValidate" ? markRaw(parseFunc(value)) : (parseFunc(value) as any);
60+
}
61+
});
5862

5963
this._descriptors[key] = finalDescriptor;
64+
// if (this.store) {
65+
// this.store.update(
66+
// (state) => {
67+
// setVal(state, key.split("_$_"), finalDescriptor);
68+
// },
69+
// {
70+
// silent: true,
71+
// },
72+
// );
73+
// }
6074

6175
if (this.shadow && descriptor.value !== undefined) {
6276
this.shadow.update(

packages/core/src/store/store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export class AutoStore<State extends Dict> extends EventEmitter<StoreEvents> {
9191
private _batching = false; // 是否批量更新中
9292
private _batchOperates: StateOperate[] = []; // 暂存批量操作
9393
private _updateFlags: number = 0; // 额外的更新标识
94+
private _safeTraverse: boolean = false; // 安全遍历对象不触发可观察对象的创建
9495
private _peeping: boolean = false;
9596

9697
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: <noUnusedPrivateClassMembers>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* 在schema中,如果值是一个字符串,且以```function```开头,则认为是函数定义
3+
*
4+
* @param str
5+
* @returns
6+
*/
7+
export function isFuncDefine(val: any): val is string {
8+
return typeof val === "string" && val.startsWith("```") && val.endsWith("```");
9+
}
Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,62 @@
11
// biome-ignore lint/complexity/noBannedTypes: <noBannedTypes>
2-
export function parseFunc(fnStr: string): Function | undefined {
3-
// 去掉可选的 ``` 包裹
4-
if (fnStr.startsWith("```") && fnStr.endsWith("```")) {
5-
fnStr = fnStr.slice(3, -3);
2+
export function parseFunc(fnStr: string, defaultFunc: (...args: any[]) => any = () => {}): Function | undefined {
3+
// 统一剥离前后反引号包裹(数量不一致也剥离),兼容 ``` 代码块和语言标识
4+
fnStr = fnStr.replace(/^\s*`{3,}\w*(?:\r?\n|\n)/, "").replace(/^\s*`+\s*/, "");
5+
fnStr = fnStr.replace(/\s*`{3,}\s*$/, "").replace(/\s*`+\s*$/, "");
6+
// 清理可能的反斜杠转义导致的控制字符或多余反斜杠(例如 \f)
7+
fnStr = fnStr.replace(/^[\f\t\r\n]+/, "");
8+
fnStr = fnStr.replace(/^[\\]+(?=(?:async|function|\(|[A-Za-z_$]))/, "");
9+
10+
// 支持普通/异步 function(命名或匿名)、箭头函数(含单参省略括号),并容忍结尾分号
11+
const mf = /^\s*(async\s+)?function(?:\s+\w+)?\s*\(([^)]*)\)\s*\{([\s\S]*)\}\s*;?\s*$/m.exec(fnStr);
12+
const ma = /^\s*(async\s+)?\(([^)]*)\)\s*=>\s*(?:\{([\s\S]*)\}|(.+))\s*;?\s*$/m.exec(fnStr);
13+
const mas = /^\s*(async\s+)?([A-Za-z_$][\w$]*)\s*=>\s*(?:\{([\s\S]*)\}|(.+))\s*;?\s*$/m.exec(fnStr);
14+
15+
if (!mf && !ma && !mas) return;
16+
17+
let isAsync = false;
18+
let params: string[] = [];
19+
let body = "";
20+
21+
if (mf) {
22+
const [, asyncFlag, fnParams, fnBody] = mf;
23+
isAsync = Boolean(asyncFlag);
24+
params = (fnParams || "")
25+
.split(",")
26+
.map((s) => s.trim())
27+
.filter(Boolean);
28+
body = fnBody;
29+
} else if (ma) {
30+
const [, asyncFlag, afParams, afBodyBlock, afBodyExpr] = ma;
31+
isAsync = Boolean(asyncFlag);
32+
params = (afParams || "")
33+
.split(",")
34+
.map((s) => s.trim())
35+
.filter(Boolean);
36+
body = afBodyBlock || `return ${afBodyExpr}`;
37+
} else if (mas) {
38+
const [, asyncFlag, singleParam, afBodyBlock, afBodyExpr] = mas;
39+
isAsync = Boolean(asyncFlag);
40+
params = singleParam ? [singleParam] : [];
41+
body = afBodyBlock || `return ${afBodyExpr}`;
642
}
743

8-
// 一条正则吃尽两种函数形式
9-
// ^\s*(?:function\s*\(([^)]*)\)\s*\{([\s\S]*)\}| // function(...) { ... }
10-
// \(([^)]*)\)\s*=>\s*(?:\{([\s\S]*)\}|(.+)))$ // (...) => { ... } 或 (...) => expr
11-
const m = /^\s*(?:function\s*\(([^)]*)\)\s*\{([\s\S]*)\}|\(([^)]*)\)\s*=>\s*(?:\{([\s\S]*)\}|(.+)))$/m.exec(fnStr);
12-
13-
if (!m) return;
14-
15-
// 解构出捕获组
16-
// m[1/2] -> function(...) { ... }
17-
// m[3/4/5] -> 箭头函数
18-
const [, fnParams, fnBody, afParams, afBodyBlock, afBodyExpr] = m;
19-
20-
const params = (fnParams || afParams)
21-
.split(",")
22-
.map((s) => s.trim())
23-
.filter(Boolean);
24-
const body = fnBody || afBodyBlock || `return ${afBodyExpr}`;
44+
// 根据是否 async 选择构造函数
45+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor as FunctionConstructor;
46+
const Ctor: FunctionConstructor = isAsync ? (AsyncFunction as any) : Function;
2547

2648
try {
27-
return new Function(...params, body);
28-
} catch {}
29-
30-
// if (fnStr.startsWith('```') && fnStr.endsWith('```')) {
31-
// fnStr = fnStr.slice(3, fnStr.length - 3);
32-
// }
33-
34-
// // 普通函数
35-
// const match1 = fnStr.match(/^function\s*\(([^)]*)\)\s*\{([\s\S]*)\}$/);
36-
// if (match1) {
37-
// const [, params, body] = match1;
38-
// return new Function(...params.split(',').map((p) => p.trim()), body);
39-
// }
40-
41-
// // 箭头函数
42-
// try {
43-
// // 处理单行表达式形式的箭头函数: (params) => expression
44-
// const match2 = fnStr.match(/^\(([^)]*)\)\s*=>\s*(?!\{)(.+)$/);
45-
// if (match2) {
46-
// const [, params, body] = match2;
47-
// return new Function(...params.split(',').map((p) => p.trim()), `return ${body}`);
48-
// }
49-
50-
// // 处理带花括号的多行语句形式的箭头函数: (params) => { statements }
51-
// const match3 = fnStr.match(/^\(([^)]*)\)\s*=>\s*\{([\s\S]*)\}$/);
52-
// if (match3) {
53-
// const [, params, body] = match3;
54-
// return new Function(...params.split(',').map((p) => p.trim()), body);
55-
// }
56-
// } catch (e) {
57-
// e;
58-
// }
59-
60-
// return fnStr;
49+
return new Ctor(...params, body);
50+
} catch {
51+
return defaultFunc;
52+
}
6153
}
54+
// console.log(parseFunc("``` ()=>{1}```"));
55+
// console.log(parseFunc("```` ()=>1```"));
56+
// console.log(parseFunc("```function (){1}```"));
57+
// console.log(parseFunc("```function test(){\n1\n}```"));
58+
59+
// console.log(parseFunc("````async ()=>{1}```"));
60+
// console.log(parseFunc("````async ()=>1```"));
61+
// console.log(parseFunc("````async function (){1}```"));
62+
// console.log(parseFunc("````async function test(){1}```"));

0 commit comments

Comments
 (0)