diff --git a/apps/dsv/src/App.tsx b/apps/dsv/src/App.tsx index 704cead..7754add 100644 --- a/apps/dsv/src/App.tsx +++ b/apps/dsv/src/App.tsx @@ -2,7 +2,29 @@ import { useEffect, useState } from 'react'; import { run } from 'parser'; function App() { - const [code, setCode] = useState(`const bubbleSort = (arr) => { + const [code, setCode] = useState(` +// const bubbleSort = (arr) => { +// for (let i = 0; i < arr.length; i++) { +// for (let j = 0; j < arr.length - i - 1; j++) { +// if (arr[j] > arr[j + 1]) { +// let temp = arr[j]; +// arr[j] = arr[j + 1]; +// arr[j + 1] = temp; +// } +// } +// } +// return arr; +// } + +// const arr = [5, 3, 8, 4, 2]; +// arr.pop() +// arr.push(1); +// bubbleSort(arr) + +// console.log(arr) +// console.log(JSON.parse(JSON.stringify(arr))) + +const bubbleSort = (arr) => { for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { @@ -15,13 +37,16 @@ function App() { return arr; } -const arr = [5, 3, 8, 4, 2]; -arr.pop() -arr.push(1); -bubbleSort(arr) +const arr1 = [5, 3, 8, 4, 2]; + +const arr2 = [1, 2, 4] + +const arr3 = arr1.concat(arr2) +bubbleSort(arr3) + +console.log(arr3) +console.log(JSON.parse(JSON.stringify(arr3))) -console.log(arr) -console.log(JSON.parse(JSON.stringify(arr))) `); return ( diff --git a/packages/parser/src/data-structures/array/array-proxy.temp.js b/packages/parser/src/data-structures/array/array-proxy.temp.js deleted file mode 100644 index 8639737..0000000 --- a/packages/parser/src/data-structures/array/array-proxy.temp.js +++ /dev/null @@ -1,131 +0,0 @@ -const uuid = (prefix) => { - return ( - prefix + - "-" + - "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { - const r = (Math.random() * 16) | 0; - const v = c === "x" ? r : (r & 0x3) | 0x8; - return v.toString(16); - }) - ); -}; - -class ArrayProxy { - constructor(array, options) { - const id = uuid("ArrayProxy"); - const { snapshotSchema, schema, SchemaBuilder } = options; - this.options = options; - - snapshotSchema( - new SchemaBuilder() - .from(schema) - .addStructure({ - id: id, - type: "ArrayProxy", - }) - .build() - ); - - this.structureId = id; - this.target = [...array]; - - const proxy = new Proxy(this.target, { - get: (target, prop) => { - if (prop === "__proxyGet") { - return (index) => this._getHandler(target, index); - } - if (prop === "__proxySet") { - return (index, value) => this._setHandler(target, index, value); - } - if (prop === "__proxyCall") { - return (method, args) => { - const fn = target[method]; - return this._applyHandler(fn, target, args, method); - }; - } - return this._getHandler(target, prop); - }, - set: (target, prop, value) => this._setHandler(target, prop, value), - }); - return proxy; - } - - _getHandler(target, prop) { - const { snapshotSchema, schema, SchemaBuilder } = this.options; - - const value = target[prop]; - if (typeof value === "function" && Array.prototype[prop]) { - return (...args) => { - const result = value.apply(target, args); - - snapshotSchema( - new SchemaBuilder() - .from(schema) - .addAction(this.structureId, { - name: "call", - type: prop, - args: [...args], - }) - .build() - ); - return result; - }; - } - - if (typeof prop !== "symbol" && !isNaN(prop)) { - snapshotSchema( - new SchemaBuilder() - .from(schema) - .addAction(this.structureId, { - name: "get", - type: "get", - args: [Number(prop)], - }) - .build() - ); - } - - return value; - } - - _setHandler(target, prop, value) { - const { snapshotSchema, schema, SchemaBuilder } = this.options; - - const index = Number(prop); - if (!isNaN(index)) { - snapshotSchema( - new SchemaBuilder() - .from(schema) - .addAction(this.structureId, { - name: "set", - type: "set", - args: [index, value], - }) - .build() - ); - } - target[prop] = value; - return true; - } - - _applyHandler(target, thisArg, args, method) { - const { snapshotSchema, schema, SchemaBuilder } = this.options; - - const result = target.apply(thisArg, args); - snapshotSchema( - new SchemaBuilder() - .from(schema) - .addAction(this.structureId, { - name: "call", - type: method, - args: [...args], - }) - .build() - ); - - if (Array.isArray(result)) { - return new ArrayProxy(result, this.options); - } - return result; - } -} diff --git a/packages/parser/src/data-structures/array/array-proxy.ts b/packages/parser/src/data-structures/array/array-proxy.ts index 2dfefed..558ff8e 100644 --- a/packages/parser/src/data-structures/array/array-proxy.ts +++ b/packages/parser/src/data-structures/array/array-proxy.ts @@ -1,46 +1,46 @@ -export const ArrayProxyString = ` -const uuid = (prefix) => { - return ( - prefix + - "-" + - "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { - const r = (Math.random() * 16) | 0; - const v = c === "x" ? r : (r & 0x3) | 0x8; - return v.toString(16); - }) - ); -}; +import { Schema, SchemaBuilder, StructureType } from "schema"; -class ArrayProxy { - constructor(array, options) { - const id = uuid("ArrayProxy"); - const { snapshotSchema, schema, SchemaBuilder } = options; - this.options = options; +interface ArrayProxyOptions { + snapshotSchema: (schema: Schema) => void; + schema: Schema; + SchemaBuilder: typeof SchemaBuilder; + uuid: (prefix: string) => string; +} + +export class ArrayProxy { + structureId: string; + options: ArrayProxyOptions; + target: any[]; + constructor(array: any[], options: ArrayProxyOptions) { + const { snapshotSchema, schema, SchemaBuilder, uuid } = options; + this.structureId = uuid("array"); + this.options = options; snapshotSchema( new SchemaBuilder() .from(schema) .addStructure({ - id: id, - type: "ArrayProxy", + id: this.structureId, + type: StructureType.Array, + array, }) .build() ); - this.structureId = id; this.target = [...array]; const proxy = new Proxy(this.target, { get: (target, prop) => { if (prop === "__proxyGet") { - return (index) => this._getHandler(target, index); + return (index: number) => this._getHandler(target, index); } if (prop === "__proxySet") { - return (index, value) => this._setHandler(target, index, value); + return (index: number, value: any) => + this._setHandler(target, index, value); } if (prop === "__proxyCall") { - return (method, args) => { - const fn = target[method]; + return (method: string, args: any[]) => { + const fn = target[method as keyof typeof target]; return this._applyHandler(fn, target, args, method); }; } @@ -51,20 +51,21 @@ class ArrayProxy { return proxy; } - _getHandler(target, prop) { + _getHandler(target: any[], prop: number) { const { snapshotSchema, schema, SchemaBuilder } = this.options; const value = target[prop]; if (typeof value === "function" && Array.prototype[prop]) { - return (...args) => { + return (...args: any[]) => { const result = value.apply(target, args); snapshotSchema( new SchemaBuilder() .from(schema) - .addAction(this.structureId, { + .addAction({ + structureId: this.structureId, name: "call", - type: prop, + type: prop.toString(), args: [...args], }) .build() @@ -77,7 +78,8 @@ class ArrayProxy { snapshotSchema( new SchemaBuilder() .from(schema) - .addAction(this.structureId, { + .addAction({ + structureId: this.structureId, name: "get", type: "get", args: [Number(prop)], @@ -89,7 +91,7 @@ class ArrayProxy { return value; } - _setHandler(target, prop, value) { + _setHandler(target: any[], prop: number, value: any) { const { snapshotSchema, schema, SchemaBuilder } = this.options; const index = Number(prop); @@ -97,7 +99,8 @@ class ArrayProxy { snapshotSchema( new SchemaBuilder() .from(schema) - .addAction(this.structureId, { + .addAction({ + structureId: this.structureId, name: "set", type: "set", args: [index, value], @@ -109,14 +112,15 @@ class ArrayProxy { return true; } - _applyHandler(target, thisArg, args, method) { + _applyHandler(fn: Function, thisArg: any, args: any[], method: string) { const { snapshotSchema, schema, SchemaBuilder } = this.options; - const result = target.apply(thisArg, args); + const result = fn.apply(thisArg, args); snapshotSchema( new SchemaBuilder() .from(schema) - .addAction(this.structureId, { + .addAction({ + structureId: this.structureId, name: "call", type: method, args: [...args], @@ -130,6 +134,3 @@ class ArrayProxy { return result; } } - - -`; diff --git a/packages/parser/src/data-structures/array/array-visitor.ts b/packages/parser/src/data-structures/array/array-visitor.ts index 599e6f7..85a117c 100644 --- a/packages/parser/src/data-structures/array/array-visitor.ts +++ b/packages/parser/src/data-structures/array/array-visitor.ts @@ -10,6 +10,19 @@ export const arrayVisitor = { return; } + // 检查父节点是否为 __proxyCall 的参数 + const parent = path.parentPath; + if (parent.isCallExpression()) { + const callee = parent.node.callee; + if ( + t.isMemberExpression(callee) && + t.isIdentifier(callee.property, { name: "__proxyCall" }) + ) { + // 如果是 __proxyCall 的参数,跳过转换 + return; + } + } + // 创建内部数组时标记为已转换 const innerArray = t.arrayExpression(path.node.elements); (innerArray as any).wasConverted = true; @@ -37,6 +50,7 @@ export const arrayVisitor = { "splice", "sort", "reverse", + "concat", ].includes(node.callee.property.name) ) { const proxyCall = t.callExpression( diff --git a/packages/parser/src/execute/executeCode.ts b/packages/parser/src/execute/executeCode.ts index b0ed133..460288c 100644 --- a/packages/parser/src/execute/executeCode.ts +++ b/packages/parser/src/execute/executeCode.ts @@ -1,21 +1,23 @@ import { logStyle } from "../utils/log"; import { Schema, SchemaBuilder } from "schema"; +import { uuid } from "../utils/uuid"; +import { ArrayProxy } from "../data-structures/array/array-proxy"; // 执行代码 export const executeCode = (code: string) => { try { console.groupCollapsed("%cExecuted Result", logStyle); - const exeFunc = new Function("__GlobalContext__", code); + const exeFunc = new Function("ArrayProxy", "__GlobalContext__", code); const __GlobalContext__: Record = { + uuid, schema: {}, SchemaBuilder, snapshotSchema: (schema: Schema) => { __GlobalContext__.schema = schema; }, }; - - const result = exeFunc(__GlobalContext__); + const result = exeFunc(ArrayProxy, __GlobalContext__); result && console.log(result); __GlobalContext__ && console.log(__GlobalContext__); diff --git a/packages/parser/src/transform/transformCode.ts b/packages/parser/src/transform/transformCode.ts index 712952a..e84e642 100644 --- a/packages/parser/src/transform/transformCode.ts +++ b/packages/parser/src/transform/transformCode.ts @@ -1,4 +1,3 @@ -import { ArrayProxyString } from "../data-structures/array/array-proxy"; import * as babel from "@babel/core"; import { arrayVisitor } from "../data-structures/array/array-visitor"; import { logStyle } from "../utils/log"; @@ -6,9 +5,7 @@ import { logStyle } from "../utils/log"; // 转换代码 export const transformCode = (code: string) => { try { - const presetCodeEnv = ` -${ArrayProxyString} - `; + const presetCodeEnv = ``; const result = babel.transformSync(code, { plugins: [arrayVisitor], diff --git a/packages/parser/src/utils/uuid.ts b/packages/parser/src/utils/uuid.ts new file mode 100644 index 0000000..f34a128 --- /dev/null +++ b/packages/parser/src/utils/uuid.ts @@ -0,0 +1,10 @@ +export const uuid = (prefix: string) => { + return ( + prefix + + "-" + + "xxxxxx".replace(/[x]/g, (c) => { + const r = (Math.random() * 16) | 0; + return r.toString(16); + }) + ); +}; diff --git a/packages/schema/src/builder/index.ts b/packages/schema/src/builder/index.ts index 58fced6..7803f6a 100644 --- a/packages/schema/src/builder/index.ts +++ b/packages/schema/src/builder/index.ts @@ -1,20 +1,20 @@ import { Action, Schema, Structure } from "../types"; export class SchemaBuilder { - private actionsMap: Record = {}; + private actions: Action[] = []; private structures: Structure[] = []; constructor() {} init() { this.structures = []; - this.actionsMap = {}; + this.actions = []; return this; } from(schema: Schema) { this.structures = [...(schema.structures ?? [])]; - this.actionsMap = { ...(schema.actionsMap ?? {}) }; + this.actions = [...(schema.actions ?? [])]; return this; } @@ -23,18 +23,15 @@ export class SchemaBuilder { return this; } - addAction(structureId: string, action: Action) { - this.actionsMap[structureId] = [ - ...(this.actionsMap[structureId] || []), - action, - ]; + addAction(action: Action) { + this.actions.push(action); return this; } build(): Schema { return { structures: this.structures, - actionsMap: this.actionsMap, + actions: this.actions, }; } @@ -43,6 +40,6 @@ export class SchemaBuilder { } getActions(structureId: string) { - return this.actionsMap[structureId]; + return this.actions.filter((action) => action.structureId === structureId); } } diff --git a/packages/schema/src/types/index.ts b/packages/schema/src/types/index.ts index c35e985..97b9f59 100644 --- a/packages/schema/src/types/index.ts +++ b/packages/schema/src/types/index.ts @@ -2,6 +2,5 @@ export { Schema, Structure, Action, - ActionsMap, StructureType, } from "./schema"; diff --git a/packages/schema/src/types/schema.ts b/packages/schema/src/types/schema.ts index e52335f..b5ae0b6 100644 --- a/packages/schema/src/types/schema.ts +++ b/packages/schema/src/types/schema.ts @@ -7,25 +7,23 @@ export interface Schema { */ structures: Structure[]; /** - * @description The actions map in the schema + * @description The actions in the schema */ - actionsMap: ActionsMap; + actions: Action[]; } export interface Structure { id: string; type: StructureType; + array: any[]; } export enum StructureType { Array = "array", } -export interface ActionsMap { - [structureId: string]: Action[]; -} - export interface Action { + structureId: string; name: string; type: string; args: any[];