@longzai-intelligence-docs/compile-plugin 0.0.14 → 0.0.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.
- package/dist/index.d.ts +69 -45
- package/dist/index.js +11 -11
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ declare const compilePlugin: import("@longzai-intelligence-docs/core").DocsPlugi
|
|
|
18
18
|
* compile 插件配置 schema 即整体缺省
|
|
19
19
|
*/
|
|
20
20
|
declare const CompilePluginConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
sourceRoot: z.ZodDefault<z.ZodString>;
|
|
22
|
+
documents: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
23
23
|
output: z.ZodString;
|
|
24
24
|
title: z.ZodOptional<z.ZodString>;
|
|
25
25
|
toolFace: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -84,7 +84,7 @@ declare const runCompileCheck: (root: string, config: CompilePluginConfig) => Pr
|
|
|
84
84
|
/**
|
|
85
85
|
* 条目元信息解析后形态
|
|
86
86
|
*
|
|
87
|
-
*
|
|
87
|
+
* 五键均未声明时对应字段为 `null`,零元数据条目完全正常
|
|
88
88
|
*/
|
|
89
89
|
type ItemMeta = {
|
|
90
90
|
/**
|
|
@@ -99,10 +99,6 @@ type ItemMeta = {
|
|
|
99
99
|
* 标题提示串,未声明时为 `null`
|
|
100
100
|
*/
|
|
101
101
|
title: string | null;
|
|
102
|
-
/**
|
|
103
|
-
* 定序键,须为有限数值,未声明时为 `null`
|
|
104
|
-
*/
|
|
105
|
-
order: number | null;
|
|
106
102
|
/**
|
|
107
103
|
* 锚定的源码文件路径即仓库根相对路径,未声明时为 `null`
|
|
108
104
|
*/
|
|
@@ -115,30 +111,59 @@ type ItemMeta = {
|
|
|
115
111
|
//#endregion
|
|
116
112
|
//#region src/scan/items-scan.core.d.ts
|
|
117
113
|
/**
|
|
118
|
-
*
|
|
114
|
+
* 文档内产出条目
|
|
119
115
|
*/
|
|
120
|
-
type
|
|
116
|
+
type SourceItem = {
|
|
121
117
|
/**
|
|
122
|
-
*
|
|
118
|
+
* 条目文件名即文档目录内相对路径
|
|
123
119
|
*/
|
|
124
|
-
|
|
120
|
+
fileName: string;
|
|
125
121
|
/**
|
|
126
|
-
*
|
|
122
|
+
* 定序键即文件名数值前缀
|
|
127
123
|
*/
|
|
128
|
-
|
|
124
|
+
order: number;
|
|
129
125
|
/**
|
|
130
|
-
*
|
|
126
|
+
* 条目文件解析出的元信息
|
|
131
127
|
*/
|
|
132
128
|
meta: ItemMeta;
|
|
133
129
|
/**
|
|
134
130
|
* 正文,已去尾空白
|
|
135
131
|
*/
|
|
136
132
|
body: string;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* 文档条目解析入参
|
|
136
|
+
*/
|
|
137
|
+
type ResolveDocumentItemsInput = {
|
|
138
|
+
/**
|
|
139
|
+
* 文档目录绝对路径
|
|
140
|
+
*/
|
|
141
|
+
documentDir: string;
|
|
137
142
|
/**
|
|
138
|
-
*
|
|
143
|
+
* 文档目录名
|
|
139
144
|
*/
|
|
140
|
-
|
|
145
|
+
documentName: string;
|
|
146
|
+
/**
|
|
147
|
+
* 真源根的仓库根相对显示路径
|
|
148
|
+
*/
|
|
149
|
+
sourceRootLabel: string;
|
|
150
|
+
/**
|
|
151
|
+
* 该文档的排除 glob 集合
|
|
152
|
+
*/
|
|
153
|
+
exclude: readonly string[];
|
|
141
154
|
};
|
|
155
|
+
/**
|
|
156
|
+
* 解析单文档目录下全部产出条目
|
|
157
|
+
*
|
|
158
|
+
* 文件名数值前缀强制,无前缀即报错,同目录数值重复即报错,正文空白即剔除
|
|
159
|
+
* 暂存,exclude 以 glob 匹配条目文件名整串命中即整条目排除,产出按前缀数值
|
|
160
|
+
* 升序,文档目录不存在时返回空集即零条目文档为正常态
|
|
161
|
+
*
|
|
162
|
+
* @param input - 解析入参
|
|
163
|
+
* @returns 按前缀数值升序排列的产出条目列表
|
|
164
|
+
* @throws {@link Error} 条目文件名无数值前缀、前缀数值重复或元信息非法时
|
|
165
|
+
*/
|
|
166
|
+
declare const resolveDocumentItems: (input: ResolveDocumentItemsInput) => Promise<readonly SourceItem[]>;
|
|
142
167
|
//#endregion
|
|
143
168
|
//#region src/scan/manifest-scan.utils.d.ts
|
|
144
169
|
/**
|
|
@@ -349,19 +374,19 @@ declare const extractToolFace: (input: ExtractToolFaceInput) => Promise<readonly
|
|
|
349
374
|
//#endregion
|
|
350
375
|
//#region src/model/compile-model.core.d.ts
|
|
351
376
|
/**
|
|
352
|
-
*
|
|
377
|
+
* 单个文档的视图
|
|
353
378
|
*/
|
|
354
|
-
type
|
|
379
|
+
type DocumentView = {
|
|
355
380
|
/**
|
|
356
|
-
*
|
|
381
|
+
* 文档名即真源目录名,产物 basename 去 `.md`
|
|
357
382
|
*/
|
|
358
|
-
|
|
383
|
+
document: string;
|
|
359
384
|
/**
|
|
360
385
|
* 产物路径即仓库根相对路径
|
|
361
386
|
*/
|
|
362
387
|
output: string;
|
|
363
388
|
/**
|
|
364
|
-
*
|
|
389
|
+
* 文档标题,缺省为文档名
|
|
365
390
|
*/
|
|
366
391
|
title: string;
|
|
367
392
|
/**
|
|
@@ -369,9 +394,9 @@ type SurfaceView = {
|
|
|
369
394
|
*/
|
|
370
395
|
toolFace: boolean;
|
|
371
396
|
/**
|
|
372
|
-
*
|
|
397
|
+
* 该文档产出条目即已定序已过滤
|
|
373
398
|
*/
|
|
374
|
-
items: readonly
|
|
399
|
+
items: readonly SourceItem[];
|
|
375
400
|
};
|
|
376
401
|
/**
|
|
377
402
|
* 真源视图
|
|
@@ -382,9 +407,9 @@ type CompileSourceView = {
|
|
|
382
407
|
*/
|
|
383
408
|
root: string;
|
|
384
409
|
/**
|
|
385
|
-
*
|
|
410
|
+
* 真源根的仓库根相对路径
|
|
386
411
|
*/
|
|
387
|
-
|
|
412
|
+
sourceRootLabel: string;
|
|
388
413
|
/**
|
|
389
414
|
* manifest 面
|
|
390
415
|
*/
|
|
@@ -394,9 +419,9 @@ type CompileSourceView = {
|
|
|
394
419
|
*/
|
|
395
420
|
toolFace: readonly ToolFace[];
|
|
396
421
|
/**
|
|
397
|
-
*
|
|
422
|
+
* 各文档视图
|
|
398
423
|
*/
|
|
399
|
-
|
|
424
|
+
documents: readonly DocumentView[];
|
|
400
425
|
};
|
|
401
426
|
/**
|
|
402
427
|
* 构建真源视图
|
|
@@ -404,27 +429,27 @@ type CompileSourceView = {
|
|
|
404
429
|
* @param root - 仓库根目录绝对路径
|
|
405
430
|
* @param config - 解析后的插件配置
|
|
406
431
|
* @returns 真源视图
|
|
407
|
-
* @throws {@link Error}
|
|
432
|
+
* @throws {@link Error} 任一文档条目文件名或元信息非法时,报错携带条目定位
|
|
408
433
|
*/
|
|
409
434
|
declare const buildSourceView: (root: string, config: CompilePluginConfig) => Promise<CompileSourceView>;
|
|
410
435
|
//#endregion
|
|
411
436
|
//#region src/compose/surface-composer.core.d.ts
|
|
412
437
|
/**
|
|
413
|
-
*
|
|
438
|
+
* 合成单个文档产物
|
|
414
439
|
*
|
|
415
440
|
* @param view - 真源视图
|
|
416
|
-
* @param
|
|
441
|
+
* @param documentView - 该文档视图
|
|
417
442
|
* @returns 产物 markdown 全文,恒以单个换行收尾
|
|
418
443
|
*/
|
|
419
|
-
declare const composeSurface: (view: CompileSourceView,
|
|
444
|
+
declare const composeSurface: (view: CompileSourceView, documentView: DocumentView) => string;
|
|
420
445
|
/**
|
|
421
|
-
*
|
|
446
|
+
* 合成全部文档产物
|
|
422
447
|
*
|
|
423
448
|
* @param view - 真源视图
|
|
424
|
-
* @returns
|
|
449
|
+
* @returns 文档名到产物路径与产物全文的集合
|
|
425
450
|
*/
|
|
426
451
|
declare const composeAllSurfaces: (view: CompileSourceView) => readonly {
|
|
427
|
-
|
|
452
|
+
document: string;
|
|
428
453
|
output: string;
|
|
429
454
|
markdown: string;
|
|
430
455
|
}[];
|
|
@@ -448,15 +473,14 @@ type CompileScanResult = {
|
|
|
448
473
|
*/
|
|
449
474
|
toolFace: readonly unknown[];
|
|
450
475
|
/**
|
|
451
|
-
*
|
|
476
|
+
* 各文档条目清单
|
|
452
477
|
*/
|
|
453
|
-
|
|
454
|
-
|
|
478
|
+
documents: readonly {
|
|
479
|
+
document: string;
|
|
455
480
|
output: string;
|
|
456
481
|
items: readonly {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
order: number | null;
|
|
482
|
+
file: string;
|
|
483
|
+
order: number;
|
|
460
484
|
metadata: readonly string[];
|
|
461
485
|
}[];
|
|
462
486
|
}[];
|
|
@@ -467,7 +491,7 @@ type CompileScanResult = {
|
|
|
467
491
|
* @param root - 仓库根目录绝对路径
|
|
468
492
|
* @param config - 解析后的插件配置
|
|
469
493
|
* @returns scan 结果
|
|
470
|
-
* @throws {@link Error}
|
|
494
|
+
* @throws {@link Error} 条目文件名或元信息非法时
|
|
471
495
|
*/
|
|
472
496
|
declare const runCompileScan: (root: string, config: CompilePluginConfig) => Promise<CompileScanResult>;
|
|
473
497
|
/**
|
|
@@ -476,13 +500,13 @@ declare const runCompileScan: (root: string, config: CompilePluginConfig) => Pro
|
|
|
476
500
|
* @param root - 仓库根目录绝对路径
|
|
477
501
|
* @param config - 解析后的插件配置
|
|
478
502
|
* @param dryRun - 只打印不写盘
|
|
479
|
-
* @returns
|
|
480
|
-
* @throws {@link Error}
|
|
503
|
+
* @returns 写盘清单即文档名与产物路径与条目数
|
|
504
|
+
* @throws {@link Error} 未配置文档或条目文件名或元信息非法时
|
|
481
505
|
*/
|
|
482
506
|
declare const runCompileDerive: (root: string, config: CompilePluginConfig, dryRun: boolean) => Promise<readonly {
|
|
483
|
-
|
|
507
|
+
document: string;
|
|
484
508
|
output: string;
|
|
485
509
|
itemCount: number;
|
|
486
510
|
}[]>;
|
|
487
511
|
//#endregion
|
|
488
|
-
export { type CompilePluginConfig, type CompilePluginConfigInput, CompilePluginConfigSchema, type CompileSourceView, type
|
|
512
|
+
export { type CompilePluginConfig, type CompilePluginConfigInput, CompilePluginConfigSchema, type CompileSourceView, type DocumentView, type SourceItem, type ToolFace, buildSourceView, compilePlugin, composeAllSurfaces, composeSurface, extractToolFace, parseCommanderHelp, parseCompilePluginConfig, resolveDocumentItems, runCompileCheck, runCompileDerive, runCompileScan };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import"./rolldown-runtime-BqT_7tdF.js";import{
|
|
2
|
-
`,` `),
|
|
3
|
-
`),
|
|
4
|
-
`);let t=[`### ${e.bin}`,``];e.description!==``&&t.push(e.description,``),t.push(`用法:\`${
|
|
5
|
-
`)},
|
|
1
|
+
import"./rolldown-runtime-BqT_7tdF.js";import{definePlugin as e,pluginCommand as t}from"@longzai-intelligence-docs/core";import*as n from"zod";import{mkdir as r,stat as i,writeFile as a}from"node:fs/promises";import{dirname as o,join as s}from"node:path";const c=`.lzi/docs/sources`,l=n.object({output:n.string().min(1).refine(e=>!e.startsWith(`/`),`产物路径须为仓库根相对路径`).refine(e=>e.endsWith(`.md`),`产物路径须为 md 文件`),title:n.string().min(1).optional(),toolFace:n.boolean().default(!1),exclude:n.array(n.string().min(1)).default([])}),u=n.object({bins:n.array(n.string().min(1)).optional(),invocations:n.record(n.string().min(1),n.array(n.string().min(1))).default({})}),d=n.object({sourceRoot:n.string().min(1).default(c),documents:n.array(l).default([]),toolFace:u.default({invocations:{}})}).default({sourceRoot:c,documents:[],toolFace:{invocations:{}}}),f=e=>{let t=e.split(`/`).at(-1)??e;return t.endsWith(`.md`)?t.slice(0,-3):t},p=e=>{let t=d.safeParse(e);if(!t.success)throw Error(`compile 插件配置非法:${t.error.issues.map(e=>`${e.path.join(`.`)||`根节`}——${e.message}`).join(`,`)}`);let n=/* @__PURE__ */ new Map;for(let e of t.data.documents){let t=f(e.output),r=n.get(t);if(r!==void 0)throw Error(`compile 插件配置非法:产物 basename '${t}' 跨文档重复,${r} 与 ${e.output},真源目录无法区分归属`);n.set(t,e.output)}return t.data},m=[`<!-- 本文件由 lzi-docs compile 派生维护,禁止手工编辑 -->`,`<!-- 真源为 .lzi/docs/sources 下文档条目与 lzi-docs.config.ts 的 plugins.compile 配置,变更后重新执行 compile-derive 重建 -->`],h=(e,t,n)=>`<!-- compile:source ${e}/${t}/${n} -->`,g=e=>e.replaceAll(`|`,`\\|`).replaceAll(`
|
|
2
|
+
`,` `),_=e=>e.length===0?``:[`| 选项 | 说明 |`,`| --- | --- |`,...e.map(e=>`| \`${g(e.flags)}\` | ${g(e.description)} |`)].join(`
|
|
3
|
+
`),v=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(`用法:\`${g(e.usage.replace(/^Usage:\s*/,``))}\``);let n=_(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} ${g(n.invocation)}\``);let i=_(n.options);i!==``&&t.push(``,`**选项**`,``,i)}return t.join(`
|
|
5
|
+
`)},y=e=>[`## 命令参考`,``,"本节由工具面自 `--help` 输出抽取合成,源为 bin 帮助文案。",``,e.map(e=>v(e)).join(`
|
|
6
6
|
|
|
7
7
|
`)].join(`
|
|
8
|
-
`),
|
|
9
|
-
`).trimEnd()}\n`},
|
|
8
|
+
`),b=(e,t)=>{let n=[...m,``,`# ${t.title}`,``];for(let r of t.items)n.push(h(e.sourceRootLabel,t.document,r.fileName),r.body,``);return t.toolFace&&e.toolFace.length>0&&n.push(y(e.toolFace),``),`${n.join(`
|
|
9
|
+
`).trimEnd()}\n`},x=e=>e.documents.map(t=>({document:t.document,output:t.output,markdown:b(e,t)})),S=/* @__PURE__ */ new Set([`id`,`type`,`title`,`anchor`,`command`]),C={id:null,type:null,title:null,anchor:null,command:null},w=e=>{let t=e.split(`
|
|
10
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
|
-
`)}},
|
|
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
|
|
13
|
-
`),options:c,commands:l}},
|
|
14
|
-
`)},
|
|
11
|
+
`)}},T=(e,t)=>{let n={...C},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(o===`order`)throw Error(`条目 ${t} 的 frontmatter 键 order 已废弃,定序由文件名数值前缀唯一承载`);if(!S.has(o))throw Error(`条目 ${t} 的 frontmatter 含未知元数据键 '${o}',仅支持 id 与 type 与 title 与 anchor 与 command`);if(r.has(o))throw Error(`条目 ${t} 的 frontmatter 重复声明 ${o}`);if(r.add(o),s===``)throw Error(`条目 ${t} 的元数据键 ${o} 值为空`);(o===`id`||o===`type`||o===`title`||o===`anchor`||o===`command`)&&(n[o]=s)}return n},ee=/^(\d+)-(.+)$/,E=async e=>{try{return await i(e),!0}catch{return!1}},D=e=>{let t=e.endsWith(`.md`)?e.slice(0,-3):e,n=ee.exec(t);if(n===null)return null;let r=n[1]??``;return{order:Number(r),slug:n[2]??``}},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=(e,t,n)=>`${e}/${t}/${n}`,A=async e=>{let t=[];if(!await E(e.documentDir))return t;let n=await O(e.documentDir),r=/* @__PURE__ */ new Set,i=e.exclude.map(e=>new Bun.Glob(e));for(let a of n){if(i.some(e=>e.match(a)))continue;let n=D(a);if(n===null)throw Error(`条目 ${k(e.sourceRootLabel,e.documentName,a)} 文件名无数值前缀,形态须为 NNN-slug.md,顺序性由前缀承载`);if(r.has(n.order))throw Error(`文档 ${e.documentName} 内条目前缀数值 ${String(n.order)} 重复,文件 ${a} 与先登记者冲突`);r.add(n.order);let o=await Bun.file(s(e.documentDir,a)).text(),{metaLines:c,body:l}=w(o),u=T(c,k(e.sourceRootLabel,e.documentName,a));l.trim()!==``&&t.push({fileName:a,order:n.order,meta:u,body:l.trimEnd()})}return t.sort((e,t)=>e.order-t.order)},j=e=>typeof e==`object`&&!!e,M=async e=>{let t={name:null,description:null,version:null,bins:[]};try{let n=await Bun.file(`${e}/package.json`).json();if(!j(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]:j(r)&&(t.bins=Object.keys(r))}catch{return t}return t},N=[{name:`options`,pattern:/^Options:\s*$/},{name:`commands`,pattern:/^Commands:\s*$/}],P=/^\s+\S/,F=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 N)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(P.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}},I=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)}}},L=async e=>{let t=await I([...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=F(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 I([...e.invocation,t.name,`--help`],e.root),r=n.stdout===``?n.stderr:n.stdout,a=n.exitCode===0?F(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}},R=async e=>{let t=[];for(let n of e.bins)t.push(await L({bin:n,invocation:e.invocations[n]??[n],root:e.root}));return t},z=e=>{let t=e.split(`/`).at(-1)??e;return t.endsWith(`.md`)?t.slice(0,-3):t},B=async(e,t)=>{let n=await M(e),r=t.toolFace.bins??n.bins,i=r.length>0?await R({bins:r,invocations:t.toolFace.invocations,root:e}):[],a=[];for(let n of t.documents){let r=z(n.output),i=await A({documentDir:s(e,t.sourceRoot,r),documentName:r,sourceRootLabel:t.sourceRoot,exclude:n.exclude});a.push({document:r,output:n.output,title:n.title??r,toolFace:n.toolFace,items:i})}return{root:e,sourceRootLabel:t.sourceRoot,manifest:n,toolFace:i,documents:a}},V=e=>{let t=e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);return[RegExp(`name\\s*[:=]\\s*(['"\`])${t}\\1`),RegExp(`\\.command\\(\\s*(['"\`])${t}\\1`)]},H=async e=>{let t=[];for(let n of e.documents)for(let r of n.items){let i=`${e.sourceRootLabel}/${n.document}/${r.fileName}`;if(r.meta.anchor===null&&r.meta.command===null)continue;if(r.meta.anchor===null){t.push({kind:`anchor-missing`,message:`条目 ${i} 声明了 command 而无 anchor,命令锚定需要 anchor 指向命令定义所在源码文件`});continue}let a=s(e.root,r.meta.anchor);if(!await Bun.file(a).exists()){t.push({kind:`anchor-missing`,message:`条目 ${i} 的 anchor 指向的文件不存在:${r.meta.anchor}`});continue}if(r.meta.command===null)continue;let o=await Bun.file(a).text();V(r.meta.command).some(e=>e.test(o))||t.push({kind:`command-not-found`,message:`条目 ${i} 的 command '${r.meta.command}' 在锚点源码 ${r.meta.anchor} 中未命中命令定义,命令可能已改名`})}return t},U=async(e,t)=>{let n=await B(e,t),r=x(n),i=/* @__PURE__ */ new Map;for(let t of r){let n=s(e,t.output);if(!await Bun.file(n).exists()){i.set(t.document,{status:`missing`,expected:t.markdown});continue}let r=await Bun.file(n).text();i.set(t.document,{status:r===t.markdown?`fresh`:`stale`,expected:t.markdown})}return i},W=async(e,t)=>{let n=await B(e,t),r=[...await H(n)];for(let t of x(n)){let n=s(e,t.output);await Bun.file(n).exists()?await Bun.file(n).text()!==t.markdown&&r.push({kind:`snapshot-stale`,message:`文档 ${t.document} 的产物过期:${t.output} 与真源合成结果不一致,执行 compile-derive 重建`}):r.push({kind:`snapshot-missing`,message:`文档 ${t.document} 的产物缺失:${t.output},执行 compile-derive 生成`})}return r},G=async(e,t)=>{let n=await U(e.root,t),r=0,i=0;for(let t of e.documents)for(let e of t.items)r+=1,(e.meta.id!==null||e.meta.type!==null||e.meta.title!==null||e.meta.anchor!==null||e.meta.command!==null)&&(i+=1);return{repo:e.manifest.name??``,itemCount:r,metadataCoverage:r===0?1:i/r,documents:e.documents.map(e=>({document:e.document,output:e.output,itemCount:e.items.length,freshness:n.get(e.document)?.status??`missing`})),toolFace:e.toolFace.map(e=>({bin:e.bin,degraded:e.degraded,commandCount:e.degraded?0:e.commands.length}))}},K=e=>e===`fresh`?`新鲜`:e===`stale`?`过期`:`缺失`,q=e=>{let t=e.documents.map(e=>`| ${e.document} | \`${e.output}\` | ${e.itemCount} | ${K(e.freshness)} |`),n=e.toolFace.map(e=>`| \`${e.bin}\` | ${e.degraded?`是`:`否`} | ${e.commandCount} |`);return[`# compile inventory:${e.repo===``?`未识别包名`:e.repo}`,``,`- 条目总数:${e.itemCount}`,`- 元数据覆盖率:${(e.metadataCoverage*100).toFixed(0)}%`,``,`## 文档`,``,`| 文档 | 产物 | 条目数 | 新鲜度 |`,`| --- | --- | --- | --- |`,...t.length>0?t:[`| 无 | 无 | 0 | 缺失 |`],``,`## 工具面`,``,`| bin | 降级 | 命令数 |`,`| --- | --- | --- |`,...n.length>0?n:[`| 无 | 是 | 0 |`],``].join(`
|
|
14
|
+
`)},J=e=>e.documents.length===0,Y=async(e,t)=>{let n=await B(e,t);return{manifest:n.manifest,toolFace:n.toolFace,documents:n.documents.map(e=>({document:e.document,output:e.output,items:e.items.map(e=>({file:e.fileName,order:e.order,metadata:[[`id`,e.meta.id],[`type`,e.meta.type],[`title`,e.meta.title],[`anchor`,e.meta.anchor],[`command`,e.meta.command]].filter(([,e])=>e!==null).map(([e])=>e)}))}))}},X=async(e,t,n)=>{if(J(t))throw Error(`plugins.compile.options 未配置任何文档,请在 lzi-docs.config.ts 的 documents 节配置后重试`);let i=await B(e,t),c=x(i);for(let t of c)if(!n){let n=s(e,t.output);await r(o(n),{recursive:!0}),await a(n,t.markdown,`utf-8`)}return c.map(e=>({document:e.document,output:e.output,itemCount:i.documents.find(t=>t.document===e.document)?.items.length??0}))},Z=async(e,t)=>{if(J(t))throw Error(`plugins.compile.options 未配置任何文档,请在 lzi-docs.config.ts 的 documents 节配置后重试`);return{findings:await W(e,t),documentCount:t.documents.length}},Q=async(e,t)=>{let n=await B(e,t),r=await G(n,t);return{markdown:q(r),data:r}},$=n.object({}),te=n.object({dryRun:n.boolean().default(!1)}),ne=n.object({}),re=n.object({json:n.boolean().default(!1)}),ie=e({name:`compile`,version:`0.0.1`,configSchema:d,commands:[e=>ae(e),e=>oe(e),e=>se(e),e=>ce(e)]});function ae(e){return t({name:`compile-scan`,description:`扫描真源面出清单:文档条目、manifest 面与工具面帮助抽取`,schema:$,action:async()=>{try{let t=await Y(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 oe(e){return t({name:`compile-derive`,description:`建模并派生文档产物写盘,同输入逐字节相同输出`,options:[{flags:`--dry-run`,description:`只打印合成结果不写盘`}],schema:te,action:async t=>{try{let n=await X(process.cwd(),p(e.pluginConfig),t.dryRun);for(let e of n)process.stdout.write(`${t.dryRun?`预览`:`已写入`} ${e.output},文档 ${e.document},条目 ${e.itemCount}\n`)}catch(e){process.stderr.write(`错误: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}})}function se(e){return t({name:`compile-check`,description:`只读校验:快照新鲜度逐字节比对与锚点命令定义命中`,schema:ne,action:async()=>{try{let t=await Z(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.documentCount} 份全绿\n`)}catch(e){process.stderr.write(`错误: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}})}function ce(e){return t({name:`compile-report`,description:`单仓 inventory 上报:文档计数、条目数、元数据覆盖率与产物新鲜度`,options:[{flags:`--json`,description:`以 JSON 形态输出`}],schema:re,action:async t=>{try{let n=await Q(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{d as CompilePluginConfigSchema,B as buildSourceView,ie as compilePlugin,x as composeAllSurfaces,b as composeSurface,R as extractToolFace,F as parseCommanderHelp,p as parseCompilePluginConfig,A as resolveDocumentItems,W as runCompileCheck,X as runCompileDerive,Y as runCompileScan};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence-docs/compile-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Longzai Intelligence Docs compile 插件",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compile",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@longzai-intelligence-cli/core": "^0.0.11",
|
|
41
|
-
"@longzai-intelligence-docs/core": "0.0.
|
|
41
|
+
"@longzai-intelligence-docs/core": "0.0.15",
|
|
42
42
|
"zod": "^4.4.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|