@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,582 @@
1
+ # Magic 开发规范
2
+
3
+ ## 目录
4
+
5
+ 1. [编码标准](#1-编码标准)
6
+ 2. [命名约定](#2-命名约定)
7
+ 3. [文件组织](#3-文件组织)
8
+ 4. [组件开发规范](#4-组件开发规范)
9
+ 5. [CSS 规范](#5-css-规范)
10
+ 6. [事件处理规范](#6-事件处理规范)
11
+ 7. [接口设计规范](#7-接口设计规范)
12
+ 8. [文档规范](#8-文档规范)
13
+
14
+ ---
15
+
16
+ ## 1. 编码标准
17
+
18
+ ### 1.1 基本原则
19
+
20
+ - 使用 UTF-8 编码
21
+ - 使用 Tab 缩进(2-4 个 Tab)
22
+ - 每行不超过 120 个字符
23
+ - 关键字后加空格:`if (condition)`
24
+ - 函数调用不加空格:`func(arg)`
25
+
26
+ ### 1.2 字符串
27
+
28
+ - 优先使用单引号
29
+ - 模板字符串用于多行或变量插值
30
+
31
+ ```javascript
32
+ // 推荐
33
+ const name = 'Magic';
34
+ const message = `Hello, ${name}!`;
35
+
36
+ // 避免
37
+ const name = "Magic";
38
+ ```
39
+
40
+ ### 1.3 变量声明
41
+
42
+ - 使用 `const` 优先于 `let`
43
+ - 避免使用 `var`
44
+ - 命名清晰的变量名
45
+
46
+ ```javascript
47
+ // 推荐
48
+ const maxRetries = 3;
49
+ const userList = [];
50
+
51
+ // 避免
52
+ const a = 3;
53
+ const list = [];
54
+ ```
55
+
56
+ ### 1.4 函数
57
+
58
+ ```javascript
59
+ // 箭头函数
60
+ const add = (a, b) => a + b;
61
+
62
+ // 普通函数
63
+ function multiply(a, b) {
64
+ return a * b;
65
+ }
66
+
67
+ // 异步函数
68
+ async function fetchData(url) {
69
+ const response = await fetch(url);
70
+ return response.json();
71
+ }
72
+ ```
73
+
74
+ ### 1.5 对象和数组
75
+
76
+ ```javascript
77
+ // 对象
78
+ const config = {
79
+ name: 'my-app',
80
+ version: '1.0.0',
81
+ getData() {
82
+ return this.name;
83
+ }
84
+ };
85
+
86
+ // 数组
87
+ const items = [1, 2, 3];
88
+ const newItems = items.map(item => item * 2);
89
+ ```
90
+
91
+ ---
92
+
93
+ ## 2. 命名约定
94
+
95
+ ### 2.1 文件命名
96
+
97
+ | 类型 | 规范 | 示例 |
98
+ |------|------|------|
99
+ | .m 组件 | kebab-case | `greeting-card.m`, `user-profile.m` |
100
+ | JavaScript | camelCase | `util.js`, `api-handler.js` |
101
+ | CSS | kebab-case | `theme.css`, `button-styles.css` |
102
+ | 图片 | kebab-case | `logo-small.png`, `bg-pattern.jpg` |
103
+
104
+ ### 2.2 元素 ID 命名
105
+
106
+ ```xml
107
+ <!-- 推荐:描述性名称 -->
108
+ <div #id="header-container">...</div>
109
+ <div #id="user-name-label">...</div>
110
+
111
+ <!-- 避免:无意义名称 -->
112
+ <div #id="div1">...</div>
113
+ <div #id="d1">...</div>
114
+ ```
115
+
116
+ **命名模式:**
117
+ - `$id="元素类型-功能"` 如 `$id="main-content"`
118
+ - `$id="元素类型-序号"` 如 `$id="list-item-1"`
119
+
120
+ ### 2.3 变量命名
121
+
122
+ | 类型 | 规范 | 示例 |
123
+ |------|------|------|
124
+ | 普通变量 | camelCase | `userName`, `isValid` |
125
+ | 常量 | UPPER_SNAKE | `MAX_COUNT`, `API_URL` |
126
+ | 布尔值 | is/has/can 前缀 | `isVisible`, `hasChildren` |
127
+ | 数组 | 复数名词 | `users`, `itemList` |
128
+ | DOM 元素 | `$` 前缀 | `$button`, `$container` |
129
+
130
+ ### 2.4 函数命名
131
+
132
+ | 类型 | 规范 | 示例 |
133
+ |------|------|------|
134
+ | 事件处理 | `on` + 事件名 | `onClick`, `onChange` |
135
+ | 事件定义 | 动词 | `handleClick`, `processSubmit` |
136
+ | 回调 | `callback` | `onCompleteCallback` |
137
+ | 获取数据 | `get` + 名词 | `getUserData`, `fetchConfig` |
138
+ | 设置数据 | `set` + 名词 | `setUserName`, `updateConfig` |
139
+ | 判断 | `is`/`has`/`can` + 名词 | `isValid`, `hasPermission` |
140
+
141
+ ### 2.5 CSS 类名
142
+
143
+ ```css
144
+ /* BEM 风格 */
145
+ .button { }
146
+ .button__icon { }
147
+ .button--disabled { }
148
+
149
+ /* 组件作用域 */
150
+ .m-css-scope-xxx { }
151
+ ```
152
+
153
+ ---
154
+
155
+ ## 3. 文件组织
156
+
157
+ ### 3.1 目录结构
158
+
159
+ ```
160
+ app/
161
+ ├── app.xml # 应用配置(必需)
162
+ ├── index.m # 入口模块(必需)
163
+ ├── components/ # 可复用组件
164
+ │ ├── button/
165
+ │ │ └── button.m
166
+ │ ├── dialog/
167
+ │ │ └── dialog.m
168
+ │ └── card/
169
+ │ └── card.m
170
+ ├── pages/ # 页面组件
171
+ │ ├── home/
172
+ │ │ └── index.m
173
+ │ └── about/
174
+ │ └── index.m
175
+ ├── layouts/ # 布局组件
176
+ │ └── main-layout.m
177
+ ├── shared/ # 共享模块
178
+ │ ├── header.m
179
+ │ └── footer.m
180
+ └── assets/ # 静态资源
181
+ ├── images/
182
+ ├── fonts/
183
+ └── data/
184
+ ```
185
+
186
+ ### 3.2 导入组织
187
+
188
+ ```xml
189
+ <!-- 1. 导入外部库(如有) -->
190
+ <!-- 2. 导入共享组件 -->
191
+ <!-- 3. 导入页面组件 -->
192
+
193
+ <import root=".">
194
+ <!-- 共享组件 -->
195
+ <header/>
196
+ <footer/>
197
+
198
+ <!-- 页面组件 -->
199
+ <home/>
200
+ </import>
201
+ ```
202
+
203
+ ---
204
+
205
+ ## 4. 组件开发规范
206
+
207
+ ### 4.1 .m 文件结构顺序
208
+
209
+ ```xml
210
+ <import> <!-- 1. 导入(可选) -->
211
+ <template> <!-- 2. 模板(必需) -->
212
+ <script code=""> <!-- 3. 脚本(可选,多个) -->
213
+ <css> <!-- 4. 样式(可选,多个) -->
214
+ <expose-event> <!-- 5. 事件暴露(可选) -->
215
+ ```
216
+
217
+ ### 4.2 模板规范
218
+
219
+ ```xml
220
+ <template>
221
+ <!-- 根元素必须有 #id -->
222
+ <div #id="组件根元素">
223
+ <!-- 子元素使用有意义的 #id -->
224
+ <header #id="组件头部">
225
+ <h1 #id="标题">Title</h1>
226
+ </header>
227
+ <main #id="内容区域">
228
+ <!-- 组件内容 -->
229
+ </main>
230
+ <footer #id="组件底部">
231
+ </footer>
232
+ </div>
233
+ </template>
234
+ ```
235
+
236
+ ### 4.3 脚本规范
237
+
238
+ #### 全局脚本 (code="global")
239
+
240
+ ```xml
241
+ <script code="global">
242
+ // 1. 获取元素
243
+ const {
244
+ $root,
245
+ $header,
246
+ $content
247
+ } = $id();
248
+
249
+ // 2. 定义组件状态
250
+ const state = {
251
+ isExpanded: false
252
+ };
253
+ </script>
254
+ ```
255
+
256
+ #### 事件脚本 (code="event")
257
+
258
+ ```xml
259
+ <script code="event">
260
+ // 事件处理函数定义
261
+ clickHandler = (event) => {
262
+ // 处理点击
263
+ }
264
+
265
+ submitForm = (data) => {
266
+ // 处理表单提交
267
+ }
268
+ </script>
269
+ ```
270
+
271
+ #### 接口脚本 (code="interface")
272
+
273
+ ```xml
274
+ <script code="interface">
275
+ // 对外暴露的方法
276
+ setTitle = (title) => {
277
+ $header.textContent = title;
278
+ };
279
+
280
+ getData = () => {
281
+ return state;
282
+ };
283
+ </script>
284
+ ```
285
+
286
+ ### 4.4 组件接口设计
287
+
288
+ ```xml
289
+ <!-- 组件 -->
290
+ <script code="interface">
291
+ // 数据设置
292
+ setData = (data) => {
293
+ // 设置组件数据
294
+ };
295
+
296
+ // 状态控制
297
+ enable = () => {};
298
+ disable = () => {};
299
+
300
+ // 事件触发
301
+ show = () => {};
302
+ hide = () => {};
303
+
304
+ // 数据获取
305
+ getValue = () => {};
306
+ </script>
307
+ ```
308
+
309
+ ---
310
+
311
+ ## 5. CSS 规范
312
+
313
+ ### 5.1 作用域使用
314
+
315
+ ```xml
316
+ <!-- 正确:使用 #id:xx 作用域 -->
317
+ <css scope="#id:my-component">
318
+ & {
319
+ /* 组件样式 */
320
+ }
321
+ </css>
322
+ ```
323
+
324
+ ### 5.2 样式分离
325
+
326
+ ```xml
327
+ <!-- 主题样式(带 default-theme) -->
328
+ <css scope="#id:button" default-theme>
329
+ & {
330
+ background-color: #007bff;
331
+ color: #ffffff;
332
+ }
333
+ </css>
334
+
335
+ <!-- 布局样式 -->
336
+ <css scope="#id:button">
337
+ & {
338
+ display: inline-flex;
339
+ padding: 8px 16px;
340
+ border-radius: 4px;
341
+ }
342
+ </css>
343
+ ```
344
+
345
+ ### 5.3 嵌套规则
346
+
347
+ ```xml
348
+ <css scope="#id:card">
349
+ & {
350
+ /* 根样式 */
351
+ }
352
+ & > .header {
353
+ /* 直接子元素 */
354
+ }
355
+ & .content {
356
+ /* 后代元素 */
357
+ }
358
+ &:hover {
359
+ /* 伪类 */
360
+ }
361
+ </css>
362
+ ```
363
+
364
+ ### 5.4 避免样式冲突
365
+
366
+ - 不使用全局样式
367
+ - 所有样式都在作用域内
368
+ - 使用 `#id:xx` 而非直接使用元素名
369
+
370
+ ```xml
371
+ <!-- 避免 -->
372
+ <css>
373
+ div { color: red; }
374
+ </css>
375
+
376
+ <!-- 推荐 -->
377
+ <css scope="#id:container">
378
+ & div { color: red; }
379
+ </css>
380
+ ```
381
+
382
+ ---
383
+
384
+ ## 6. 事件处理规范
385
+
386
+ ### 6.1 事件命名
387
+
388
+ 使用小驼峰命名:
389
+
390
+ | 事件 | 说明 |
391
+ |------|------|
392
+ | `click` | 点击 |
393
+ | `change` | 值改变 |
394
+ | `select` | 选中 |
395
+ | `open` | 打开 |
396
+ | `close` | 关闭 |
397
+ | `submit` | 提交 |
398
+ | `cancel` | 取消 |
399
+
400
+ ### 6.2 expose-event 定义
401
+
402
+ ```xml
403
+ <expose-event>
404
+ <!-- 基本事件 -->
405
+ <click/>
406
+ <change/>
407
+
408
+ <!-- 带参数事件 -->
409
+ <select :value/>
410
+ <action :type :data/>
411
+ </expose-event>
412
+ ```
413
+
414
+ ### 6.3 事件触发
415
+
416
+ ```xml
417
+ <script code="event">
418
+ click = (event) => {
419
+ emit_event("click", event);
420
+ }
421
+
422
+ select = (value) => {
423
+ emit_event("select", { value });
424
+ }
425
+ </script>
426
+ ```
427
+
428
+ ### 6.4 事件监听
429
+
430
+ ```xml
431
+ <template>
432
+ <!-- 监听子组件事件 -->
433
+ <my-component
434
+ #listen:click="onChildClick"
435
+ #listen:select="onChildSelect"
436
+ />
437
+ </template>
438
+
439
+ <script code="listen">
440
+ onChildClick = (event) => {
441
+ console.log("Child clicked:", event);
442
+ }
443
+
444
+ onChildSelect = (data) => {
445
+ console.log("Child selected:", data);
446
+ }
447
+ </script>
448
+ ```
449
+
450
+ ---
451
+
452
+ ## 7. 接口设计规范
453
+
454
+ ### 7.1 接口命名
455
+
456
+ ```xml
457
+ <script code="interface">
458
+ // 设置方法
459
+ setData = (data) => {};
460
+ setTitle = (title) => {};
461
+ setOptions = (options) => {};
462
+
463
+ // 获取方法
464
+ getData = () => {};
465
+ getValue = () => {};
466
+
467
+ // 状态方法
468
+ show = () => {};
469
+ hide = () => {};
470
+ enable = () => {};
471
+ disable = () => {};
472
+
473
+ // 动作方法
474
+ refresh = () => {};
475
+ reset = () => {};
476
+ submit = () => {};
477
+ </script>
478
+ ```
479
+
480
+ ### 7.2 once 接口
481
+
482
+ `once` 标记的接口在模块初始化时只执行一次:
483
+
484
+ ```xml
485
+ <script code="interface" once>
486
+ initialize = () => {
487
+ // 只执行一次
488
+ };
489
+ </script>
490
+ ```
491
+
492
+ ### 7.3 接口参数设计
493
+
494
+ ```xml
495
+ <script code="interface">
496
+ // 简单参数
497
+ setTitle = (title) => {};
498
+
499
+ // 对象参数(推荐用于多参数)
500
+ setConfig = (config) => {
501
+ if (config.width) { /* ... */ }
502
+ if (config.height) { /* ... */ }
503
+ };
504
+
505
+ // 回调参数
506
+ load = (onComplete, onError) => {
507
+ // ...
508
+ };
509
+ </script>
510
+ ```
511
+
512
+ ---
513
+
514
+ ## 8. 文档规范
515
+
516
+ ### 8.1 .m 文件注释
517
+
518
+ ```xml
519
+ <!--
520
+ * Button 组件
521
+ * 用于触发操作
522
+ *
523
+ * @param {string} text - 按钮文本
524
+ * @param {boolean} disabled - 是否禁用
525
+ * @fires click
526
+ -->
527
+ <template>
528
+ <button #id="btn">按钮</button>
529
+ </template>
530
+ ```
531
+
532
+ ### 8.2 脚本注释
533
+
534
+ ```javascript
535
+ /**
536
+ * 处理按钮点击事件
537
+ * @param {Event} event - 原生事件对象
538
+ */
539
+ clickHandler = (event) => {
540
+ // ...
541
+ };
542
+ ```
543
+
544
+ ### 8.3 示例注释
545
+
546
+ ```xml
547
+ <!-- 示例:基本用法 -->
548
+ <!--
549
+ <import root=".">
550
+ <my-button/>
551
+ </import>
552
+
553
+ <script>
554
+ // 使用
555
+ const btn = magic.importM("my-button");
556
+ btn.interface.setText("点击我");
557
+ </script>
558
+ -->
559
+ ```
560
+
561
+ ---
562
+
563
+ ## 最佳实践总结
564
+
565
+ ### DO
566
+
567
+ 1. **使用有意义的命名**
568
+ 2. **保持组件职责单一**
569
+ 3. **合理拆分大型组件**
570
+ 4. **使用 `const` 避免意外修改**
571
+ 5. **事件处理函数抽离**
572
+ 6. **样式使用作用域隔离**
573
+ 7. **提供清晰的接口文档**
574
+
575
+ ### DON'T
576
+
577
+ 1. **避免全局变量污染**
578
+ 2. **避免巨型单一组件**
579
+ 3. **避免硬编码值**
580
+ 4. **避免样式冲突**
581
+ 5. **避免不必要的事件冒泡**
582
+ 6. **避免裸露的内部实现**