@longzai-intelligence-docs/compile-plugin 0.0.0-stage → 0.0.14

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.
@@ -0,0 +1,488 @@
1
+ import "./rolldown-runtime-BqT_7tdF.js";
2
+ import * as z from "zod";
3
+ //#region src/compile.plugin.d.ts
4
+ /**
5
+ * compile 内置插件
6
+ *
7
+ * 文档派生域的一方插件即 items 真源合成与工具面抽取与快照新鲜度校验,
8
+ * 契约承 ADR 0131,对外经 definePlugin 声明四命令,宿主经内置插件列表
9
+ * 装载,外部联邦装载同样可用
10
+ */
11
+ /**
12
+ * compile 内置插件定义
13
+ */
14
+ declare const compilePlugin: import("@longzai-intelligence-docs/core").DocsPlugin;
15
+ //#endregion
16
+ //#region src/compile-config.schema.d.ts
17
+ /**
18
+ * compile 插件配置 schema 即整体缺省
19
+ */
20
+ declare const CompilePluginConfigSchema: z.ZodDefault<z.ZodObject<{
21
+ itemsRoot: z.ZodDefault<z.ZodString>;
22
+ surfaces: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
23
+ output: z.ZodString;
24
+ title: z.ZodOptional<z.ZodString>;
25
+ toolFace: z.ZodDefault<z.ZodBoolean>;
26
+ exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
27
+ }, z.core.$strip>>>;
28
+ toolFace: z.ZodDefault<z.ZodObject<{
29
+ bins: z.ZodOptional<z.ZodArray<z.ZodString>>;
30
+ invocations: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
31
+ }, z.core.$strip>>;
32
+ }, z.core.$strip>>;
33
+ /**
34
+ * compile 插件配置即解析后形态
35
+ */
36
+ type CompilePluginConfig = z.output<typeof CompilePluginConfigSchema>;
37
+ /**
38
+ * compile 插件配置书写形态
39
+ */
40
+ type CompilePluginConfigInput = z.input<typeof CompilePluginConfigSchema>;
41
+ /**
42
+ * 解析 compile 插件配置
43
+ *
44
+ * @param input - 宿主注入的 plugins.compile.options 节
45
+ * @returns 解析后配置,未书写时节为整体缺省
46
+ * @throws {@link Error} 配置违反 schema 时
47
+ */
48
+ declare const parseCompilePluginConfig: (input: unknown) => CompilePluginConfig;
49
+ //#endregion
50
+ //#region src/check/finding-types.d.ts
51
+ /**
52
+ * 校验与上报共用类型
53
+ */
54
+ /**
55
+ * compile 违规类别
56
+ */
57
+ type CompileFindingKind = 'snapshot-missing' | 'snapshot-stale' | 'anchor-missing' | 'command-not-found';
58
+ /**
59
+ * 单条 compile 违规
60
+ */
61
+ type CompileFinding = {
62
+ /**
63
+ * 违规类别
64
+ */
65
+ kind: CompileFindingKind;
66
+ /**
67
+ * 违规报文,含定位与处置指引
68
+ */
69
+ message: string;
70
+ };
71
+ //#endregion
72
+ //#region src/check/compile-check.core.d.ts
73
+ /**
74
+ * 执行 compile 校验
75
+ *
76
+ * @param root - 仓库根目录绝对路径
77
+ * @param config - 解析后的插件配置
78
+ * @returns 违规清单,空即全绿
79
+ * @throws {@link Error} 扫描或条目元信息非法时由建模上抛
80
+ */
81
+ declare const runCompileCheck: (root: string, config: CompilePluginConfig) => Promise<readonly CompileFinding[]>;
82
+ //#endregion
83
+ //#region src/scan/frontmatter.utils.d.ts
84
+ /**
85
+ * 条目元信息解析后形态
86
+ *
87
+ * 六键均未声明时对应字段为 `null`,零元数据条目完全正常
88
+ */
89
+ type ItemMeta = {
90
+ /**
91
+ * 稳定身份键,未声明时为 `null`
92
+ */
93
+ id: string | null;
94
+ /**
95
+ * 条目类型提示串,未声明时为 `null`
96
+ */
97
+ type: string | null;
98
+ /**
99
+ * 标题提示串,未声明时为 `null`
100
+ */
101
+ title: string | null;
102
+ /**
103
+ * 定序键,须为有限数值,未声明时为 `null`
104
+ */
105
+ order: number | null;
106
+ /**
107
+ * 锚定的源码文件路径即仓库根相对路径,未声明时为 `null`
108
+ */
109
+ anchor: string | null;
110
+ /**
111
+ * 锚定的命令定义名,未声明时为 `null`
112
+ */
113
+ command: string | null;
114
+ };
115
+ //#endregion
116
+ //#region src/scan/items-scan.core.d.ts
117
+ /**
118
+ * 面内产出条目
119
+ */
120
+ type SurfaceItem = {
121
+ /**
122
+ * 条目 base 相对路径,不含扩展名
123
+ */
124
+ baseRelPath: string;
125
+ /**
126
+ * 该面选用的源文件相对路径即 items 根内相对路径,含扩展名
127
+ */
128
+ chosenRelPath: string;
129
+ /**
130
+ * 选用文件解析出的元信息
131
+ */
132
+ meta: ItemMeta;
133
+ /**
134
+ * 正文,已去尾空白
135
+ */
136
+ body: string;
137
+ /**
138
+ * 定序键,未声明为 `null`
139
+ */
140
+ order: number | null;
141
+ };
142
+ //#endregion
143
+ //#region src/scan/manifest-scan.utils.d.ts
144
+ /**
145
+ * manifest 面扫描
146
+ *
147
+ * 读取仓库根 package.json 的清单四字段即 name 与 description 与 version 与
148
+ * bin,作为产物头部身份信息与工具面 bin 缺省来源
149
+ */
150
+ /**
151
+ * manifest 面形态
152
+ */
153
+ type ManifestFace = {
154
+ /**
155
+ * 包名
156
+ */
157
+ name: string | null;
158
+ /**
159
+ * 包描述
160
+ */
161
+ description: string | null;
162
+ /**
163
+ * 包版本
164
+ */
165
+ version: string | null;
166
+ /**
167
+ * bin 名集合,书写形态为单串时归一为单元素集合
168
+ */
169
+ bins: readonly string[];
170
+ };
171
+ //#endregion
172
+ //#region src/scan/tool-face-scan.core.d.ts
173
+ /**
174
+ * 工具面黑盒抽取
175
+ *
176
+ * 逐 bin 运行 `--help` 解析 commander 形态帮助文本为结构化命令清单,逐命令
177
+ * 再取细化帮助,非 commander 形态降级记录原文不中断,调用方式可经配置覆写
178
+ * 以覆盖 dist 未构建场景即以 `bun` 直跑源码入口
179
+ */
180
+ /**
181
+ * 工具面选项条目
182
+ */
183
+ type ToolFaceOption = {
184
+ /**
185
+ * 选项旗标原文,如 `--scope <key>`
186
+ */
187
+ flags: string;
188
+ /**
189
+ * 选项说明
190
+ */
191
+ description: string;
192
+ };
193
+ /**
194
+ * 工具面命令条目
195
+ */
196
+ type ToolFaceCommand = {
197
+ /**
198
+ * 命令名即首词
199
+ */
200
+ name: string;
201
+ /**
202
+ * 用法列原文,已去 ` [options]` 尾缀
203
+ */
204
+ invocation: string;
205
+ /**
206
+ * 顶层帮助中的命令说明
207
+ */
208
+ summary: string;
209
+ /**
210
+ * 细化帮助中的命令描述
211
+ */
212
+ detailDescription: string;
213
+ /**
214
+ * 细化帮助解析出的选项集合
215
+ */
216
+ options: readonly ToolFaceOption[];
217
+ /**
218
+ * 细化帮助是否解析成功
219
+ */
220
+ detailParsed: boolean;
221
+ };
222
+ /**
223
+ * 解析成功的工具面
224
+ */
225
+ type ParsedToolFace = {
226
+ /**
227
+ * bin 名
228
+ */
229
+ bin: string;
230
+ /**
231
+ * 降级标记,恒为 `false`
232
+ */
233
+ degraded: false;
234
+ /**
235
+ * 用法行原文
236
+ */
237
+ usage: string;
238
+ /**
239
+ * bin 级描述
240
+ */
241
+ description: string;
242
+ /**
243
+ * bin 级选项集合
244
+ */
245
+ options: readonly ToolFaceOption[];
246
+ /**
247
+ * 命令集合,保持帮助输出顺序
248
+ */
249
+ commands: readonly ToolFaceCommand[];
250
+ };
251
+ /**
252
+ * 降级工具面
253
+ */
254
+ type DegradedToolFace = {
255
+ /**
256
+ * bin 名
257
+ */
258
+ bin: string;
259
+ /**
260
+ * 降级标记,恒为 `true`
261
+ */
262
+ degraded: true;
263
+ /**
264
+ * 帮助输出原文
265
+ */
266
+ raw: string;
267
+ /**
268
+ * 降级原因
269
+ */
270
+ reason: string;
271
+ };
272
+ /**
273
+ * 工具面联合形态
274
+ */
275
+ type ToolFace = ParsedToolFace | DegradedToolFace;
276
+ /**
277
+ * 帮助文本解析出的命令条目
278
+ */
279
+ type HelpCommandEntry = {
280
+ /**
281
+ * 命令名即首词
282
+ */
283
+ name: string;
284
+ /**
285
+ * 用法列原文,已去 `[options]` 尾缀
286
+ */
287
+ invocation: string;
288
+ /**
289
+ * 命令说明
290
+ */
291
+ summary: string;
292
+ };
293
+ /**
294
+ * 帮助文本解析结果
295
+ */
296
+ type ParsedHelp = {
297
+ /**
298
+ * 用法行原文,非 commander 形态即 `null`
299
+ */
300
+ usage: string | null;
301
+ /**
302
+ * 用法行与首个区块之间的描述
303
+ */
304
+ description: string;
305
+ /**
306
+ * 选项条目集合
307
+ */
308
+ options: ToolFaceOption[];
309
+ /**
310
+ * 命令条目集合
311
+ */
312
+ commands: HelpCommandEntry[];
313
+ };
314
+ /**
315
+ * 解析 commander 形态帮助文本为选项与命令区块
316
+ *
317
+ * 判定口径为存在 `Usage:` 行,缺失即视为非 commander 形态,区块条目按两个
318
+ * 以上连续空白切分左列与右列,左列为命令或旗标、右列为说明,跨列折行的
319
+ * 说明尾行会落入左列,属已知精度边界,此类行以原样保留不丢弃
320
+ *
321
+ * @param text - 帮助输出全文
322
+ * @returns 解析出的用法行、bin 级描述、bin 级选项与命令清单
323
+ */
324
+ declare const parseCommanderHelp: (text: string) => ParsedHelp;
325
+ /**
326
+ * 全量工具面抽取入参
327
+ */
328
+ type ExtractToolFaceInput = {
329
+ /**
330
+ * bin 名集合
331
+ */
332
+ bins: readonly string[];
333
+ /**
334
+ * bin 名到调用方式的覆写映射
335
+ */
336
+ invocations: Readonly<Record<string, readonly string[]>>;
337
+ /**
338
+ * 工作目录绝对路径
339
+ */
340
+ root: string;
341
+ };
342
+ /**
343
+ * 抽取全部 bin 的工具面
344
+ *
345
+ * @param input - 抽取入参
346
+ * @returns 工具面集合,顺序与 bins 声明一致
347
+ */
348
+ declare const extractToolFace: (input: ExtractToolFaceInput) => Promise<readonly ToolFace[]>;
349
+ //#endregion
350
+ //#region src/model/compile-model.core.d.ts
351
+ /**
352
+ * 单个公开面的视图
353
+ */
354
+ type SurfaceView = {
355
+ /**
356
+ * 公开面名
357
+ */
358
+ surface: string;
359
+ /**
360
+ * 产物路径即仓库根相对路径
361
+ */
362
+ output: string;
363
+ /**
364
+ * 面标题,缺省为面名
365
+ */
366
+ title: string;
367
+ /**
368
+ * 是否追加工具面命令参考节
369
+ */
370
+ toolFace: boolean;
371
+ /**
372
+ * 该面产出条目即已定序已过滤
373
+ */
374
+ items: readonly SurfaceItem[];
375
+ };
376
+ /**
377
+ * 真源视图
378
+ */
379
+ type CompileSourceView = {
380
+ /**
381
+ * 仓库根目录绝对路径
382
+ */
383
+ root: string;
384
+ /**
385
+ * items 根的仓库根相对路径
386
+ */
387
+ itemsRootLabel: string;
388
+ /**
389
+ * manifest 面
390
+ */
391
+ manifest: ManifestFace;
392
+ /**
393
+ * 工具面集合
394
+ */
395
+ toolFace: readonly ToolFace[];
396
+ /**
397
+ * 各公开面视图
398
+ */
399
+ surfaces: readonly SurfaceView[];
400
+ };
401
+ /**
402
+ * 构建真源视图
403
+ *
404
+ * @param root - 仓库根目录绝对路径
405
+ * @param config - 解析后的插件配置
406
+ * @returns 真源视图
407
+ * @throws {@link Error} 任一面条目元信息非法时,报错携带条目定位
408
+ */
409
+ declare const buildSourceView: (root: string, config: CompilePluginConfig) => Promise<CompileSourceView>;
410
+ //#endregion
411
+ //#region src/compose/surface-composer.core.d.ts
412
+ /**
413
+ * 合成单个公开面产物
414
+ *
415
+ * @param view - 真源视图
416
+ * @param surfaceView - 该面视图
417
+ * @returns 产物 markdown 全文,恒以单个换行收尾
418
+ */
419
+ declare const composeSurface: (view: CompileSourceView, surfaceView: SurfaceView) => string;
420
+ /**
421
+ * 合成全部公开面产物
422
+ *
423
+ * @param view - 真源视图
424
+ * @returns 面名到产物路径与产物全文的集合
425
+ */
426
+ declare const composeAllSurfaces: (view: CompileSourceView) => readonly {
427
+ surface: string;
428
+ output: string;
429
+ markdown: string;
430
+ }[];
431
+ //#endregion
432
+ //#region src/compile.commands.d.ts
433
+ /**
434
+ * scan 结果形态
435
+ */
436
+ type CompileScanResult = {
437
+ /**
438
+ * manifest 面四字段
439
+ */
440
+ manifest: {
441
+ name: string | null;
442
+ description: string | null;
443
+ version: string | null;
444
+ bins: readonly string[];
445
+ };
446
+ /**
447
+ * 工具面集合
448
+ */
449
+ toolFace: readonly unknown[];
450
+ /**
451
+ * 各面条目清单
452
+ */
453
+ surfaces: readonly {
454
+ surface: string;
455
+ output: string;
456
+ items: readonly {
457
+ base: string;
458
+ source: string;
459
+ order: number | null;
460
+ metadata: readonly string[];
461
+ }[];
462
+ }[];
463
+ };
464
+ /**
465
+ * 执行 scan 即扫描真源面出清单
466
+ *
467
+ * @param root - 仓库根目录绝对路径
468
+ * @param config - 解析后的插件配置
469
+ * @returns scan 结果
470
+ * @throws {@link Error} 条目元信息非法时
471
+ */
472
+ declare const runCompileScan: (root: string, config: CompilePluginConfig) => Promise<CompileScanResult>;
473
+ /**
474
+ * 执行 derive 即建模派生并写盘
475
+ *
476
+ * @param root - 仓库根目录绝对路径
477
+ * @param config - 解析后的插件配置
478
+ * @param dryRun - 只打印不写盘
479
+ * @returns 写盘清单即面名与产物路径与条目数
480
+ * @throws {@link Error} 未配置公开面或条目元信息非法时
481
+ */
482
+ declare const runCompileDerive: (root: string, config: CompilePluginConfig, dryRun: boolean) => Promise<readonly {
483
+ surface: string;
484
+ output: string;
485
+ itemCount: number;
486
+ }[]>;
487
+ //#endregion
488
+ export { type CompilePluginConfig, type CompilePluginConfigInput, CompilePluginConfigSchema, type CompileSourceView, type SurfaceView, type ToolFace, buildSourceView, compilePlugin, composeAllSurfaces, composeSurface, extractToolFace, parseCommanderHelp, parseCompilePluginConfig, runCompileCheck, runCompileDerive, runCompileScan };
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ import"./rolldown-runtime-BqT_7tdF.js";import{IDENTIFIER_KEBAB_PATTERN as e,definePlugin as t,pluginCommand as n}from"@longzai-intelligence-docs/core";import*as r from"zod";import{mkdir as i,stat as a,writeFile as o}from"node:fs/promises";import{dirname as s,join as c}from"node:path";const l=`docs/items`,u=r.object({output:r.string().min(1).refine(e=>!e.startsWith(`/`),`产物路径须为仓库根相对路径`),title:r.string().min(1).optional(),toolFace:r.boolean().default(!1),exclude:r.array(r.string().min(1)).default([])}),d=r.object({bins:r.array(r.string().min(1)).optional(),invocations:r.record(r.string().min(1),r.array(r.string().min(1))).default({})}),f=r.object({itemsRoot:r.string().min(1).default(l),surfaces:r.record(r.string().regex(e),u).default({}),toolFace:d.default({invocations:{}})}).default({itemsRoot:l,surfaces:{},toolFace:{invocations:{}}}),p=e=>{let t=f.safeParse(e);if(!t.success)throw Error(`compile 插件配置非法:${t.error.issues.map(e=>`${e.path.join(`.`)||`根节`}——${e.message}`).join(`,`)}`);return t.data},ee=[`<!-- 本文件由 lzi-docs compile 派生维护,禁止手工编辑 -->`,`<!-- 真源为 items 条目与 lzi-docs.config.ts 的 plugins.compile 配置,变更后重新执行 compile-derive 重建 -->`],m=(e,t)=>`<!-- compile:source ${e}/${t} -->`,h=e=>e.replaceAll(`|`,`\\|`).replaceAll(`
2
+ `,` `),g=e=>e.length===0?``:[`| 选项 | 说明 |`,`| --- | --- |`,...e.map(e=>`| \`${h(e.flags)}\` | ${h(e.description)} |`)].join(`
3
+ `),_=e=>{if(e.degraded)return[`### ${e.bin}`,``,`该 bin 的帮助输出未呈可解析形态,以下为原文。`,``,"````",e.raw.trimEnd(),"````"].join(`
4
+ `);let t=[`### ${e.bin}`,``];e.description!==``&&t.push(e.description,``),t.push(`用法:\`${h(e.usage.replace(/^Usage:\s*/,``))}\``);let n=g(e.options);n!==``&&t.push(``,`**全局选项**`,``,n);for(let n of e.commands){let r=n.detailDescription===``?n.summary:n.detailDescription;t.push(``,`#### ${e.bin} ${n.name}`,``),r!==``&&t.push(r,``),t.push(`用法:\`${e.bin} ${h(n.invocation)}\``);let i=g(n.options);i!==``&&t.push(``,`**选项**`,``,i)}return t.join(`
5
+ `)},v=e=>[`## 命令参考`,``,"本节由工具面自 `--help` 输出抽取合成,源为 bin 帮助文案。",``,e.map(e=>_(e)).join(`
6
+
7
+ `)].join(`
8
+ `),y=(e,t)=>{let n=[...ee,``,`# ${t.title}`,``];for(let r of t.items)n.push(m(e.itemsRootLabel,r.chosenRelPath),r.body,``);return t.toolFace&&e.toolFace.length>0&&n.push(v(e.toolFace),``),`${n.join(`
9
+ `).trimEnd()}\n`},b=e=>e.surfaces.map(t=>({surface:t.surface,output:t.output,markdown:y(e,t)})),x=/* @__PURE__ */ new Set([`id`,`type`,`title`,`order`,`anchor`,`command`]),S={id:null,type:null,title:null,order:null,anchor:null,command:null},C=e=>{let t=e.split(`
10
+ `);if(t[0]?.trim()!==`---`)return{metaLines:[],body:e};let n=-1;for(let e=1;e<t.length;e+=1)if(t[e]?.trim()===`---`){n=e;break}return n===-1?{metaLines:[],body:e}:{metaLines:t.slice(1,n),body:t.slice(n+1).join(`
11
+ `)}},w=(e,t)=>{let n={...S},r=/* @__PURE__ */ new Set;for(let i of e){let e=i.trim();if(e===``)continue;let a=/^([^\s:]+):\s*(.*)$/.exec(e);if(a===null)throw Error(`条目 ${t} 的 frontmatter 存在无法解析的行 '${e}'`);let o=a[1]??``,s=(a[2]??``).trim();if(!x.has(o))throw Error(`条目 ${t} 的 frontmatter 含未知元数据键 '${o}',仅支持 id 与 type 与 title 与 order 与 anchor 与 command`);if(r.has(o))throw Error(`条目 ${t} 的 frontmatter 重复声明 ${o}`);if(r.add(o),s===``)throw Error(`条目 ${t} 的元数据键 ${o} 值为空`);if(o===`order`){let e=Number(s);if(!Number.isFinite(e))throw Error(`条目 ${t} 的 order 值 '${s}' 不是有限数值`);n.order=e}else(o===`id`||o===`type`||o===`title`||o===`anchor`||o===`command`)&&(n[o]=s)}return n},T=async e=>{try{return await a(e),!0}catch{return!1}},E=async e=>Bun.file(e).text(),D=(e,t)=>{let n=e.endsWith(`.md`)?e.slice(0,-3):e,r=n.lastIndexOf(`.`);if(r===-1)return{baseRelPath:n,surface:null};let i=n.slice(r+1);return t.includes(i)?{baseRelPath:n.slice(0,r),surface:i}:{baseRelPath:n,surface:null}},O=async e=>{let t=new Bun.Glob(`**/*.md`),n=[];for await(let r of t.scan({cwd:e,onlyFiles:!0}))n.push(r);return n.sort()},k=async(e,t)=>{let n=/* @__PURE__ */ new Map;if(!await T(e))return n;let r=await O(e);for(let e of r){let{baseRelPath:r,surface:i}=D(e,t);n.has(r)||n.set(r,{common:null,variants:/* @__PURE__ */ new Map});let a=n.get(r);a!==void 0&&(i===null?a.common===null&&(a.common=e):a.variants.has(i)||a.variants.set(i,e))}return n},A=(e,t)=>{let n=e.order??1/0,r=t.order??1/0;return n===r?e.baseRelPath===t.baseRelPath?0:e.baseRelPath<t.baseRelPath?-1:1:n-r},j=(e,t)=>`${e}/${t}`,M=async e=>{let t=await k(e.itemsRoot,e.surfaceNames),n=[],r=e.exclude.map(e=>new Bun.Glob(e));for(let[i,a]of t){if(r.some(e=>e.match(i)))continue;let t=a.variants.get(e.surface)??null,o=t??a.common;if(o===null)continue;let s=await E(c(e.itemsRoot,o)),{metaLines:l,body:u}=C(s),d=w(l,j(e.itemsRootLabel,o)),f=d.order;if(t!==null&&a.common!==null){if(d.order!==null)throw Error(`条目 ${j(e.itemsRootLabel,i+`.md`)} 的变体 ${t} 不得声明 order,条目定位由共同版唯一决定`);let n=await E(c(e.itemsRoot,a.common)),{metaLines:r}=C(n);f=w(r,j(e.itemsRootLabel,a.common)).order}u.trim()!==``&&n.push({baseRelPath:i,chosenRelPath:o,meta:d,body:u.trimEnd(),order:f})}return n.sort(A)},N=e=>typeof e==`object`&&!!e,P=async e=>{let t={name:null,description:null,version:null,bins:[]};try{let n=await Bun.file(`${e}/package.json`).json();if(!N(n))return t;typeof n.name==`string`&&(t.name=n.name),typeof n.description==`string`&&(t.description=n.description),typeof n.version==`string`&&(t.version=n.version);let r=n.bin;typeof r==`string`?t.bins=[r]:N(r)&&(t.bins=Object.keys(r))}catch{return t}return t},F=[{name:`options`,pattern:/^Options:\s*$/},{name:`commands`,pattern:/^Commands:\s*$/}],I=/^\s+\S/,L=e=>{let t=e.split(`
12
+ `),n=t.findIndex(e=>e.startsWith(`Usage:`));if(n===-1)return{usage:null,description:``,options:[],commands:[]};let r=/* @__PURE__ */ new Map;for(let e=0;e<t.length;e+=1)for(let n of F)n.pattern.test(t[e]??``)&&(r.has(n.name)||r.set(n.name,e));let i=r.size===0?t.length:Math.min(...r.values()),a=t.slice(n+1,i).filter(e=>e.trim()!==``),o=e=>{let n=r.get(e);if(n===void 0)return[];let i=[];for(let e=n+1;e<t.length;e+=1){let n=t[e]??``;if(I.test(n))i.push(n);else if(n.trim()!==``)break}return i},s=e=>{let t=e.trim().split(/\s{2,}/);return{left:t[0]??``,right:t.slice(1).join(` `)}},c=o(`options`).map(e=>{let{left:t,right:n}=s(e);return{flags:t,description:n}}),l=o(`commands`).map(e=>{let{left:t,right:n}=s(e);return{name:t.split(/\s+/)[0]??``,invocation:t.replace(/\s*\[options\]/g,``).trim(),summary:n}});return{usage:(t[n]??``).trim(),description:a.join(`
13
+ `),options:c,commands:l}},R=async(e,t)=>{try{let n=Bun.spawn({cmd:[...e],cwd:t,stdout:`pipe`,stderr:`pipe`});return{exitCode:await n.exited,stdout:await new Response(n.stdout).text(),stderr:await new Response(n.stderr).text()}}catch(e){return{exitCode:null,stdout:``,stderr:e instanceof Error?e.message:String(e)}}},z=async e=>{let t=await R([...e.invocation,`--help`],e.root),n=t.stdout===``?t.stderr:t.stdout;if(t.exitCode!==0)return{bin:e.bin,degraded:!0,raw:n,reason:`运行退出码 ${String(t.exitCode)}`};let r=L(n);if(r.usage===null)return{bin:e.bin,degraded:!0,raw:n,reason:`帮助输出未含 Usage 行即非 commander 形态`};let i=[];for(let t of r.commands){let n=await R([...e.invocation,t.name,`--help`],e.root),r=n.stdout===``?n.stderr:n.stdout,a=n.exitCode===0?L(r):null;i.push({name:t.name,invocation:t.invocation,summary:t.summary,detailDescription:a?.description??``,options:a?.options??[],detailParsed:a!==null&&a.usage!==null})}return{bin:e.bin,degraded:!1,usage:r.usage,description:r.description,options:r.options,commands:i}},B=async e=>{let t=[];for(let n of e.bins)t.push(await z({bin:n,invocation:e.invocations[n]??[n],root:e.root}));return t},V=async(e,t)=>{let n=await P(e),r=Object.keys(t.surfaces),i=t.toolFace.bins??n.bins,a=i.length>0?await B({bins:i,invocations:t.toolFace.invocations,root:e}):[],o=[];for(let[n,i]of Object.entries(t.surfaces)){let a=await M({itemsRoot:c(e,t.itemsRoot),itemsRootLabel:t.itemsRoot,surface:n,surfaceNames:r,exclude:i.exclude});o.push({surface:n,output:i.output,title:i.title??n,toolFace:i.toolFace,items:a})}return{root:e,itemsRootLabel:t.itemsRoot,manifest:n,toolFace:a,surfaces:o}},H=e=>{let t=e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);return[RegExp(`name\\s*[:=]\\s*(['"\`])${t}\\1`),RegExp(`\\.command\\(\\s*(['"\`])${t}\\1`)]},U=async e=>{let t=[];for(let n of e.surfaces)for(let r of n.items){let n=`${e.itemsRootLabel}/${r.chosenRelPath}`;if(r.meta.anchor===null&&r.meta.command===null)continue;if(r.meta.anchor===null){t.push({kind:`anchor-missing`,message:`条目 ${n} 声明了 command 而无 anchor,命令锚定需要 anchor 指向命令定义所在源码文件`});continue}let i=c(e.root,r.meta.anchor);if(!await Bun.file(i).exists()){t.push({kind:`anchor-missing`,message:`条目 ${n} 的 anchor 指向的文件不存在:${r.meta.anchor}`});continue}if(r.meta.command===null)continue;let a=await Bun.file(i).text();H(r.meta.command).some(e=>e.test(a))||t.push({kind:`command-not-found`,message:`条目 ${n} 的 command '${r.meta.command}' 在锚点源码 ${r.meta.anchor} 中未命中命令定义,命令可能已改名`})}return t},W=async(e,t)=>{let n=await V(e,t),r=b(n),i=/* @__PURE__ */ new Map;for(let t of r){let n=c(e,t.output);if(!await Bun.file(n).exists()){i.set(t.surface,{status:`missing`,expected:t.markdown});continue}let r=await Bun.file(n).text();i.set(t.surface,{status:r===t.markdown?`fresh`:`stale`,expected:t.markdown})}return i},G=async(e,t)=>{let n=await V(e,t),r=[...await U(n)];for(let t of b(n)){let n=c(e,t.output);await Bun.file(n).exists()?await Bun.file(n).text()!==t.markdown&&r.push({kind:`snapshot-stale`,message:`公开面 ${t.surface} 的产物过期:${t.output} 与真源合成结果不一致,执行 compile-derive 重建`}):r.push({kind:`snapshot-missing`,message:`公开面 ${t.surface} 的产物缺失:${t.output},执行 compile-derive 生成`})}return r},K=async(e,t)=>{let n=await W(e.root,t),r=/* @__PURE__ */ new Set,i=0,a=0;for(let t of e.surfaces)for(let e of t.items)r.add(e.baseRelPath),i+=1,(e.meta.id!==null||e.meta.type!==null||e.meta.title!==null||e.meta.order!==null||e.meta.anchor!==null||e.meta.command!==null)&&(a+=1);return{repo:e.manifest.name??``,itemBases:r.size,metadataCoverage:i===0?1:a/i,surfaces:e.surfaces.map(e=>({surface:e.surface,output:e.output,itemCount:e.items.length,freshness:n.get(e.surface)?.status??`missing`})),toolFace:e.toolFace.map(e=>({bin:e.bin,degraded:e.degraded,commandCount:e.degraded?0:e.commands.length}))}},q=e=>e===`fresh`?`新鲜`:e===`stale`?`过期`:`缺失`,J=e=>{let t=e.surfaces.map(e=>`| ${e.surface} | \`${e.output}\` | ${e.itemCount} | ${q(e.freshness)} |`),n=e.toolFace.map(e=>`| \`${e.bin}\` | ${e.degraded?`是`:`否`} | ${e.commandCount} |`);return[`# compile inventory:${e.repo===``?`未识别包名`:e.repo}`,``,`- 条目 base 总数:${e.itemBases}`,`- 元数据覆盖率:${(e.metadataCoverage*100).toFixed(0)}%`,``,`## 公开面`,``,`| 面 | 产物 | 条目数 | 新鲜度 |`,`| --- | --- | --- | --- |`,...t.length>0?t:[`| 无 | 无 | 0 | 缺失 |`],``,`## 工具面`,``,`| bin | 降级 | 命令数 |`,`| --- | --- | --- |`,...n.length>0?n:[`| 无 | 是 | 0 |`],``].join(`
14
+ `)},Y=e=>Object.keys(e.surfaces).length===0,X=async(e,t)=>{let n=await V(e,t);return{manifest:n.manifest,toolFace:n.toolFace,surfaces:n.surfaces.map(e=>({surface:e.surface,output:e.output,items:e.items.map(e=>({base:e.baseRelPath,source:`${n.itemsRootLabel}/${e.chosenRelPath}`,order:e.order,metadata:[[`id`,e.meta.id],[`type`,e.meta.type],[`title`,e.meta.title],[`order`,e.meta.order],[`anchor`,e.meta.anchor],[`command`,e.meta.command]].filter(([,e])=>e!==null).map(([e])=>e)}))}))}},Z=async(e,t,n)=>{if(Y(t))throw Error(`plugins.compile.options 未配置任何公开面,请在 lzi-docs.config.ts 的 surfaces 节配置后重试`);let r=await V(e,t),a=b(r);for(let t of a)if(!n){let n=c(e,t.output);await i(s(n),{recursive:!0}),await o(n,t.markdown,`utf-8`)}return a.map(e=>({surface:e.surface,output:e.output,itemCount:r.surfaces.find(t=>t.surface===e.surface)?.items.length??0}))},Q=async(e,t)=>{if(Y(t))throw Error(`plugins.compile.options 未配置任何公开面,请在 lzi-docs.config.ts 的 surfaces 节配置后重试`);return{findings:await G(e,t),surfaceCount:Object.keys(t.surfaces).length}},te=async(e,t)=>{let n=await V(e,t),r=await K(n,t);return{markdown:J(r),data:r}},$=r.object({}),ne=r.object({dryRun:r.boolean().default(!1)}),re=r.object({}),ie=r.object({json:r.boolean().default(!1)}),ae=t({name:`compile`,version:`0.0.1`,configSchema:f,commands:[e=>oe(e),e=>se(e),e=>ce(e),e=>le(e)]});function oe(e){return n({name:`compile-scan`,description:`扫描真源面出清单:items 条目、manifest 面与工具面帮助抽取`,schema:$,action:async()=>{try{let t=await X(process.cwd(),p(e.pluginConfig));process.stdout.write(`${JSON.stringify(t,null,2)}\n`)}catch(e){process.stderr.write(`错误: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}})}function se(e){return n({name:`compile-derive`,description:`建模并派生公开面产物写盘,同输入逐字节相同输出`,options:[{flags:`--dry-run`,description:`只打印合成结果不写盘`}],schema:ne,action:async t=>{try{let n=await Z(process.cwd(),p(e.pluginConfig),t.dryRun);for(let e of n)process.stdout.write(`${t.dryRun?`预览`:`已写入`} ${e.output},公开面 ${e.surface},条目 ${e.itemCount}\n`)}catch(e){process.stderr.write(`错误: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}})}function ce(e){return n({name:`compile-check`,description:`只读校验:快照新鲜度逐字节比对与锚点命令定义命中`,schema:re,action:async()=>{try{let t=await Q(process.cwd(),p(e.pluginConfig));for(let e of t.findings)process.stderr.write(`[compile:${e.kind}] ${e.message}\n`);t.findings.length>0&&process.exit(1),process.stdout.write(`校验通过,公开面 ${t.surfaceCount} 面全绿\n`)}catch(e){process.stderr.write(`错误: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}})}function le(e){return n({name:`compile-report`,description:`单仓 inventory 上报:面计数、条目数、元数据覆盖率与产物新鲜度`,options:[{flags:`--json`,description:`以 JSON 形态输出`}],schema:ie,action:async t=>{try{let n=await te(process.cwd(),p(e.pluginConfig));process.stdout.write(`${t.json?JSON.stringify(n.data,null,2):n.markdown}\n`)}catch(e){process.stderr.write(`错误: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}})}export{f as CompilePluginConfigSchema,V as buildSourceView,ae as compilePlugin,b as composeAllSurfaces,y as composeSurface,B as extractToolFace,L as parseCommanderHelp,p as parseCompilePluginConfig,G as runCompileCheck,Z as runCompileDerive,X as runCompileScan};
@@ -0,0 +1 @@
1
+ import"node:module";export{};
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@longzai-intelligence-docs/compile-plugin",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.0.14",
4
+ "description": "Longzai Intelligence Docs compile 插件",
5
+ "keywords": [
6
+ "compile",
7
+ "docs",
8
+ "longzai-intelligence",
9
+ "plugin"
10
+ ],
11
+ "license": "UNLICENSED",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "scripts": {
25
+ "build": "lzi-builder",
26
+ "build:prod": "NODE_ENV=production bun run build",
27
+ "prepublishOnly": "bun run build:prod",
28
+ "typecheck": "bun run typecheck:app && bun run typecheck:node && bun run typecheck:test",
29
+ "typecheck:app": "lzi-tsgo typecheck tsconfig/app.json",
30
+ "typecheck:node": "lzi-tsgo typecheck tsconfig/node.json",
31
+ "typecheck:test": "lzi-tsgo typecheck tsconfig/test.json",
32
+ "lint": "oxlint && oxfmt --check",
33
+ "lint:fix": "oxlint --fix && oxfmt",
34
+ "test": "bun test",
35
+ "test:watch": "bun test --watch",
36
+ "test:coverage": "bun test --coverage",
37
+ "clean": "lzi-dev-cli clean"
38
+ },
39
+ "dependencies": {
40
+ "@longzai-intelligence-cli/core": "^0.0.11",
41
+ "@longzai-intelligence-docs/core": "0.0.14",
42
+ "zod": "^4.4.3"
43
+ },
44
+ "devDependencies": {
45
+ "@types/bun": "^1.3.14"
46
+ },
47
+ "packageManager": "bun@1.4.0"
48
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.