@love-sqjm/magic 2026.4.15

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.
Files changed (56) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +93 -0
  3. package/app.js +51 -0
  4. package/doc/api/examples.md +563 -0
  5. package/doc/api/index.md +563 -0
  6. package/doc/architecture.md +322 -0
  7. package/doc/config-reference.md +646 -0
  8. package/doc/data-model.md +622 -0
  9. package/doc/development-guide.md +582 -0
  10. package/doc/magic-file/index.md +610 -0
  11. package/doc/user-guide/index.md +485 -0
  12. package/doc/workflow.md +548 -0
  13. package/index.js +157 -0
  14. package/magic.bat +2 -0
  15. package/magic.ps1 +5 -0
  16. package/package.json +44 -0
  17. package/script/build-project.js +16 -0
  18. package/script/config.js +23 -0
  19. package/script/create-project.js +73 -0
  20. package/script/global/printf.js +13 -0
  21. package/script/global/project-build-config.js +161 -0
  22. package/script/global/support-platform.js +5 -0
  23. package/script/module/compiler/global.js +43 -0
  24. package/script/module/compiler/id-generate.js +18 -0
  25. package/script/module/compiler/index-dom.js +78 -0
  26. package/script/module/compiler/macro-replace.js +22 -0
  27. package/script/module/compiler/macro.js +6 -0
  28. package/script/module/compiler/start.js +10 -0
  29. package/script/module/compiler/step/1.js +253 -0
  30. package/script/module/compiler/step/2.js +79 -0
  31. package/script/module/compiler/step/3.js +37 -0
  32. package/script/module/compiler/step/4.js +20 -0
  33. package/script/module/compiler/step/5.js +634 -0
  34. package/script/module/compiler/step/6.js +304 -0
  35. package/script/module/compiler/step/end.js +124 -0
  36. package/script/run-project.js +249 -0
  37. package/script/util/bun-fs.js +40 -0
  38. package/script/util/copy-dir.js +21 -0
  39. package/script/util/create-simple-dom-element.js +23 -0
  40. package/script/util/file-util.js +95 -0
  41. package/script/util/filtration-file.js +20 -0
  42. package/script/util/get-dir-all-file.js +28 -0
  43. package/script/util/get-first-object-key.js +9 -0
  44. package/script/util/is-empty-object.js +8 -0
  45. package/script/util/is-string-over-size.js +4 -0
  46. package/script/util/is.js +18 -0
  47. package/script/util/logging.js +142 -0
  48. package/script/util/task.js +16 -0
  49. package/script/util/traversal.js +28 -0
  50. package/template/platform-config/node-webkit +23 -0
  51. package/template/platform-config/web +1 -0
  52. package/template/project-base/app.xml +5 -0
  53. package/template/project-base/build.module.toml +37 -0
  54. package/template/project-base/build.toml +43 -0
  55. package/template/runtime/runtime.css +3 -0
  56. package/template/runtime/runtime.js +895 -0
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # Magic 框架
2
+
3
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/SQJM/magic)
4
+ [![version](https://img.shields.io/badge/version-1.0.0-green.svg)](https://github.com/SQJM/magic)
5
+
6
+ ## 概述
7
+
8
+ **Magic** 是一个基于 Bun.js 运行的全栈 Web 开发框架,旨在提供高效、简洁的全栈开发体验。通过自定义的 `.m` 文件格式,开发者可以将模板、样式和脚本整合到单一文件中,极大简化了组件化开发的复杂度。
9
+
10
+ ## 核心特性
11
+
12
+ | 特性 | 描述 |
13
+ |------|------|
14
+ | **一体化文件格式** | `.m` 文件整合 HTML 模板、CSS 样式、JavaScript 脚本 |
15
+ | **多平台支持** | Web 浏览器、Node-Webkit 桌面应用、可复用模块 |
16
+ | **编译时优化** | Babel AST 转换、CSS 作用域、代码压缩 |
17
+ | **热更新支持** | WebSocket 实时刷新开发 |
18
+ | **宏系统** | 支持文件包含、数据绑定等编译时处理 |
19
+ | **模块化架构** | 清晰的编译器流水线设计 |
20
+
21
+ ## 技术栈
22
+
23
+ | 类别 | 技术选型 |
24
+ |------|----------|
25
+ | 运行时 | Bun.js |
26
+ | CLI | Commander.js |
27
+ | HTML 解析 | node-html-parser |
28
+ | CSS 处理 | PostCSS + Autoprefixer |
29
+ | JS 压缩 | Terser |
30
+ | HTML 压缩 | html-minifier-terser |
31
+ | AST 处理 | @babel/* |
32
+ | 文件匹配 | fast-glob |
33
+ | WebSocket | ws |
34
+
35
+ ## 快速开始
36
+
37
+ ### 安装
38
+
39
+ ```bash
40
+ bun install -g @love-sqjm/magic
41
+ ```
42
+
43
+ ### 创建项目
44
+
45
+ ```bash
46
+ magic init new-project --web
47
+ ```
48
+
49
+ ### 构建项目
50
+
51
+ ```bash
52
+ cd new-project
53
+ magic build
54
+ ```
55
+
56
+ ### 运行项目
57
+
58
+ ```bash
59
+ magic run
60
+ ```
61
+
62
+ ## 支持的平台
63
+
64
+ | 平台 | 说明 |
65
+ |------|------|
66
+ | `web` | 浏览器环境,支持内置 HTTP 服务器和热更新 |
67
+ | `node-webkit` | Node-Webkit 桌面应用 |
68
+ | `module` | 可复用的模块库 |
69
+
70
+ ## 项目结构
71
+
72
+ ```
73
+ magic-project/
74
+ ├── app/ # 源码目录
75
+ │ ├── app.xml # 应用配置文件
76
+ │ ├── index.m # 入口模块
77
+ │ └── ... # 其他 .m 模块文件
78
+ ├── build/ # 构建输出目录
79
+ ├── build.toml # 构建配置文件
80
+ └── package.json
81
+ ```
82
+
83
+ ## 学习资源
84
+
85
+ - [架构文档](./architecture.md) - 系统架构和技术细节
86
+ - [使用指南](./user-guide/index.md) - 环境配置和部署步骤
87
+ - [.m 文件规范](./magic-file/index.md) - 组件开发文档
88
+ - [API 参考](./api/index.md) - Runtime API 详细说明
89
+ - [配置手册](./config-reference.md) - build.toml 配置详解
90
+
91
+ ## 许可证
92
+
93
+ MIT License - [SQJM](https://github.com/SQJM)
package/app.js ADDED
@@ -0,0 +1,51 @@
1
+ import fs from "node:fs";
2
+
3
+ const runDir = import.meta.dir + '/';
4
+
5
+ const App = {
6
+ version : JSON.parse( fs.readFileSync( runDir + "package.json" ).toString() ).version,
7
+ runDir : runDir,
8
+ templateDir : {
9
+ runtime : {
10
+ path : runDir + "template/runtime/"
11
+ },
12
+ platformConfig : {
13
+ path : runDir + "template/platform-config/"
14
+ },
15
+ projectBase : {
16
+ path : runDir + "template/project-base/"
17
+ }
18
+ },
19
+ project : {
20
+ dir : process.cwd() + '/'
21
+ }
22
+ };
23
+
24
+ function read( path ) {
25
+ if ( !fs.existsSync( path ) ) throw `${ path } doesn't exist`;
26
+ return fs.readFileSync( path ).toString();
27
+ }
28
+
29
+ export const app = {
30
+ ...App,
31
+ templateDir : {
32
+ runtime : {
33
+ path : App.templateDir.runtime.path,
34
+ get( fileName ) {
35
+ return read( App.templateDir.runtime.path + fileName );
36
+ }
37
+ },
38
+ platformConfig : {
39
+ path : App.templateDir.platformConfig.path,
40
+ get( fileName ) {
41
+ return read( App.templateDir.platformConfig.path + fileName );
42
+ }
43
+ },
44
+ projectBase : {
45
+ path : App.templateDir.projectBase.path,
46
+ get( fileName ) {
47
+ return read( App.templateDir.projectBase.path + fileName );
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,563 @@
1
+ # Magic Runtime 函数使用示例
2
+
3
+ ## 目录
4
+
5
+ 1. [模块导入 - importM](#1-模块导入---importm)
6
+ 2. [元素获取 - $id / $](#2-元素获取---id--)
7
+ 3. [UiData 响应式数据 - createUiData](#3-uodata-响应式数据---createuodata)
8
+ 4. [动态值绑定 - DynamicValueBind](#4-动态值绑定---dynamicvaluebind)
9
+ 5. [事件系统 - emit / on_event](#5-事件系统---emit--on_event)
10
+ 6. [参数处理 - parserArgs / createArgs](#6-参数处理---parserargs--createargs)
11
+ 7. [路由系统 - router](#7-路由系统---router)
12
+ 8. [其他工具函数](#8-其他工具函数)
13
+
14
+ ---
15
+
16
+ ## 1. 模块导入 - importM
17
+
18
+ ### 基本用法
19
+
20
+ ```javascript
21
+ // 导入并实例化一个组件
22
+ const dialog = magic.importM("dialog");
23
+
24
+ // 传入参数
25
+ const form = magic.importM("form", {
26
+ title: "用户注册",
27
+ width: 400
28
+ });
29
+
30
+ // 传入事件监听
31
+ const button = magic.importM("button", {}, {
32
+ click: (data) => {
33
+ console.log("按钮被点击:", data);
34
+ }
35
+ });
36
+ ```
37
+
38
+ ### 完整示例
39
+
40
+ ```xml
41
+ <!-- button.m -->
42
+ <template>
43
+ <button #id="btn">点击</button>
44
+ </template>
45
+
46
+ <script code="event">
47
+ click = (event) => {
48
+ emit_event("click", { time: Date.now() });
49
+ }
50
+ </script>
51
+
52
+ <script code="interface">
53
+ setText = (text) => {
54
+ $btn.textContent = text;
55
+ };
56
+ </script>
57
+ ```
58
+
59
+ ```javascript
60
+ // 使用按钮组件
61
+ const btn = magic.importM("button");
62
+ btn.interface.setText("新文本");
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 2. 元素获取 - $id / $
68
+
69
+ ### $id() - 获取模块内元素
70
+
71
+ ```xml
72
+ <script code="global">
73
+ const {
74
+ $container, // 获取 #id="container" 的元素
75
+ $title, // 获取 #id="title" 的元素
76
+ $submitBtn // 获取 #id="submitBtn" 的元素
77
+ } = $id();
78
+ </script>
79
+ ```
80
+
81
+ ### $() - 全局查询
82
+
83
+ ```javascript
84
+ // 在整个文档中查找元素
85
+ const element = magic.$("my-element-id");
86
+
87
+ // 在指定根元素内查找
88
+ const container = magic.$("container-id");
89
+ const child = magic.$("child-id", container);
90
+ ```
91
+
92
+ ### 查找命名元素
93
+
94
+ ```xml
95
+ <template>
96
+ <div #id="form">
97
+ <input #name="username" placeholder="用户名"/>
98
+ <button #name="submit">提交</button>
99
+ </div>
100
+ </template>
101
+
102
+ <script code="global">
103
+ const { $form } = $id();
104
+
105
+ // 使用 $name 查找命名元素
106
+ const usernameInput = $form.$name("username");
107
+ const submitBtn = $form.$name("submit");
108
+ </script>
109
+ ```
110
+
111
+ ---
112
+
113
+ ## 3. UiData 响应式数据 - createUiData
114
+
115
+ ### 基本用法
116
+
117
+ ```xml
118
+ <script code="global">
119
+ const UiData = magic_define_ui_data({
120
+ username: "Guest",
121
+ age: 18,
122
+ isActive: true
123
+ });
124
+
125
+ // 修改值会自动触发更新
126
+ UiData.username = "Alice";
127
+ UiData.age = 25;
128
+ UiData.isActive = false;
129
+ </script>
130
+ ```
131
+
132
+ ### 嵌套对象
133
+
134
+ ```xml
135
+ <script code="global">
136
+ const UiData = magic_define_ui_data({
137
+ user: {
138
+ name: "Guest",
139
+ profile: {
140
+ avatar: "",
141
+ bio: ""
142
+ }
143
+ }
144
+ });
145
+
146
+ // 深度修改
147
+ UiData.user.name = "Alice";
148
+ UiData.user.profile.avatar = "/avatar.png";
149
+ </script>
150
+ ```
151
+
152
+ ### 数组支持
153
+
154
+ ```xml
155
+ <script code="global">
156
+ const UiData = magic_define_ui_data({
157
+ items: ["苹果", "香蕉", "橙子"],
158
+ selectedIndex: 0
159
+ });
160
+
161
+ // 修改数组
162
+ UiData.items.push("葡萄");
163
+ UiData.selectedIndex = 2;
164
+ </script>
165
+ ```
166
+
167
+ ### 类型自动转换
168
+
169
+ ```xml
170
+ <script code="global">
171
+ const UiData = magic_define_ui_data({
172
+ count: 0, // Number
173
+ isValid: false, // Boolean
174
+ pattern: /^abc$/, // RegExp
175
+ data: [1, 2, 3] // Array
176
+ });
177
+
178
+ // 传入字符串会自动转换类型
179
+ const UserInput = magic.createUiData(UiData, {
180
+ count: "42", // "42" → 42
181
+ isValid: "true", // "true" → true
182
+ pattern: "/^xyz$/", // 字符串 → RegExp
183
+ data: "[1,2,3,4]" // 字符串 → Array
184
+ });
185
+ </script>
186
+ ```
187
+
188
+ ---
189
+
190
+ ## 4. 动态值绑定 - DynamicValueBind
191
+
192
+ ### 文本节点绑定
193
+
194
+ ```xml
195
+ <template>
196
+ <div #id="container">
197
+ <p #id="name-text">Hello ${username}</p>
198
+ <p #id="count-text">Count: ${count}</p>
199
+ </div>
200
+ </template>
201
+
202
+ <script code="global">
203
+ const UiData = magic_define_ui_data({
204
+ username: "Guest",
205
+ count: 0
206
+ });
207
+
208
+ const {
209
+ $nameText,
210
+ $countText
211
+ } = $id();
212
+ </script>
213
+
214
+ <script code="interface">
215
+ startBinding = () => {
216
+ magic_dynamic_value_bind($nameText, $countText);
217
+ };
218
+
219
+ increment = () => {
220
+ UiData.count++;
221
+ };
222
+ </script>
223
+
224
+ <script>
225
+ startBinding();
226
+ </script>
227
+ ```
228
+
229
+ ### 工作原理
230
+
231
+ 1. `${username}` 在编译时被转换为注释节点 `<!--MAGIC:DV[username]-->`
232
+ 2. `magic_dynamic_value_bind()` 找到所有绑定点
233
+ 3. 当 `UiData.username` 改变时,文本节点自动更新
234
+
235
+ ---
236
+
237
+ ## 5. 事件系统 - emit / on_event
238
+
239
+ ### 定义事件
240
+
241
+ ```xml
242
+ <template>
243
+ <button #id="btn">点击</button>
244
+ </template>
245
+
246
+ <expose-event>
247
+ <click/>
248
+ <change/>
249
+ </expose-event>
250
+
251
+ <script code="event">
252
+ click = (eventData) => {
253
+ emit_event("click", { timestamp: Date.now() });
254
+ };
255
+
256
+ change = (newValue) => {
257
+ emit_event("change", { value: newValue });
258
+ };
259
+ </script>
260
+ ```
261
+
262
+ ### 监听事件
263
+
264
+ ```javascript
265
+ const component = magic.importM("my-component", {}, {
266
+ click: (data) => {
267
+ console.log("点击事件:", data);
268
+ },
269
+ change: (data) => {
270
+ console.log("变更事件:", data);
271
+ }
272
+ });
273
+ ```
274
+
275
+ ### 主动触发事件
276
+
277
+ ```javascript
278
+ // 通过 call 接口触发
279
+ const scope = magic.call(component);
280
+ scope.event("click", { custom: true });
281
+ ```
282
+
283
+ ---
284
+
285
+ ## 6. 参数处理 - parserArgs / createArgs
286
+
287
+ ### parserArgs - 解析参数
288
+
289
+ ```javascript
290
+ // 解析 JSON 字符串
291
+ const args1 = magic.parserArgs('{"name":"Alice","age":25}');
292
+ // 结果: { name: "Alice", age: 25 }
293
+
294
+ // 解析嵌套键
295
+ const args2 = magic.parserArgs({
296
+ "user:profile:name": "Alice",
297
+ "user:profile:age": "25"
298
+ });
299
+ // 结果: { user: { profile: { name: "Alice", age: "25" } } }
300
+
301
+ // 使用冒号分隔的键
302
+ const args3 = magic.parserArgs({
303
+ "a:b:c": "deep value"
304
+ });
305
+ // 结果: { a: { b: { c: "deep value" } } }
306
+ ```
307
+
308
+ ### createArgs - 创建参数字符串
309
+
310
+ ```javascript
311
+ const obj = { name: "Alice", age: 25 };
312
+ const jsonStr = magic.createArgs(obj);
313
+ // 结果: '{"name":"Alice","age":25}'
314
+ ```
315
+
316
+ ---
317
+
318
+ ## 7. 路由系统 - router
319
+
320
+ ### 基本使用
321
+
322
+ ```javascript
323
+ // 添加路由
324
+ magic.router.addRoute('/', 'home');
325
+ magic.router.addRoute('/about', 'about');
326
+ magic.router.addRoute('/user/:id', 'user-profile');
327
+
328
+ // 初始化路由
329
+ magic.router.init('router-view');
330
+ ```
331
+
332
+ ### 批量添加路由
333
+
334
+ ```javascript
335
+ magic.router.addRoutes([
336
+ { path: '/', component: 'home' },
337
+ { path: '/about', component: 'about' },
338
+ { path: '/user/:id', component: 'user-profile' },
339
+ { path: '/post/:postId/comment/:commentId', component: 'comment' }
340
+ ]);
341
+ ```
342
+
343
+ ### 导航
344
+
345
+ ```javascript
346
+ // 跳转到新路径(添加历史记录)
347
+ magic.router.push('/about');
348
+
349
+ // 替换当前路径(不添加历史)
350
+ magic.router.replace('/user/123');
351
+
352
+ // 获取当前路由
353
+ const route = magic.router.getCurrentRoute();
354
+ console.log(route.path); // "/user/123"
355
+ console.log(route.params.id); // "123"
356
+ console.log(route.query); // { search: "abc" }
357
+ ```
358
+
359
+ ### 动态路由参数
360
+
361
+ ```javascript
362
+ // /user/:id → { path: '/user/123', params: { id: '123' } }
363
+ // /post/:postId/comment/:commentId → { path: '/post/1/comment/5', params: { postId: '1', commentId: '5' } }
364
+ ```
365
+
366
+ ### 导航守卫
367
+
368
+ ```javascript
369
+ magic.router.beforeEach((to, from) => {
370
+ // to: 目标路由信息
371
+ // from: 来源路由信息
372
+
373
+ if (to.path === '/admin' && !isLoggedIn) {
374
+ return '/login'; // 重定向到登录页
375
+ }
376
+
377
+ return true; // 允许导航
378
+ });
379
+
380
+ // 支持异步守卫
381
+ magic.router.beforeEach(async (to, from) => {
382
+ const canAccess = await checkPermission(to.path);
383
+ if (!canAccess) {
384
+ return '/unauthorized';
385
+ }
386
+ return true;
387
+ });
388
+ ```
389
+
390
+ ### 完整示例
391
+
392
+ ```xml
393
+ <!-- index.m -->
394
+ <template>
395
+ <div #id="app">
396
+ <nav #id="nav">
397
+ <a @click="goHome">首页</a>
398
+ <a @click="goAbout">关于</a>
399
+ <a @click="goUser">用户:123</a>
400
+ </nav>
401
+ <div #id="router-view"></div>
402
+ </div>
403
+ </template>
404
+
405
+ <script code="event">
406
+ goHome = () => magic.router.push('/');
407
+ goAbout = () => magic.router.push('/about');
408
+ goUser = () => magic.router.push('/user/123');
409
+ </script>
410
+
411
+ <script>
412
+ magic.router.addRoutes([
413
+ { path: '/', component: 'home' },
414
+ { path: '/about', component: 'about' },
415
+ { path: '/user/:id', component: 'user-profile' }
416
+ ]);
417
+
418
+ magic.router.init('router-view');
419
+ </script>
420
+ ```
421
+
422
+ ---
423
+
424
+ ## 8. 其他工具函数
425
+
426
+ ### importElementInit - 初始化导入组件
427
+
428
+ ```javascript
429
+ // 导入多个组件并批量初始化
430
+ magic.importElementInit(comp1, comp2, comp3);
431
+ // 会依次调用每个组件的 _render() 接口方法
432
+ ```
433
+
434
+ ### exportInterface - 导出接口
435
+
436
+ ```javascript
437
+ const target = {};
438
+ magic.exportInterface(scope, target, {
439
+ _render: nop, // 直接映射
440
+ onClick: (args) => { // 函数转换
441
+ console.log("Clicked with:", args);
442
+ }
443
+ });
444
+ ```
445
+
446
+ ### GetInterface - 获取组件接口
447
+
448
+ ```javascript
449
+ const element = magic.$("my-component");
450
+ const interface = magic.GetInterface(element);
451
+ if (interface) {
452
+ interface.someMethod();
453
+ }
454
+ ```
455
+
456
+ ### BindScope - 绑定作用域
457
+
458
+ ```javascript
459
+ const elements = [elem1, elem2, elem3];
460
+ const scoped = magic.BindScope(elements, scope);
461
+ // 每个元素会添加 __SCOPE__ 属性指向 scope
462
+ ```
463
+
464
+ ### mapIdElement - ID 映射
465
+
466
+ ```javascript
467
+ const map = magic.mapIdElement();
468
+ map.s("element-id", element, "optional-class");
469
+ const el = map.get("element-id");
470
+ ```
471
+
472
+ ### idGenerate - 生成唯一 ID
473
+
474
+ ```javascript
475
+ const id1 = magic.idGenerate(); // 生成带时间戳的唯一 ID
476
+ const id2 = magic.idGenerate(6); // 指定长度
477
+ ```
478
+
479
+ ### parserListen - 解析监听器
480
+
481
+ ```javascript
482
+ const listen = magic.parserListen({
483
+ click: handleClick,
484
+ change: handleChange
485
+ });
486
+ ```
487
+
488
+ ---
489
+
490
+ ## 综合示例:完整组件
491
+
492
+ ```xml
493
+ <!-- user-card.m -->
494
+ <import root=".">
495
+ <avatar/>
496
+ </import>
497
+
498
+ <template>
499
+ <div #id="card">
500
+ <avatar #id="avatar-img" :src="avatar"/>
501
+ <h3 #id="name">${name}</h3>
502
+ <p #id="bio">${bio}</p>
503
+ <button #id="edit-btn" @click="edit">编辑</button>
504
+ </div>
505
+ </template>
506
+
507
+ <script code="global">
508
+ const UiData = magic_define_ui_data({
509
+ name: "未命名",
510
+ bio: "暂无简介",
511
+ avatar: "/default-avatar.png"
512
+ });
513
+
514
+ const { $name, $bio } = $id();
515
+ </script>
516
+
517
+ <expose-event>
518
+ <edit/>
519
+ </expose-event>
520
+
521
+ <script code="event">
522
+ edit = () => {
523
+ emit_event("edit", { name: UiData.name });
524
+ };
525
+ </script>
526
+
527
+ <script code="interface" once>
528
+ init = () => {
529
+ magic_dynamic_value_bind($name, $bio);
530
+ };
531
+
532
+ setUser = (user) => {
533
+ UiData.name = user.name;
534
+ UiData.bio = user.bio;
535
+ if (user.avatar) UiData.avatar = user.avatar;
536
+ };
537
+
538
+ getUser = () => {
539
+ return {
540
+ name: UiData.name,
541
+ bio: UiData.bio
542
+ };
543
+ };
544
+ </script>
545
+
546
+ <script code="interface">
547
+ startBinding();
548
+ </script>
549
+ ```
550
+
551
+ **使用:**
552
+
553
+ ```javascript
554
+ const card = magic.importM("user-card");
555
+
556
+ card.interface.setUser({
557
+ name: "Alice",
558
+ bio: "一名前端开发者",
559
+ avatar: "/avatars/alice.png"
560
+ });
561
+
562
+ card.interface.getUser(); // { name: "Alice", bio: "一名前端开发者" }
563
+ ```