labull-framework 0.1.23 → 0.1.24
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/dist/magic-block.js +1279 -1203
- package/dist/style.css +1 -1
- package/dist/types/magic-block-localfs.d.ts +43 -2
- package/dist/types/magic-block-manifest.d.ts +10 -3
- package/dist/types/magic-block-real.d.ts +1 -1
- package/package.json +1 -1
|
@@ -64,8 +64,27 @@ export interface WriteFailure {
|
|
|
64
64
|
export interface WriteResult {
|
|
65
65
|
written: number;
|
|
66
66
|
failed: WriteFailure[];
|
|
67
|
-
/** 一共排了几个文件(= `written + failed.length`,进度条的分母)。 */
|
|
67
|
+
/** 一共排了几个文件(= `written + skipped + failed.length`,进度条的分母)。 */
|
|
68
68
|
total: number;
|
|
69
|
+
/** 盘上那份与要写的那份**一模一样**、因此一下都没动的文件数(`verify` 打开时才有)。 */
|
|
70
|
+
skipped: number;
|
|
71
|
+
}
|
|
72
|
+
/** `writePackage` 的开关。 */
|
|
73
|
+
export interface WriteOptions {
|
|
74
|
+
/**
|
|
75
|
+
* 写之前**先读一眼**:盘上那份与要写的一模一样就**不写**(`skipped` 计数)。
|
|
76
|
+
*
|
|
77
|
+
* 🔴 这是"重复导出"那个闭环里最划算的一件事,而且**不改任何语义**:正文一字不差时
|
|
78
|
+
* "写"与"不写"落盘的字节完全相同(只是 mtime 不动)。实测(真实开发包 136 个文件):
|
|
79
|
+
* 全写 205 ms → 全跳过 53 ms;改 3 个文件后再导 70 ms。
|
|
80
|
+
* 🔴 **为什么值得**:`createWritable()` 不是"就地改几个字节"——浏览器要**另写一份临时文件再原子改名**,
|
|
81
|
+
* 所以一次写的代价远大于一次读。一个块的代码改一行,没必要把另外 135 个文件重写一遍。
|
|
82
|
+
* 🔴 **代价**:多一次 `getFileHandle`(+ 命中时一次 `getFile().text()`)。读不到(没这个文件)
|
|
83
|
+
* 就退回"照写",所以**空目录上开着它也不亏**(实测 68 ms → 62 ms,在噪声里)。
|
|
84
|
+
* ⚠️ 读得到、比不了(不是文本 / 权限不对)也算"不比" ⇒ 照写:那种情况本来就该由写那一步报错。
|
|
85
|
+
* ⚠️ 刚 `clearChildren()` 过的目录可以传 `false`:那里**一个文件都不存在**,读那一趟纯属白问。
|
|
86
|
+
*/
|
|
87
|
+
verify?: boolean;
|
|
69
88
|
}
|
|
70
89
|
/**
|
|
71
90
|
* 把一整个开发包写进用户选的目录(`{相对路径: 正文}`)。
|
|
@@ -74,11 +93,13 @@ export interface WriteResult {
|
|
|
74
93
|
* 这个函数自己**不删任何东西**(`clearChildren()` 才是删那一步),它只管写。
|
|
75
94
|
* 🔴 **并发写 + 目录句柄缓存**:原来是一个文件一个文件地等、每个文件都从根重新走一遍目录,
|
|
76
95
|
* 几十个文件(含 540 KB 的主题那份)要串行好几趟目录树。
|
|
96
|
+
* ⚠️ 实测(真实开发包 136 个文件)并发 8 / 16 / 32 **一样快**:浏览器那一侧本来就是一件件做的,
|
|
97
|
+
* 把口子开更大不解决问题 —— 真正省时间的是"**不写**"(见 `WriteOptions.verify`)。
|
|
77
98
|
* 🔴 **一个文件写失败不许把整批吞掉**:失败收进 `failed` 回给调用方(这一层的判据与后端
|
|
78
99
|
* `export.write_dir` 一致 —— "一个块失败只报它自己"),调用方把它们显示出来。
|
|
79
100
|
* 原来是一抛全停:排在前面的文件已经落盘了,用户却只看到一句"失败",不知道铺了多少。
|
|
80
101
|
*/
|
|
81
|
-
export declare function writePackage(dir: LocalDir, files: Record<string, string>, onProgress?: (done: number, total: number) => void): Promise<WriteResult>;
|
|
102
|
+
export declare function writePackage(dir: LocalDir, files: Record<string, string>, onProgress?: (done: number, total: number) => void, options?: WriteOptions): Promise<WriteResult>;
|
|
82
103
|
/** 选中目录里都有什么(顶层项 + 递归数出来的文件 / 目录数)—— 导出前"要不要清空"那个确认框用。 */
|
|
83
104
|
export interface DirInventory {
|
|
84
105
|
/** 顶层项(名字 + 是不是目录)。 */
|
|
@@ -114,6 +135,26 @@ export declare function inspectDirectory(dir: LocalDir, rules: ScanRules): Promi
|
|
|
114
135
|
* ⚠️ 一个删不掉就照原样抛(**与串行一样**):已经删掉的那些留在那儿,"删了几项"由调用方自己看到。
|
|
115
136
|
*/
|
|
116
137
|
export declare function clearChildren(dir: LocalDir): Promise<number>;
|
|
138
|
+
/**
|
|
139
|
+
* **只删"这一包不要的东西"**(导出时那个「清空」用的扫帚)。
|
|
140
|
+
*
|
|
141
|
+
* 🔴 它与 `clearChildren()` 的**结果一样**:铺完之后目录里正好只剩这一包。但过程省得多 ——
|
|
142
|
+
* 包里那些**盘上已有**的文件原地留着(读一眼、一样就不动,见 `WriteOptions.verify`),
|
|
143
|
+
* 只删包里**没有**的东西(上一趟留下的垃圾、用户自己放进去的文件)。
|
|
144
|
+
* 🔴 **为什么值得**:`createWritable()` 不是就地改几个字节(浏览器要另写一份临时文件再原子改名),
|
|
145
|
+
* 所以"全删再全铺"里的每一次写都是白花;实测(真实开发包 136 个文件):
|
|
146
|
+
* 全删重铺 228 ms → 只删多余 + 复用没变的 79 ms。
|
|
147
|
+
* 🔴 **只删 `dir` 里面的东西**(与 `clearChildren` 同一条边界),而"要留哪些"由**这一包自己**
|
|
148
|
+
* 算出来(`files` 的键逐级拼成集合)—— 不是从盘上读到什么再拼一次路径,所以"删到别处去"
|
|
149
|
+
* 在实现上就不可能。
|
|
150
|
+
* 🔴 **形状冲突也顺手清掉**:盘上那个位置是**目录**而包里要的是文件(或反过来)⇒ 它不在
|
|
151
|
+
* "这一包要的文件 / 目录"集合里,于是被删掉,紧接着由写那一步按正确的形状建出来。
|
|
152
|
+
* (这是"全删再铺"顺带保证的一件事,这里必须显式保住:否则同名目录会让那一次写直接失败。)
|
|
153
|
+
*
|
|
154
|
+
* :return: 删掉的**条目数**(每层各算一个;被整棵删掉的目录算它自己那一个 —— 与
|
|
155
|
+
* `clearChildren` 报的"几项"同一个口径)。
|
|
156
|
+
*/
|
|
157
|
+
export declare function pruneTo(dir: LocalDir, files: Record<string, string>): Promise<number>;
|
|
117
158
|
/**
|
|
118
159
|
* 选中的目录**本身**就是代码那一层时当场说清(`workspace/workspace/…` 是没人想要的)。
|
|
119
160
|
*
|
|
@@ -2,8 +2,15 @@
|
|
|
2
2
|
export declare const BLOCK_ENTRY = "index.open.html";
|
|
3
3
|
/** 块包清单(必备件)。与后端 `sdk.BLOCK_MANIFEST` 逐字一致。 */
|
|
4
4
|
export declare const BLOCK_MANIFEST = "magic-block.open.yaml";
|
|
5
|
-
/**
|
|
6
|
-
export declare const MANIFEST_KEYS: readonly ["id", "module", "name", "brief"];
|
|
5
|
+
/** 清单认得的键(顺序就是文档里的顺序)。🔴 `detail` 是**可选**的第五个键。 */
|
|
6
|
+
export declare const MANIFEST_KEYS: readonly ["id", "module", "name", "brief", "detail"];
|
|
7
|
+
/** 必须写全的那四个键(= `MANIFEST_KEYS` 去掉可选的 `detail`)。
|
|
8
|
+
*
|
|
9
|
+
* 🔴 为什么 `detail` **不进必填这一档**:它是给人读的详情介绍(一段话,比 `brief` 那句长),
|
|
10
|
+
* 存量块的清单里一个都没有 —— 判"缺少 detail"等于让库里每一个块在保存 / 体检时集体判不合格。
|
|
11
|
+
* 🔴 认得的键与必填的键**必须分开两处**:合成一处的话,报文会把可选键说成必填。
|
|
12
|
+
* 与后端 `validate.MANIFEST_REQUIRED` 逐字对齐。 */
|
|
13
|
+
export declare const MANIFEST_REQUIRED: readonly ["id", "module", "name", "brief"];
|
|
7
14
|
export type ManifestKey = (typeof MANIFEST_KEYS)[number];
|
|
8
15
|
/** 可读名的字符上限(与后端 `NAME_MAX` 同一份)。 */
|
|
9
16
|
export declare const NAME_MAX = 40;
|
|
@@ -15,7 +22,7 @@ export declare function validName(value: string): boolean;
|
|
|
15
22
|
export type Manifest = Partial<Record<ManifestKey, string>>;
|
|
16
23
|
/** 一个块包的校验结果。`files` 是提交时**原样回给后端**的那一份,这里只读不写。 */
|
|
17
24
|
export interface BlockValidation {
|
|
18
|
-
/**
|
|
25
|
+
/** 清单里读出来的键(没读全就是空对象)。 */
|
|
19
26
|
manifest: Manifest;
|
|
20
27
|
/** 逐条问题,中文、可直接显示给用户。 */
|
|
21
28
|
issues: string[];
|
|
@@ -3,6 +3,6 @@ export { default as MagicBlockConsole } from './magic-block-MagicBlockConsole.vu
|
|
|
3
3
|
export { loadBlockRender, onBlockRenderRefresh, refreshBlockRender, type BlockRender } from './magic-block-render';
|
|
4
4
|
export { BLOCK_BACKEND_FILE, BLOCK_ENTRY, buildPreview } from './magic-block-preview';
|
|
5
5
|
export { CLIENT_SOURCE, installBridge, type BridgeDeps } from './magic-block-bridge';
|
|
6
|
-
export { BLOCK_MANIFEST, MANIFEST_KEYS, NAME_MAX, checkSelection, parseManifest, validFileName, validName, validateBlock, type BlockValidation, type Manifest, type ManifestKey, type SelectionCheck, } from './magic-block-manifest';
|
|
6
|
+
export { BLOCK_MANIFEST, MANIFEST_KEYS, MANIFEST_REQUIRED, NAME_MAX, checkSelection, parseManifest, validFileName, validName, validateBlock, type BlockValidation, type Manifest, type ManifestKey, type SelectionCheck, } from './magic-block-manifest';
|
|
7
7
|
export { API_BASE } from './auth-real';
|
|
8
8
|
export { declaredMissing, declaredUuidOf, declaredUuidsOf, type DeclaredEntry, type DeclaredRoute, } from './magic-block-declared';
|