@ticatec/uniface-flexi-module 0.0.2 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MODULE_LOADER_CN.md +11 -3
- package/README.md +4 -1
- package/README_CN.md +0 -1
- package/dist/flexi-datatable/index.d.ts +2 -0
- package/dist/flexi-form/flexi_form/FlexiFormPanel.svelte +3 -1
- package/dist/flexi-form/flexi_form/FlexiFormPanel.svelte.d.ts +2 -1
- package/dist/flexi-form/index.d.ts +2 -1
- package/dist/flexi-form/index.js +2 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/package.json +6 -5
- package/SANDBOX_CN.md +0 -201
- package/dist/Sandbox.d.ts +0 -33
- package/dist/Sandbox.js +0 -101
package/MODULE_LOADER_CN.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
## 概述
|
|
21
21
|
|
|
22
|
-
`ModuleLoader` 采用 **单例模式 + 依赖注入** 设计,通过外部传入的 `loadModule` 函数实现模块的实际加载逻辑,内部使用 `Map`
|
|
22
|
+
`ModuleLoader` 采用 **单例模式 + 依赖注入** 设计,通过外部传入的 `loadModule` 函数实现模块的实际加载逻辑,内部使用 `Map` 实现高效缓存。可以配合`@ticatec/dyna-js`一起使用,实现动态代码的加载和实现。
|
|
23
23
|
|
|
24
24
|
```ts
|
|
25
25
|
export type LoadModule = (params: any) => Promise<any>;
|
|
@@ -84,7 +84,7 @@ async load(key: string, params: any): Promise<any>
|
|
|
84
84
|
|
|
85
85
|
```ts
|
|
86
86
|
import ModuleLoader, {LoadModule} from '@ticatec/uniface-flexi-module/ModuleLoader';
|
|
87
|
-
import
|
|
87
|
+
import { initializeDynaJs, getDynaJs } from '@ticatec/dyna-js';
|
|
88
88
|
import axios from "axios";
|
|
89
89
|
|
|
90
90
|
// 定义模块加载函数(例如使用 import() 动态导入)
|
|
@@ -94,7 +94,15 @@ const loadModule: LoadModule = async (params: any) => {
|
|
|
94
94
|
|
|
95
95
|
// 初始化 ModuleLoader
|
|
96
96
|
ModuleLoader.initialize(loadModule);
|
|
97
|
-
|
|
97
|
+
|
|
98
|
+
// 初始化 DynaJs
|
|
99
|
+
initializeDynaJs({
|
|
100
|
+
defaultImports: {AppModule},
|
|
101
|
+
defaultInjectedKeys: ['Dialog', 'MessageBox'],
|
|
102
|
+
useProxyByDefault: true,
|
|
103
|
+
allowBrowserAPIs: false,
|
|
104
|
+
validateCode: true
|
|
105
|
+
});
|
|
98
106
|
|
|
99
107
|
// 使用示例
|
|
100
108
|
async function loadComponents() {
|
package/README.md
CHANGED
|
@@ -15,9 +15,11 @@ A flexible form framework for Svelte applications with dynamic field types, crit
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm install @ticatec/uniface-flexi-form
|
|
18
|
+
npm install @ticatec/uniface-flexi-form @ticatec/dyna-js
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
> **Note**: `@ticatec/dyna-js` is required for dynamic code execution features used internally by some components.
|
|
22
|
+
|
|
21
23
|
## Quick Start
|
|
22
24
|
|
|
23
25
|
```typescript
|
|
@@ -242,6 +244,7 @@ import {
|
|
|
242
244
|
FlexiForm,
|
|
243
245
|
FlexiCard,
|
|
244
246
|
FlexiField,
|
|
247
|
+
FlexiComposite,
|
|
245
248
|
FlexiFormPage,
|
|
246
249
|
FlexiFormDialog,
|
|
247
250
|
ComponentBuilder,
|
package/README_CN.md
CHANGED
|
@@ -32,7 +32,6 @@ npm install @ticatec/uniface-flexi-form
|
|
|
32
32
|
|
|
33
33
|
- `FlexiContext` [详情](./FLEXI_CONTEXT_GUIDE_CN.md)
|
|
34
34
|
- `ModuleLoader` [详情](./MODULE_LOADER_CN.md)
|
|
35
|
-
- `Sandbox` [详情](./SANDBOX_CN.md)
|
|
36
35
|
- 动态表单 `FlexiForm` [详情](./FLEXIFORM_GUIDE_CN.md)
|
|
37
36
|
- 条件面板 `FlexiCriteriaSet` [详情](./FLEXICRITERIASET_GUIDE_CN.md)
|
|
38
37
|
- 动态数据表 `FlexiDataTable` [详情](./FLEXIDATATABLE_GUIDE_CN.md)
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import FlexiDataTable from "./FlexiDataTable";
|
|
2
|
+
import type { FlexiDataTableSchema, FlexiDataTableColumnSchema, IndicatorColumnSchema, ActionsColumnSchema } from "./FlexiDataTable";
|
|
2
3
|
export default FlexiDataTable;
|
|
4
|
+
export type { FlexiDataTableSchema, FlexiDataTableColumnSchema, IndicatorColumnSchema, ActionsColumnSchema };
|
|
@@ -3,14 +3,16 @@ import { onMount } from "svelte";
|
|
|
3
3
|
import FlexiCardPanel from "../flexi_card/FlexiCardPanel.svelte";
|
|
4
4
|
let className = '';
|
|
5
5
|
export { className as class };
|
|
6
|
-
export let actions;
|
|
6
|
+
export let actions = null;
|
|
7
7
|
export let readonly = false;
|
|
8
8
|
export let form;
|
|
9
|
+
export let onFormInvalidate = null;
|
|
9
10
|
let style = form.style;
|
|
10
11
|
let blocks;
|
|
11
12
|
onMount(async () => {
|
|
12
13
|
form.setInvalidateHandler(() => {
|
|
13
14
|
refreshCards();
|
|
15
|
+
onFormInvalidate?.();
|
|
14
16
|
});
|
|
15
17
|
refreshCards();
|
|
16
18
|
});
|
|
@@ -15,9 +15,10 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
|
|
|
15
15
|
}
|
|
16
16
|
declare const FlexiFormPanel: $$__sveltets_2_IsomorphicComponent<{
|
|
17
17
|
class?: string;
|
|
18
|
-
actions
|
|
18
|
+
actions?: ButtonActions | null;
|
|
19
19
|
readonly?: boolean;
|
|
20
20
|
form: FlexiForm;
|
|
21
|
+
onFormInvalidate?: any;
|
|
21
22
|
}, {
|
|
22
23
|
[evt: string]: CustomEvent<any>;
|
|
23
24
|
}, {}, {}, string>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import FlexiForm from "./flexi_form/FlexiForm";
|
|
2
2
|
import FlexiCard from "./flexi_card/FlexiCard";
|
|
3
3
|
import FlexiField from "./flexi_field/FlexiField";
|
|
4
|
+
import FlexiComposite from "./flexi_composite/FlexiComposite";
|
|
4
5
|
import FlexiFormPage from "./FlexiFormPage.svelte";
|
|
5
6
|
import FlexiFormDialog from "./FlexiFormDialog.svelte";
|
|
6
7
|
import ComponentBuilder from "./lib/ComponentBuilder";
|
|
7
8
|
import FlexiFormPanel from "./flexi_form/FlexiFormPanel.svelte";
|
|
8
9
|
import { registerFormFieldBuilder } from "./components/CellFieldBuilder";
|
|
9
|
-
export { FlexiForm, FlexiCard, FlexiField, FlexiFormPage, FlexiFormDialog, FlexiFormPanel };
|
|
10
|
+
export { FlexiForm, FlexiCard, FlexiField, FlexiComposite, FlexiFormPage, FlexiFormDialog, FlexiFormPanel };
|
|
10
11
|
export { ComponentBuilder };
|
|
11
12
|
export { registerFormFieldBuilder };
|
package/dist/flexi-form/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import FlexiForm from "./flexi_form/FlexiForm";
|
|
2
2
|
import FlexiCard from "./flexi_card/FlexiCard";
|
|
3
3
|
import FlexiField from "./flexi_field/FlexiField";
|
|
4
|
+
import FlexiComposite from "./flexi_composite/FlexiComposite";
|
|
4
5
|
import FlexiFormPage from "./FlexiFormPage.svelte";
|
|
5
6
|
import FlexiFormDialog from "./FlexiFormDialog.svelte";
|
|
6
7
|
import ComponentBuilder from "./lib/ComponentBuilder";
|
|
7
8
|
import FlexiFormPanel from "./flexi_form/FlexiFormPanel.svelte";
|
|
8
9
|
import { registerFormFieldBuilder } from "./components/CellFieldBuilder";
|
|
9
|
-
export { FlexiForm, FlexiCard, FlexiField, FlexiFormPage, FlexiFormDialog, FlexiFormPanel };
|
|
10
|
+
export { FlexiForm, FlexiCard, FlexiField, FlexiComposite, FlexiFormPage, FlexiFormDialog, FlexiFormPanel };
|
|
10
11
|
export { ComponentBuilder };
|
|
11
12
|
export { registerFormFieldBuilder };
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ticatec/uniface-flexi-module",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "A flexible form framework for Svelte applications with dynamic field types, criteria panels, and modular components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"package": "svelte-kit sync && svelte-package && publint",
|
|
44
44
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
45
45
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
46
|
-
"publish:public": "npm publish --access public"
|
|
46
|
+
"publish:public": "npm run build && npm publish --access public"
|
|
47
47
|
},
|
|
48
48
|
"exports": {
|
|
49
49
|
".": {
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"types": "./dist/criteria-panel/index.d.ts",
|
|
90
90
|
"import": "./dist/criteria-panel/index.js"
|
|
91
91
|
},
|
|
92
|
-
"./
|
|
92
|
+
"./flexi-datatable": {
|
|
93
93
|
"types": "./dist/flexi-datatable/index.d.ts",
|
|
94
94
|
"import": "./dist/flexi-datatable/index.js"
|
|
95
95
|
},
|
|
@@ -105,13 +105,13 @@
|
|
|
105
105
|
"@sveltejs/vite-plugin-svelte": "^6.1.1",
|
|
106
106
|
"@ticatec/app-data-manager": "^1.2.4",
|
|
107
107
|
"@ticatec/app-data-service": "^1.1.3",
|
|
108
|
-
"@ticatec/uniface-filter-panel": "^0.1.0",
|
|
109
108
|
"@ticatec/enhanced-utils": "^1.0.1",
|
|
110
109
|
"@ticatec/i18n": "^0.2.2",
|
|
111
110
|
"@ticatec/restful_service_api": "^0.1.7",
|
|
112
111
|
"@ticatec/uniface-app-component": "^0.2.2",
|
|
113
112
|
"@ticatec/uniface-dev-shell": "^0.0.6",
|
|
114
113
|
"@ticatec/uniface-element": "^0.3.4",
|
|
114
|
+
"@ticatec/uniface-filter-panel": "^0.1.0",
|
|
115
115
|
"@ticatec/uniface-google-material-icons": "^0.1.2",
|
|
116
116
|
"@ticatec/uniface-micro-frame": "^0.0.1",
|
|
117
117
|
"@ticatec/web-bean-validator": "^0.1.9",
|
|
@@ -127,7 +127,8 @@
|
|
|
127
127
|
"vite": "^6.3.5"
|
|
128
128
|
},
|
|
129
129
|
"peerDependencies": {
|
|
130
|
-
"svelte": "^5.0.0"
|
|
130
|
+
"svelte": "^5.0.0",
|
|
131
|
+
"@ticatec/dyna-js": "^0.0.2"
|
|
131
132
|
},
|
|
132
133
|
"author": "Henry Feng",
|
|
133
134
|
"license": "MIT",
|
package/SANDBOX_CN.md
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
# Sandbox 类文档
|
|
2
|
-
|
|
3
|
-
`Sandbox` 是一个**单例沙盒执行环境**,用于在隔离的上下文中**安全执行动态 JavaScript 代码**(如用户生成的表单逻辑、插件脚本等)。
|
|
4
|
-
通过 `Proxy` 代理与 `with` 语句结合,提供受控的变量访问,防止污染全局作用域。
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 目录
|
|
9
|
-
- [概述](#概述)
|
|
10
|
-
- [核心机制](#核心机制)
|
|
11
|
-
- [静态方法](#静态方法)
|
|
12
|
-
- [`initialize`](#initialize)
|
|
13
|
-
- [实例方法](#实例方法)
|
|
14
|
-
- [`createFormClass`](#createformclass)
|
|
15
|
-
- [使用示例](#使用示例)
|
|
16
|
-
- [安全机制说明](#安全机制说明)
|
|
17
|
-
- [高级用法](#高级用法)
|
|
18
|
-
- [注意事项](#注意事项)
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## 概述
|
|
23
|
-
|
|
24
|
-
`Sandbox` 设计目标:
|
|
25
|
-
- 安全执行不受信任的代码
|
|
26
|
-
- 注入指定上下文变量
|
|
27
|
-
- 防止访问未授权的全局对象
|
|
28
|
-
- 提供友好的变量访问体验(类似全局可用)
|
|
29
|
-
|
|
30
|
-
```ts
|
|
31
|
-
export default class Sandbox { ... }
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
> 典型应用:动态表单引擎、插件系统、用户自定义逻辑、微前端脚本隔离。
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## 核心机制
|
|
39
|
-
|
|
40
|
-
| 机制 | 说明 |
|
|
41
|
-
|------|------|
|
|
42
|
-
| **单例模式** | 全局唯一沙盒实例 |
|
|
43
|
-
| **依赖注入** | 通过 `injectedKeys` 指定可访问变量 |
|
|
44
|
-
| **Proxy 代理** | 控制 `in` 和 `get` 访问行为 |
|
|
45
|
-
| **with + const 解构** | 让注入变量在代码中像全局变量一样使用 |
|
|
46
|
-
| **双重上下文来源** | 支持 `ctx` 和 `ctx.window` 两个来源 |
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## 静态方法
|
|
51
|
-
|
|
52
|
-
### `initialize`
|
|
53
|
-
|
|
54
|
-
初始化 `Sandbox` 单例实例。
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
static initialize(ctx: any, injectedKeys: Array<string>): Sandbox
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
**参数:**
|
|
61
|
-
- `ctx`: `any` - 基础上下文对象(通常包含工具函数、API 等)
|
|
62
|
-
- `injectedKeys`: `string[]` - 允许注入到沙盒的变量名列表
|
|
63
|
-
|
|
64
|
-
**返回值:** `Sandbox` 实例
|
|
65
|
-
|
|
66
|
-
> 必须先调用 `initialize`,否则无法使用 `createFormClass`。
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## 实例方法
|
|
71
|
-
|
|
72
|
-
### `createFormClass`
|
|
73
|
-
|
|
74
|
-
在沙盒中执行代码字符串,生成表单类逻辑。
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
createFormClass(code: string): any
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**参数:**
|
|
81
|
-
- `code`: `string` - 要执行的 JS 代码(支持 `return` 一个类或对象)
|
|
82
|
-
|
|
83
|
-
**返回值:** 代码执行结果(通常是一个类构造函数或配置对象)
|
|
84
|
-
|
|
85
|
-
**执行流程:**
|
|
86
|
-
1. 提取 `injectedKeys` 中存在的变量 → 注入 `injected`
|
|
87
|
-
2. 合并 `ctx` + `injected` → 形成 `sandboxContext`
|
|
88
|
-
3. 创建 `Proxy` 代理,控制变量访问
|
|
89
|
-
4. 使用 `with (sandbox) { const xxx = sandbox.xxx; ...code }`
|
|
90
|
-
5. 通过 `new Function` 执行包装后的代码
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## 使用示例
|
|
95
|
-
|
|
96
|
-
### 1. 基础使用:执行表单验证逻辑
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
import Sandbox from './Sandbox';
|
|
100
|
-
|
|
101
|
-
// 准备上下文
|
|
102
|
-
const context = {
|
|
103
|
-
utils: {
|
|
104
|
-
isEmail: (str) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str),
|
|
105
|
-
required: (val) => val != null && val !== ''
|
|
106
|
-
},
|
|
107
|
-
api: {
|
|
108
|
-
submitForm: async (data) => {
|
|
109
|
-
console.log('提交表单:', data);
|
|
110
|
-
return { success: true };
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
window: window // 允许访问部分全局对象(如 console, Math)
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// 定义可注入的变量
|
|
117
|
-
const injectedKeys = ['utils', 'api', 'console', 'Math', 'Date'];
|
|
118
|
-
|
|
119
|
-
// 初始化沙盒
|
|
120
|
-
Sandbox.initialize(context, injectedKeys);
|
|
121
|
-
|
|
122
|
-
const sandbox = Sandbox.initialize(context, injectedKeys);
|
|
123
|
-
|
|
124
|
-
// 用户编写的动态代码
|
|
125
|
-
const userCode = `
|
|
126
|
-
class UserForm {
|
|
127
|
-
constructor(data) {
|
|
128
|
-
this.data = data;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
validate() {
|
|
132
|
-
if (!utils.required(this.data.email)) return '邮箱必填';
|
|
133
|
-
if (!utils.isEmail(this.data.email)) return '邮箱格式错误';
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async submit() {
|
|
138
|
-
const error = this.validate();
|
|
139
|
-
if (error) throw new Error(error);
|
|
140
|
-
return await api.submitForm(this.data);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return UserForm;
|
|
145
|
-
`;
|
|
146
|
-
|
|
147
|
-
// 执行并获取类
|
|
148
|
-
const UserFormClass = sandbox.createFormClass(userCode);
|
|
149
|
-
|
|
150
|
-
// 使用
|
|
151
|
-
const form = new UserFormClass({ email: 'test@example.com' });
|
|
152
|
-
form.submit().then(console.log).catch(console.error);
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## 安全机制说明
|
|
158
|
-
|
|
159
|
-
| 机制 | 效果 |
|
|
160
|
-
|------|------|
|
|
161
|
-
| `injectedKeys` 白名单 | 仅允许显式声明的变量可访问 |
|
|
162
|
-
| `Proxy.has` 控制 | `key in sandbox` 行为受控 |
|
|
163
|
-
| `Proxy.get` 警告 | 访问未定义变量时 `console.warn` |
|
|
164
|
-
| 无 `window` 直接暴露 | 必须通过 `injectedKeys` 授权 |
|
|
165
|
-
| `with` + `const` 解构 | 避免 `with` 污染外部作用域 |
|
|
166
|
-
|
|
167
|
-
> 注意:`new Function` 本身不解析词法作用域,天然隔离外部变量。
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
### 动态注入运行时变量
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
const dynamicCtx = { currentUser: null };
|
|
175
|
-
Sandbox.initialize({ ...context, dynamicCtx }, [...injectedKeys, 'currentUser']);
|
|
176
|
-
|
|
177
|
-
// 后续更新
|
|
178
|
-
dynamicCtx.currentUser = { id: 1, name: 'Alice' };
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## 注意事项
|
|
184
|
-
|
|
185
|
-
| 项目 | 说明 |
|
|
186
|
-
|------|------|
|
|
187
|
-
| **必须初始化** | 未调用 `initialize` 将导致 `instance` 为 `undefined` |
|
|
188
|
-
| **injectedKeys 必须精确** | 多注入风险,少注入功能缺失 |
|
|
189
|
-
| **避免注入危险对象** | 如 `eval`, `Function`, `window.fetch`(视需求) |
|
|
190
|
-
| **性能注意** | `new Function` 有编译开销,建议缓存编译结果 |
|
|
191
|
-
| **不支持 ES6 import** | 动态代码中无法使用 `import`,需通过注入提供 |
|
|
192
|
-
| **调试建议** | 开发时可临时注入 `console` 便于调试 |
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## API 汇总
|
|
197
|
-
|
|
198
|
-
| 方法 | 类型 | 描述 |
|
|
199
|
-
|------|------|------|
|
|
200
|
-
| `initialize` | `static` | 初始化沙盒上下文 |
|
|
201
|
-
| `createFormClass` | `instance` | 执行动态代码 |
|
package/dist/Sandbox.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 单例沙盒类,用于在隔离环境中安全执行代码
|
|
3
|
-
* 提供上下文注入和代理机制来控制代码执行环境
|
|
4
|
-
*/
|
|
5
|
-
export default class Sandbox {
|
|
6
|
-
#private;
|
|
7
|
-
/**
|
|
8
|
-
* Sandbox的单例实例
|
|
9
|
-
*/
|
|
10
|
-
private static instance;
|
|
11
|
-
/**
|
|
12
|
-
* 私有构造函数,用于强制单例模式
|
|
13
|
-
* @param ctx - 沙盒执行上下文
|
|
14
|
-
* @param injectedKeys - 需要注入的变量键名数组
|
|
15
|
-
*/
|
|
16
|
-
private constructor();
|
|
17
|
-
/**
|
|
18
|
-
* 初始化单例Sandbox实例
|
|
19
|
-
* @param ctx - 沙盒执行上下文
|
|
20
|
-
* @param injectedKeys - 需要注入的变量键名数组
|
|
21
|
-
* @returns Sandbox的单例实例
|
|
22
|
-
*/
|
|
23
|
-
static initialize(ctx: any, injectedKeys: Array<string>): Sandbox;
|
|
24
|
-
/**
|
|
25
|
-
* 在沙盒环境中创建并执行表单类代码
|
|
26
|
-
* 使用代理模式控制变量访问,确保代码在安全的上下文中执行
|
|
27
|
-
* @param code - 要执行的JavaScript代码字符串
|
|
28
|
-
* @param ctx
|
|
29
|
-
* @param keys
|
|
30
|
-
* @returns 代码执行结果
|
|
31
|
-
*/
|
|
32
|
-
createFormClass(code: string, ctx?: any, keys?: Array<string>): any;
|
|
33
|
-
}
|
package/dist/Sandbox.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import FlexiContext from "./FlexiContext";
|
|
2
|
-
import { ModuleLoader } from "./index";
|
|
3
|
-
import FlexiForm from "./flexi-form/flexi_form/FlexiForm";
|
|
4
|
-
import FlexiCard from "./flexi-form/flexi_card/FlexiCard";
|
|
5
|
-
import FlexiComposite from "./flexi-form/flexi_composite/FlexiComposite";
|
|
6
|
-
import FlexiCriteriaSet from "./criteria-panel/lib/FlexiCriteriaSet";
|
|
7
|
-
import FlexiDataTable from "./flexi-datatable/FlexiDataTable";
|
|
8
|
-
import { Visibility } from "./flexi-form/lib";
|
|
9
|
-
import { FlexiFormDialog } from "./flexi-form";
|
|
10
|
-
import { FlexiFormPage } from "./flexi-form";
|
|
11
|
-
/**
|
|
12
|
-
* 单例沙盒类,用于在隔离环境中安全执行代码
|
|
13
|
-
* 提供上下文注入和代理机制来控制代码执行环境
|
|
14
|
-
*/
|
|
15
|
-
export default class Sandbox {
|
|
16
|
-
/**
|
|
17
|
-
* 私有上下文对象,包含沙盒执行环境
|
|
18
|
-
*/
|
|
19
|
-
#ctx;
|
|
20
|
-
/**
|
|
21
|
-
* 私有注入键数组,定义需要注入到沙盒的变量名
|
|
22
|
-
*/
|
|
23
|
-
#injectedKeys;
|
|
24
|
-
/**
|
|
25
|
-
* Sandbox的单例实例
|
|
26
|
-
*/
|
|
27
|
-
static instance;
|
|
28
|
-
/**
|
|
29
|
-
* 私有构造函数,用于强制单例模式
|
|
30
|
-
* @param ctx - 沙盒执行上下文
|
|
31
|
-
* @param injectedKeys - 需要注入的变量键名数组
|
|
32
|
-
*/
|
|
33
|
-
constructor(ctx, injectedKeys) {
|
|
34
|
-
this.#ctx = { ...ctx, Visibility, FlexiContext, ModuleLoader, FlexiForm, FlexiCard, FlexiComposite, FlexiCriteriaSet, FlexiDataTable, FlexiFormPage, FlexiFormDialog };
|
|
35
|
-
this.#injectedKeys = [...injectedKeys, 'Dialog', 'MessageBox', 'Indicator', 'Toast'];
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* 初始化单例Sandbox实例
|
|
39
|
-
* @param ctx - 沙盒执行上下文
|
|
40
|
-
* @param injectedKeys - 需要注入的变量键名数组
|
|
41
|
-
* @returns Sandbox的单例实例
|
|
42
|
-
*/
|
|
43
|
-
static initialize(ctx, injectedKeys) {
|
|
44
|
-
if (Sandbox.instance == null) {
|
|
45
|
-
Sandbox.instance = new Sandbox(ctx, injectedKeys);
|
|
46
|
-
}
|
|
47
|
-
return Sandbox.instance;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* 在沙盒环境中创建并执行表单类代码
|
|
51
|
-
* 使用代理模式控制变量访问,确保代码在安全的上下文中执行
|
|
52
|
-
* @param code - 要执行的JavaScript代码字符串
|
|
53
|
-
* @param ctx
|
|
54
|
-
* @param keys
|
|
55
|
-
* @returns 代码执行结果
|
|
56
|
-
*/
|
|
57
|
-
createFormClass(code, ctx = {}, keys = []) {
|
|
58
|
-
const injected = {};
|
|
59
|
-
ctx = { ...this.#ctx, ...ctx };
|
|
60
|
-
keys = [...new Set([...this.#injectedKeys, ...keys])];
|
|
61
|
-
for (const key of keys) {
|
|
62
|
-
if (ctx.window && key in ctx.window) {
|
|
63
|
-
injected[key] = ctx.window[key];
|
|
64
|
-
}
|
|
65
|
-
else if (key in ctx) {
|
|
66
|
-
injected[key] = ctx[key];
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
// 组合最终上下文
|
|
70
|
-
const sandboxContext = { ...this.#ctx, ...injected };
|
|
71
|
-
const self = this;
|
|
72
|
-
const sandbox = new Proxy(sandboxContext, {
|
|
73
|
-
has(target, key) {
|
|
74
|
-
// 如果在 sandboxContext 或 window 中存在
|
|
75
|
-
if (key in target)
|
|
76
|
-
return true;
|
|
77
|
-
if (self.#ctx.window && key in self.#ctx.window)
|
|
78
|
-
return true;
|
|
79
|
-
return false; // 不存在就返回 false
|
|
80
|
-
},
|
|
81
|
-
get(target, key) {
|
|
82
|
-
if (key in target)
|
|
83
|
-
return target[key];
|
|
84
|
-
if (self.#ctx.window && key in self.#ctx.window)
|
|
85
|
-
return self.#ctx.window[key];
|
|
86
|
-
console.warn(`Sandbox: ${String(key)} not found`);
|
|
87
|
-
return undefined;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
const wrappedCode = `
|
|
91
|
-
with (sandbox) {
|
|
92
|
-
${Object.keys(sandbox).map(k => `const ${k} = sandbox.${k};`).join('\n')}
|
|
93
|
-
|
|
94
|
-
${code}
|
|
95
|
-
}
|
|
96
|
-
`;
|
|
97
|
-
console.log('sandbox code: ', wrappedCode);
|
|
98
|
-
const fn = new Function('sandbox', wrappedCode);
|
|
99
|
-
return fn(sandbox);
|
|
100
|
-
}
|
|
101
|
-
}
|