@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
@@ -0,0 +1,563 @@
1
+ # Magic Runtime API 参考
2
+
3
+ ## 概述
4
+
5
+ Magic Runtime 是框架的客户端运行时库,提供 DOM 操作、模块加载、事件处理等核心功能。
6
+
7
+ ## 全局对象
8
+
9
+ ### magic_version
10
+
11
+ 框架版本号(只读)
12
+
13
+ ```typescript
14
+ const version: string;
15
+ console.log(magic_version); // "1.0.0"
16
+ ```
17
+
18
+ ### nop
19
+
20
+ 空值常量,用于接口占位
21
+
22
+ ```typescript
23
+ const nop: null;
24
+ ```
25
+
26
+ ### __MAGIC__
27
+
28
+ 框架内部存储对象
29
+
30
+ ```typescript
31
+ const __MAGIC__: {
32
+ M: Record<string, new (...args: any[]) => any>;
33
+ CREATE_ELEMENT_LIST: Map<any, any>;
34
+ };
35
+ ```
36
+
37
+ ## magic 对象
38
+
39
+ 框架核心对象,提供所有运行时功能。
40
+
41
+ ### init()
42
+
43
+ 初始化 Magic 框架
44
+
45
+ ```typescript
46
+ init(main: string): void
47
+ ```
48
+
49
+ **参数:**
50
+ - `main` - 主模块名称
51
+
52
+ **示例:**
53
+ ```javascript
54
+ magic.init("index");
55
+ ```
56
+
57
+ ---
58
+
59
+ ### dom
60
+
61
+ DOM 操作工具集
62
+
63
+ #### dom.element()
64
+
65
+ 创建 DOM 元素
66
+
67
+ ```typescript
68
+ element(tag: string): HTMLElement & { __MAGIC_CREATE_ELEMENT__: boolean }
69
+ ```
70
+
71
+ **示例:**
72
+ ```javascript
73
+ const div = magic.dom.element("div");
74
+ ```
75
+
76
+ #### dom.text()
77
+
78
+ 创建文本节点
79
+
80
+ ```typescript
81
+ text(content: string): Text
82
+ ```
83
+
84
+ **示例:**
85
+ ```javascript
86
+ const textNode = magic.dom.text("Hello");
87
+ ```
88
+
89
+ #### dom.append()
90
+
91
+ 追加子元素
92
+
93
+ ```typescript
94
+ append(
95
+ p: HTMLElement | DocumentFragment,
96
+ ...childs: Array<HTMLElement | { fragment: DocumentFragment }>
97
+ ): void
98
+ ```
99
+
100
+ **示例:**
101
+ ```javascript
102
+ magic.dom.append(parentElement, child1, child2);
103
+ ```
104
+
105
+ #### dom.attribute()
106
+
107
+ 设置元素属性
108
+
109
+ ```typescript
110
+ attribute(e: HTMLElement, atts: Record<string, string>): void
111
+ ```
112
+
113
+ **示例:**
114
+ ```javascript
115
+ magic.dom.attribute(element, {
116
+ "class": "container active",
117
+ "data-id": "123"
118
+ });
119
+ ```
120
+
121
+ #### dom.event()
122
+
123
+ 绑定元素事件
124
+
125
+ ```typescript
126
+ event(
127
+ e: HTMLElement,
128
+ eventName: string,
129
+ _this: { __magic_event: Record<string, Function> },
130
+ fnName: string,
131
+ opt?: AddEventListenerOptions
132
+ ): void
133
+ ```
134
+
135
+ **示例:**
136
+ ```javascript
137
+ magic.dom.event(element, "click", scope, "handleClick");
138
+ ```
139
+
140
+ ---
141
+
142
+ ### importM()
143
+
144
+ 导入并实例化模块
145
+
146
+ ```typescript
147
+ importM(
148
+ name: string,
149
+ args?: Record<string, any>,
150
+ listen?: Record<string, Function>
151
+ ): ImportedModuleElement
152
+ ```
153
+
154
+ **参数:**
155
+ - `name` - 模块名称(会自动转小写并过滤非字母字符)
156
+ - `args` - 传递给模块的参数
157
+ - `listen` - 事件监听对象
158
+
159
+ **返回值:** ImportedModuleElement
160
+
161
+ **示例:**
162
+ ```javascript
163
+ const dialog = magic.importM("ui/widget/dialog", {
164
+ title: "Hello",
165
+ width: 300
166
+ }, {
167
+ close: (data) => console.log("Closed:", data)
168
+ });
169
+ ```
170
+
171
+ **返回值接口:**
172
+ ```typescript
173
+ interface ImportedModuleElement extends HTMLElement {
174
+ __file: string; // 文件路径
175
+ mid: string; // 模块 ID
176
+ fragment: DocumentFragment;
177
+ interface: Record<string, Function>; // 模块接口
178
+ templateArgs: {
179
+ inline: boolean;
180
+ };
181
+ __root__element__: HTMLElement;
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ### call()
188
+
189
+ 创建作用域调用器
190
+
191
+ ```typescript
192
+ call(scope: {
193
+ __magic_interface: Record<string, Function>;
194
+ __magic_event: Record<string, Function>;
195
+ }): {
196
+ interface: (name: string, ...args: any[]) => any;
197
+ event: (name: string, ...args: any[]) => any;
198
+ listen: (funcName: string, ...args: any[]) => any;
199
+ }
200
+ ```
201
+
202
+ **示例:**
203
+ ```javascript
204
+ const caller = magic.call(moduleInstance);
205
+ caller.interface("setTitle", "New Title");
206
+ caller.event("click", eventData);
207
+ ```
208
+
209
+ ---
210
+
211
+ ### emit
212
+
213
+ 事件发射器
214
+
215
+ #### emit.event()
216
+
217
+ 创建事件发射函数
218
+
219
+ ```typescript
220
+ emit.event(listen: Record<string, Function>): (name: string, ...args: any[]) => any
221
+ ```
222
+
223
+ **示例:**
224
+ ```javascript
225
+ const emit_event = magic.emit.event({
226
+ select: (data) => console.log("Selected:", data)
227
+ });
228
+ emit_event("select", { value: "A" });
229
+ ```
230
+
231
+ ---
232
+
233
+ ### $id()
234
+
235
+ 创建 ID 元素查找器
236
+
237
+ ```typescript
238
+ $id(_$id: Map<string, HTMLElement>): {
239
+ (): Record<string, HTMLElement>;
240
+ (id: string): HTMLElement;
241
+ }
242
+ ```
243
+
244
+ **示例:**
245
+ ```javascript
246
+ const ids = $id(elementMap);
247
+ const element = ids(); // 获取所有元素
248
+ const btn = ids("submit-btn"); // 获取指定 ID 的元素
249
+ ```
250
+
251
+ ---
252
+
253
+ ### parserArgs()
254
+
255
+ 解析参数对象
256
+
257
+ ```typescript
258
+ parserArgs(args: string | Record<string, any>): Record<string, any>
259
+ ```
260
+
261
+ **特性:**
262
+ - 字符串参数会被解析为 JSON
263
+ - 支持嵌套键解析(`a:b:c` → `{a: {b: {c: value}}}`)
264
+
265
+ **示例:**
266
+ ```javascript
267
+ magic.parserArgs('{"name": "test"}');
268
+ magic.parserArgs({ "user:profile:name": "John" });
269
+ // 结果: { user: { profile: { name: "John" } } }
270
+ ```
271
+
272
+ ---
273
+
274
+ ### createArgs()
275
+
276
+ 创建参数字符串
277
+
278
+ ```typescript
279
+ createArgs(obj: Record<string, any>): string
280
+ ```
281
+
282
+ **示例:**
283
+ ```javascript
284
+ const jsonStr = magic.createArgs({ name: "test", value: 123 });
285
+ ```
286
+
287
+ ---
288
+
289
+ ### parserListen()
290
+
291
+ 解析事件监听对象
292
+
293
+ ```typescript
294
+ parserListen(listen?: Record<string, any>): Record<string, any>
295
+ ```
296
+
297
+ **示例:**
298
+ ```javascript
299
+ const handlers = magic.parserListen({
300
+ click: handleClick,
301
+ change: handleChange
302
+ });
303
+ ```
304
+
305
+ ---
306
+
307
+ ### on_event()
308
+
309
+ 触发事件(开始阶段)
310
+
311
+ ```typescript
312
+ on_event(
313
+ event: { type: string; runState?: string },
314
+ listen: Record<string, Function>
315
+ ): any
316
+ ```
317
+
318
+ **特性:**
319
+ - 设置 `event.runState = "on"`
320
+ - 调用匹配的监听函数
321
+
322
+ ---
323
+
324
+ ### end_event()
325
+
326
+ 触发事件(结束阶段)
327
+
328
+ ```typescript
329
+ end_event(
330
+ event: { type: string; runState?: string },
331
+ listen: Record<string, Function>
332
+ ): any
333
+ ```
334
+
335
+ **特性:**
336
+ - 设置 `event.runState = "end"`
337
+ - 调用匹配的监听函数
338
+
339
+ ---
340
+
341
+ ### mapIdElement()
342
+
343
+ 创建 ID-元素映射表
344
+
345
+ ```typescript
346
+ mapIdElement(): Map<string, HTMLElement> & {
347
+ s(id: string, e: HTMLElement, s?: string): void;
348
+ }
349
+ ```
350
+
351
+ **示例:**
352
+ ```javascript
353
+ const map = magic.mapIdElement();
354
+ map.s("myId", element, "active");
355
+ ```
356
+
357
+ ---
358
+
359
+ ### createUiData()
360
+
361
+ 合并 UI 数据(深度拷贝)
362
+
363
+ ```typescript
364
+ createUiData(
365
+ target: Record<string, any>,
366
+ source: Record<string, any>
367
+ ): Record<string, any>
368
+ ```
369
+
370
+ **特性:**
371
+ - 深度合并对象
372
+ - 类型转换支持(Boolean、Number、Array、RegExp)
373
+ - 返回带响应式绑定的深拷贝代理
374
+
375
+ **示例:**
376
+ ```javascript
377
+ const defaults = { text: "Hello", count: 0 };
378
+ const userData = { text: "World" };
379
+ const merged = magic.createUiData(defaults, userData);
380
+ ```
381
+
382
+ ---
383
+
384
+ ### importElementInit()
385
+
386
+ 初始化导入的元素
387
+
388
+ ```typescript
389
+ importElementInit(...args: Array<{ interface: Record<string, any> }>): void
390
+ ```
391
+
392
+ **描述:**
393
+ 依次调用每个元素的 `_render` 和 `__render__` 接口方法(如果存在)。
394
+
395
+ ---
396
+
397
+ ### exportInterface()
398
+
399
+ 导出接口到目标对象
400
+
401
+ ```typescript
402
+ exportInterface(
403
+ scope: Record<string, any>,
404
+ target: Record<string, any>,
405
+ parcel: Record<string, any>
406
+ ): void
407
+ ```
408
+
409
+ **参数:**
410
+ - `scope` - 源作用域对象
411
+ - `target` - 目标对象
412
+ - `parcel` - 接口映射配置
413
+
414
+ **示例:**
415
+ ```javascript
416
+ magic.exportInterface(scope, target, {
417
+ _render: nop, // 直接映射
418
+ onClick: (args) => {} // 函数包装
419
+ });
420
+ ```
421
+
422
+ ---
423
+
424
+ ### GetInterface()
425
+
426
+ 获取元素绑定的作用域接口
427
+
428
+ ```typescript
429
+ GetInterface(ele: HTMLElement): Record<string, any> | null
430
+ ```
431
+
432
+ ---
433
+
434
+ ### BindScope()
435
+
436
+ 为元素数组绑定作用域
437
+
438
+ ```typescript
439
+ BindScope(
440
+ arr: HTMLElement[],
441
+ ths: Record<string, any>
442
+ ): Array<HTMLElement & { readonly __SCOPE__: Record<string, any> }>
443
+ ```
444
+
445
+ **特性:**
446
+ - 为元素添加不可写的 `__SCOPE__` 属性
447
+ - 添加 `__MAGIC_MODULE_ID` 标识
448
+
449
+ ---
450
+
451
+ ### DynamicValueBind()
452
+
453
+ 动态值绑定
454
+
455
+ ```typescript
456
+ DynamicValueBind(...elements: HTMLElement[], uiData: object): void
457
+ ```
458
+
459
+ **示例:**
460
+ ```javascript
461
+ magic.DynamicValueBind(textElement1, textElement2, uiData);
462
+ ```
463
+
464
+ ---
465
+
466
+ ## 编译时宏
467
+
468
+ ### magic_define_include()
469
+
470
+ 编译时宏,包含文件内容
471
+
472
+ ```typescript
473
+ magic_define_include(path: string): string
474
+ ```
475
+
476
+ **限制:** 参数必须是静态字符串
477
+
478
+ ---
479
+
480
+ ### magic_define_ui_data()
481
+
482
+ 编译时宏,创建 UiData 对象
483
+
484
+ ```typescript
485
+ magic_define_ui_data(data: object): object
486
+ ```
487
+
488
+ **转换:** 编译时转换为 `magic.createUiData()` 调用
489
+
490
+ ---
491
+
492
+ ### magic_dynamic_value_bind()
493
+
494
+ 编译时宏,动态值绑定
495
+
496
+ ```typescript
497
+ magic_dynamic_value_bind(...nodes: HTMLElement[]): void
498
+ ```
499
+
500
+ **前置条件:** 必须先使用 `magic_define_ui_data` 创建 UiData 对象
501
+
502
+ **转换:** 编译时转换为 `magic.DynamicValueBind()` 调用
503
+
504
+ ---
505
+
506
+ ## Element 扩展
507
+
508
+ ### remove()
509
+
510
+ Magic 重写了 Element.prototype.remove,在移除元素前执行清理逻辑。
511
+
512
+ ```typescript
513
+ interface Element {
514
+ remove(): void;
515
+ }
516
+ ```
517
+
518
+ **行为:**
519
+ 1. 遍历所有子元素执行清理
520
+ 2. 调用原生 remove 方法
521
+
522
+ ---
523
+
524
+ ## 示例代码
525
+
526
+ ### 模块定义与使用
527
+
528
+ **模块 (button.m):**
529
+ ```xml
530
+ <template>
531
+ <button #id="btn">点击</button>
532
+ </template>
533
+
534
+ <script code="global">
535
+ const { $btn } = $id();
536
+ </script>
537
+
538
+ <script code="event">
539
+ click = () => {
540
+ emit_event("click", { time: Date.now() });
541
+ }
542
+ </script>
543
+
544
+ <script code="interface">
545
+ setText = (text) => {
546
+ $btn.textContent = text;
547
+ };
548
+ </script>
549
+
550
+ <expose-event>
551
+ <click/>
552
+ </expose-event>
553
+ ```
554
+
555
+ **使用:**
556
+ ```javascript
557
+ const btn = magic.importM("button");
558
+ btn.interface.setText("新文本");
559
+
560
+ const btn2 = magic.importM("button", {}, {
561
+ click: (data) => console.log("Clicked at:", data.time)
562
+ });
563
+ ```