@longzai-intelligence-ledger/core 0.0.1
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/README.md +5 -0
- package/dist/index.d.ts +387 -0
- package/dist/index.js +9 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# @longzai-intelligence-ledger/core
|
|
2
|
+
|
|
3
|
+
Longzai Intelligence Ledger 校验引擎:台账族文件面盘点、六类规则、编排执行与 eslint 风格报告。机制域零仓库知识,阈值与豁免由调用方经完整选项注入。
|
|
4
|
+
|
|
5
|
+
主导出契约:`runLedgerCheck`、`resolveLedgerCheckOptions`、`collectLedgerFileSet`、`formatLedgerCheckReport`、六类规则函数、`matchesAnyGlob`、markdown 行级工具。
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
//#region src/ledger-check.types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* 台账形态校验违例
|
|
4
|
+
*
|
|
5
|
+
* 单条违例对应一行 eslint 风格报告,severity 当前仅有 error 一级
|
|
6
|
+
*/
|
|
7
|
+
type LedgerViolation = {
|
|
8
|
+
/**
|
|
9
|
+
* 违例文件路径,相对仓库根
|
|
10
|
+
*/
|
|
11
|
+
file: string;
|
|
12
|
+
/**
|
|
13
|
+
* 违例行号,一基
|
|
14
|
+
*
|
|
15
|
+
* 文件级违例时为 null
|
|
16
|
+
*/
|
|
17
|
+
line: number | null;
|
|
18
|
+
/**
|
|
19
|
+
* 规则标识
|
|
20
|
+
*
|
|
21
|
+
* line-width、workstream-size、status-vocabulary、commit-hash、link-resolution、temp-path 六类
|
|
22
|
+
*/
|
|
23
|
+
ruleId: string;
|
|
24
|
+
/**
|
|
25
|
+
* 违例说明,中文完整短句
|
|
26
|
+
*/
|
|
27
|
+
message: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* 台账形态校验解析后的完整选项
|
|
31
|
+
*
|
|
32
|
+
* 由局部配置与默认值合并而成,引擎只消费完整形态
|
|
33
|
+
*/
|
|
34
|
+
type ResolvedLedgerCheckOptions = {
|
|
35
|
+
/**
|
|
36
|
+
* 仓库根绝对路径
|
|
37
|
+
*/
|
|
38
|
+
repoRoot: string;
|
|
39
|
+
/**
|
|
40
|
+
* 台账族根目录,相对仓库根
|
|
41
|
+
*/
|
|
42
|
+
ledgersRoot: string;
|
|
43
|
+
/**
|
|
44
|
+
* 单行最大字符数
|
|
45
|
+
*/
|
|
46
|
+
maxLineLength: number;
|
|
47
|
+
/**
|
|
48
|
+
* 工作流档最大行数
|
|
49
|
+
*/
|
|
50
|
+
maxWorkstreamLines: number;
|
|
51
|
+
/**
|
|
52
|
+
* 工作流档最大字节数
|
|
53
|
+
*/
|
|
54
|
+
maxWorkstreamBytes: number;
|
|
55
|
+
/**
|
|
56
|
+
* 合法状态词表,默认词表与配置附加词表的并集
|
|
57
|
+
*/
|
|
58
|
+
statusVocabulary: string[];
|
|
59
|
+
/**
|
|
60
|
+
* 体量豁免 glob 清单,相对台账族根
|
|
61
|
+
*/
|
|
62
|
+
sizeExemptGlobs: string[];
|
|
63
|
+
/**
|
|
64
|
+
* 临时路径豁免 glob 清单,相对台账族根
|
|
65
|
+
*/
|
|
66
|
+
tmpPathAllowGlobs: string[];
|
|
67
|
+
/**
|
|
68
|
+
* 哈希禁令豁免 glob 清单,相对台账族根
|
|
69
|
+
*/
|
|
70
|
+
hashExemptGlobs: string[];
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* 台账族文件盘点条目
|
|
74
|
+
*/
|
|
75
|
+
type LedgerFileEntry = {
|
|
76
|
+
/**
|
|
77
|
+
* 文件绝对路径
|
|
78
|
+
*/
|
|
79
|
+
absolutePath: string;
|
|
80
|
+
/**
|
|
81
|
+
* 文件路径,相对仓库根,恒以 posix 分隔符表达
|
|
82
|
+
*/
|
|
83
|
+
relativePath: string;
|
|
84
|
+
/**
|
|
85
|
+
* 文件全文
|
|
86
|
+
*/
|
|
87
|
+
content: string;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* 台账族文件面分类结果
|
|
91
|
+
*/
|
|
92
|
+
type LedgerFileSet = {
|
|
93
|
+
/**
|
|
94
|
+
* 索引位文件清单
|
|
95
|
+
*
|
|
96
|
+
* 各账 ledger.md 与 workstreams 目录内全部 markdown 档
|
|
97
|
+
*/
|
|
98
|
+
indexFiles: LedgerFileEntry[];
|
|
99
|
+
/**
|
|
100
|
+
* 工作流档清单
|
|
101
|
+
*
|
|
102
|
+
* workstreams 目录内的三 位编号档,不含目录 README
|
|
103
|
+
*/
|
|
104
|
+
workstreamFiles: LedgerFileEntry[];
|
|
105
|
+
/**
|
|
106
|
+
* 台账族内全部 markdown 文件,封存面除外
|
|
107
|
+
*/
|
|
108
|
+
allFiles: LedgerFileEntry[];
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* 台账形态校验结果
|
|
112
|
+
*/
|
|
113
|
+
type LedgerCheckResult = {
|
|
114
|
+
/**
|
|
115
|
+
* 违例清单,按文件路径与行号排序
|
|
116
|
+
*/
|
|
117
|
+
violations: LedgerViolation[];
|
|
118
|
+
/**
|
|
119
|
+
* 扫描文件计数
|
|
120
|
+
*/
|
|
121
|
+
summary: {
|
|
122
|
+
/**
|
|
123
|
+
* 扫描的 markdown 文件总数
|
|
124
|
+
*/
|
|
125
|
+
files: number;
|
|
126
|
+
/**
|
|
127
|
+
* 索引位文件数
|
|
128
|
+
*/
|
|
129
|
+
indexFiles: number;
|
|
130
|
+
/**
|
|
131
|
+
* 违例总数
|
|
132
|
+
*/
|
|
133
|
+
errors: number;
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* 规则消费的源文件入参形态
|
|
138
|
+
*
|
|
139
|
+
* 各规则统一消费相对路径与全文内容,不触磁盘
|
|
140
|
+
*/
|
|
141
|
+
type LedgerSourceFile = {
|
|
142
|
+
/**
|
|
143
|
+
* 文件路径,相对仓库根
|
|
144
|
+
*/
|
|
145
|
+
relativePath: string;
|
|
146
|
+
/**
|
|
147
|
+
* 文件全文
|
|
148
|
+
*/
|
|
149
|
+
content: string;
|
|
150
|
+
};
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/default-options.constants.d.ts
|
|
153
|
+
/**
|
|
154
|
+
* 默认单行最大字符数
|
|
155
|
+
*/
|
|
156
|
+
declare const DEFAULT_MAX_LINE_LENGTH = 400;
|
|
157
|
+
/**
|
|
158
|
+
* 默认工作流档最大行数
|
|
159
|
+
*/
|
|
160
|
+
declare const DEFAULT_MAX_WORKSTREAM_LINES = 100;
|
|
161
|
+
/**
|
|
162
|
+
* 默认工作流档最大字节数
|
|
163
|
+
*/
|
|
164
|
+
declare const DEFAULT_WORKSTREAM_BYTES = 16000;
|
|
165
|
+
/**
|
|
166
|
+
* 默认台账族根目录,相对仓库根
|
|
167
|
+
*/
|
|
168
|
+
declare const DEFAULT_LEDGERS_ROOT = "docs/ledgers";
|
|
169
|
+
/**
|
|
170
|
+
* 默认状态词表
|
|
171
|
+
*/
|
|
172
|
+
declare const DEFAULT_STATUS_VOCABULARY: string[];
|
|
173
|
+
/**
|
|
174
|
+
* 校验选项局部输入形态
|
|
175
|
+
*
|
|
176
|
+
* 全部字段可省略,省略项沿用默认值
|
|
177
|
+
*/
|
|
178
|
+
type PartialLedgerCheckOptions = {
|
|
179
|
+
repoRoot: string;
|
|
180
|
+
ledgersRoot?: string;
|
|
181
|
+
maxLineLength?: number;
|
|
182
|
+
maxWorkstreamLines?: number;
|
|
183
|
+
maxWorkstreamBytes?: number;
|
|
184
|
+
extraStatusVocabulary?: string[];
|
|
185
|
+
sizeExemptGlobs?: string[];
|
|
186
|
+
tmpPathAllowGlobs?: string[];
|
|
187
|
+
hashExemptGlobs?: string[];
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* 解析校验选项
|
|
191
|
+
*
|
|
192
|
+
* 将局部选项与默认值合并为引擎消费的完整形态
|
|
193
|
+
*
|
|
194
|
+
* @param options - 局部校验选项,仅 repoRoot 必填
|
|
195
|
+
* @returns 完整校验选项
|
|
196
|
+
*/
|
|
197
|
+
declare const resolveLedgerCheckOptions: (options: PartialLedgerCheckOptions) => ResolvedLedgerCheckOptions;
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/glob-match.utils.d.ts
|
|
200
|
+
/**
|
|
201
|
+
* glob 匹配工具
|
|
202
|
+
*
|
|
203
|
+
* 支持 `**` 跨段、`*` 单段与 `?` 单字符三类通配,覆盖台账豁免清单的声明需求
|
|
204
|
+
* 其余字符按字面匹配,分隔符恒按 posix 形态比较
|
|
205
|
+
*/
|
|
206
|
+
/**
|
|
207
|
+
* 判断路径是否命中任一 glob
|
|
208
|
+
*
|
|
209
|
+
* @param relativePath - 相对路径,posix 分隔符形态
|
|
210
|
+
* @param globs - glob 清单
|
|
211
|
+
* @returns 命中任一表达式时为 true
|
|
212
|
+
*/
|
|
213
|
+
declare const matchesAnyGlob: (relativePath: string, globs: string[]) => boolean;
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/markdown.utils.d.ts
|
|
216
|
+
/**
|
|
217
|
+
* markdown 行级工具
|
|
218
|
+
*
|
|
219
|
+
* 供各规则消费,统一围栏代码块的豁免口径
|
|
220
|
+
*/
|
|
221
|
+
/**
|
|
222
|
+
* 标记各行是否处于围栏代码块内
|
|
223
|
+
*
|
|
224
|
+
* 围栏判定只识别行首三连反引号形态,与台账族书写习惯一致
|
|
225
|
+
*
|
|
226
|
+
* @param lines - 文件全文按行拆分后的数组
|
|
227
|
+
* @returns 与行数等长的布尔数组,true 表示该行在围栏内
|
|
228
|
+
*/
|
|
229
|
+
declare const markFencedLines: (lines: string[]) => boolean[];
|
|
230
|
+
/**
|
|
231
|
+
* 单行字符数
|
|
232
|
+
*
|
|
233
|
+
* 按码点计数,中文与半角字符均计一字符
|
|
234
|
+
*
|
|
235
|
+
* @param line - 单行文本
|
|
236
|
+
* @returns 码点数
|
|
237
|
+
*/
|
|
238
|
+
declare const countLineLength: (line: string) => number;
|
|
239
|
+
/**
|
|
240
|
+
* 提取单行内全部 markdown 链接目标
|
|
241
|
+
*
|
|
242
|
+
* 识别行内链接与图片的目标段,锚点链接与空目标不返回
|
|
243
|
+
*
|
|
244
|
+
* @param line - 单行文本
|
|
245
|
+
* @returns 链接目标数组,按出现顺序排列
|
|
246
|
+
*/
|
|
247
|
+
declare const extractLinkTargets: (line: string) => string[];
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/scan.utils.d.ts
|
|
250
|
+
/**
|
|
251
|
+
* 盘点台账族文件面
|
|
252
|
+
*
|
|
253
|
+
* @param repoRoot - 仓库根绝对路径
|
|
254
|
+
* @param ledgersRoot - 台账族根目录,相对仓库根
|
|
255
|
+
* @returns 分类后的文件面
|
|
256
|
+
* @throws {@link Error} 当台账族根不存在时抛出
|
|
257
|
+
*/
|
|
258
|
+
declare const collectLedgerFileSet: (repoRoot: string, ledgersRoot: string) => LedgerFileSet;
|
|
259
|
+
/**
|
|
260
|
+
* 判断是否为索引位文件
|
|
261
|
+
*
|
|
262
|
+
* 各账 ledger.md 与 workstreams 目录内全部 markdown 档
|
|
263
|
+
*
|
|
264
|
+
* @param relativePath - 相对仓库根路径
|
|
265
|
+
* @param ledgersRoot - 台账族根目录
|
|
266
|
+
* @returns 索引位文件为 true
|
|
267
|
+
*/
|
|
268
|
+
declare const isIndexFile: (relativePath: string, ledgersRoot: string) => boolean;
|
|
269
|
+
/**
|
|
270
|
+
* 判断是否为工作流档
|
|
271
|
+
*
|
|
272
|
+
* workstreams 目录内以三位编号命名的档,目录 README 不计
|
|
273
|
+
*
|
|
274
|
+
* @param relativePath - 相对仓库根路径
|
|
275
|
+
* @param ledgersRoot - 台账族根目录
|
|
276
|
+
* @returns 工作流档为 true
|
|
277
|
+
*/
|
|
278
|
+
declare const isWorkstreamFile: (relativePath: string, ledgersRoot: string) => boolean;
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/check-commit-hash.rule.d.ts
|
|
281
|
+
/**
|
|
282
|
+
* 检查索引位文件提交哈希
|
|
283
|
+
*
|
|
284
|
+
* @param file - 文件条目
|
|
285
|
+
* @param ledgersRoot - 台账族根目录
|
|
286
|
+
* @param hashExemptGlobs - 哈希禁令豁免清单
|
|
287
|
+
* @returns 违例清单
|
|
288
|
+
*/
|
|
289
|
+
declare const checkCommitHash: (file: LedgerSourceFile, ledgersRoot: string, hashExemptGlobs: string[]) => LedgerViolation[];
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/check-line-width.rule.d.ts
|
|
292
|
+
/**
|
|
293
|
+
* 检查索引位文件行宽
|
|
294
|
+
*
|
|
295
|
+
* @param file - 文件条目
|
|
296
|
+
* @param maxLineLength - 单行最大字符数
|
|
297
|
+
* @returns 违例清单
|
|
298
|
+
*/
|
|
299
|
+
declare const checkLineWidth: (file: LedgerSourceFile, maxLineLength: number) => LedgerViolation[];
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/check-link-resolution.rule.d.ts
|
|
302
|
+
/**
|
|
303
|
+
* 检查索引位文件链接可解析性
|
|
304
|
+
*
|
|
305
|
+
* @param file - 文件条目
|
|
306
|
+
* @param repoRoot - 仓库根绝对路径
|
|
307
|
+
* @returns 违例清单
|
|
308
|
+
*/
|
|
309
|
+
declare const checkLinkResolution: (file: LedgerSourceFile, repoRoot: string) => LedgerViolation[];
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/check-status-vocabulary.rule.d.ts
|
|
312
|
+
/**
|
|
313
|
+
* 检查总账聚合表状态列
|
|
314
|
+
*
|
|
315
|
+
* 仅检查 ledger.md 内表头含状态列的表格
|
|
316
|
+
*
|
|
317
|
+
* @param file - 总账文件条目
|
|
318
|
+
* @param statusVocabulary - 合法状态词表
|
|
319
|
+
* @returns 违例清单
|
|
320
|
+
*/
|
|
321
|
+
declare const checkStatusVocabulary: (file: LedgerSourceFile, statusVocabulary: string[]) => LedgerViolation[];
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/check-temp-path.rule.d.ts
|
|
324
|
+
/**
|
|
325
|
+
* 检查文件临时路径引用
|
|
326
|
+
*
|
|
327
|
+
* @param file - 文件条目
|
|
328
|
+
* @param ledgersRoot - 台账族根目录
|
|
329
|
+
* @param tmpPathAllowGlobs - 临时路径豁免清单
|
|
330
|
+
* @returns 违例清单
|
|
331
|
+
*/
|
|
332
|
+
declare const checkTempPath: (file: LedgerSourceFile, ledgersRoot: string, tmpPathAllowGlobs: string[]) => LedgerViolation[];
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/check-workstream-size.rule.d.ts
|
|
335
|
+
/**
|
|
336
|
+
* 检查单个工作流档体量
|
|
337
|
+
*
|
|
338
|
+
* @param file - 文件条目
|
|
339
|
+
* @param options - 体量阈值与豁免清单,globs 以台账族内相对路径表达
|
|
340
|
+
* @returns 违例清单
|
|
341
|
+
*/
|
|
342
|
+
declare const checkWorkstreamSize: (file: LedgerSourceFile, options: WorkstreamSizeOptions) => LedgerViolation[];
|
|
343
|
+
/**
|
|
344
|
+
* 体量规则选项
|
|
345
|
+
*/
|
|
346
|
+
type WorkstreamSizeOptions = {
|
|
347
|
+
/**
|
|
348
|
+
* 台账族根目录
|
|
349
|
+
*/
|
|
350
|
+
ledgersRoot: string;
|
|
351
|
+
/**
|
|
352
|
+
* 工作流档最大行数
|
|
353
|
+
*/
|
|
354
|
+
maxWorkstreamLines: number;
|
|
355
|
+
/**
|
|
356
|
+
* 工作流档最大字节数
|
|
357
|
+
*/
|
|
358
|
+
maxWorkstreamBytes: number;
|
|
359
|
+
/**
|
|
360
|
+
* 体量豁免清单
|
|
361
|
+
*/
|
|
362
|
+
sizeExemptGlobs: string[];
|
|
363
|
+
};
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region src/run-ledger-check.utils.d.ts
|
|
366
|
+
/**
|
|
367
|
+
* 执行台账形态校验
|
|
368
|
+
*
|
|
369
|
+
* @param options - 完整校验选项
|
|
370
|
+
* @returns 校验结果,含违例清单与扫描计数
|
|
371
|
+
* @throws {@link Error} 当台账族根不存在时由盘点环节抛出
|
|
372
|
+
*/
|
|
373
|
+
declare const runLedgerCheck: (options: ResolvedLedgerCheckOptions) => LedgerCheckResult;
|
|
374
|
+
//#endregion
|
|
375
|
+
//#region src/format-report.utils.d.ts
|
|
376
|
+
/**
|
|
377
|
+
* 格式化校验报告
|
|
378
|
+
*
|
|
379
|
+
* @param result - 校验结果
|
|
380
|
+
* @param options - 格式化选项,rootLabel 为报告头展示的仓库根标签
|
|
381
|
+
* @returns 报告全文,无违例时为通过短语
|
|
382
|
+
*/
|
|
383
|
+
declare const formatLedgerCheckReport: (result: LedgerCheckResult, options?: {
|
|
384
|
+
rootLabel?: string;
|
|
385
|
+
}) => string;
|
|
386
|
+
//#endregion
|
|
387
|
+
export { DEFAULT_LEDGERS_ROOT, DEFAULT_MAX_LINE_LENGTH, DEFAULT_MAX_WORKSTREAM_LINES, DEFAULT_STATUS_VOCABULARY, DEFAULT_WORKSTREAM_BYTES, type LedgerCheckResult, type LedgerFileEntry, type LedgerFileSet, type LedgerViolation, type PartialLedgerCheckOptions, type ResolvedLedgerCheckOptions, checkCommitHash, checkLineWidth, checkLinkResolution, checkStatusVocabulary, checkTempPath, checkWorkstreamSize, collectLedgerFileSet, countLineLength, extractLinkTargets, formatLedgerCheckReport, isIndexFile, isWorkstreamFile, markFencedLines, matchesAnyGlob, resolveLedgerCheckOptions, runLedgerCheck };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{existsSync as e,readFileSync as t,readdirSync as n}from"node:fs";import{dirname as r,isAbsolute as i,join as a,normalize as o,relative as s,resolve as c,sep as l}from"node:path";const u=400,d=100,f=16e3,p=`docs/ledgers`,m=[`待建档`,`待启动`,`进行中`,`已收口`,`不适用`],h=e=>({repoRoot:e.repoRoot,ledgersRoot:e.ledgersRoot??`docs/ledgers`,maxLineLength:e.maxLineLength??400,maxWorkstreamLines:e.maxWorkstreamLines??100,maxWorkstreamBytes:e.maxWorkstreamBytes??16e3,statusVocabulary:[...m,...e.extraStatusVocabulary??[]],sizeExemptGlobs:e.sizeExemptGlobs??[],tmpPathAllowGlobs:e.tmpPathAllowGlobs??[],hashExemptGlobs:e.hashExemptGlobs??[]}),g=e=>{let t=``,n=0;for(;n<e.length;){let r=e.charAt(n);if(r===`*`){if(e.startsWith(`**`,n)){t+=`.*`,n+=2;continue}t+=`[^/]*`,n+=1;continue}if(r===`?`){t+=`[^/]`,n+=1;continue}t+=r.replace(/[\\^$.+()[\]{}|]/gu,`\\$&`),n+=1}return RegExp(`^(?:${t})$`,`u`)},_=(e,t)=>t.some(t=>g(t).test(e)),v=e=>{let t=[],n=!1;for(let r of e){if(/^\s*```/.test(r)){t.push(!1),n=!n;continue}t.push(n)}return t},y=e=>Array.from(e).length,b=e=>{let t=[],n=e.replaceAll(/`[^`]*`/gu,``);for(let e of n.matchAll(/\]\(([^)]*)\)/gu)){let n=e[1]?.trim()??``;n===``||n.startsWith(`#`)||t.push(n)}return t},x=/* @__PURE__ */ new Set([`archives`,`node_modules`,`dist`,`.turbo`,`.git`,`out`,`coverage`]),S=(e,r)=>{let i=a(e,r),o=[],c=r=>{for(let i of n(r,{withFileTypes:!0})){if(i.isDirectory()){if(x.has(i.name))continue;c(a(r,i.name));continue}if(!i.name.endsWith(`.md`))continue;let n=a(r,i.name);o.push({absolutePath:n,relativePath:s(e,n).split(l).join(`/`),content:t(n,`utf8`)})}};return c(i),{indexFiles:o.filter(e=>C(e.relativePath,r)),workstreamFiles:o.filter(e=>w(e.relativePath,r)),allFiles:o}},C=(e,t)=>{let n=T(e,t);return n===null?!1:/^[^/]+\/ledger\.md$/.test(n)?!0:/^[^/]+\/workstreams\/[^/]+\.md$/.test(n)},w=(e,t)=>{let n=T(e,t);return n!==null&&/^[^/]+\/workstreams\/\d{3}[^/]*\.md$/.test(n)},T=(e,t)=>{let n=`${t.replace(/\/$/u,``)}/`;return e.startsWith(n)?e.slice(n.length):null},E=/\b(?=[0-9a-f]{7,40}\b)(?=[0-9a-f]*[a-f])[0-9a-f]{7,40}\b/gu,D=(e,t,n)=>{let r=e.relativePath.startsWith(`${t}/`)?e.relativePath.slice(t.length+1):e.relativePath;if(_(r,n))return[];let i=[],a=e.content.split(`
|
|
2
|
+
`),o=v(a);return a.forEach((t,n)=>{if(o[n]===!0)return;let r=t.match(E)??[];for(let t of r)i.push({file:e.relativePath,line:n+1,ruleId:`commit-hash`,message:`索引面出现提交哈希 ${t},证据指针请归逐仓档`})}),i},O=(e,t)=>{let n=[],r=e.content.split(`
|
|
3
|
+
`),i=v(r);return r.forEach((r,a)=>{if(i[a]===!0)return;let o=y(r);o>t&&n.push({file:e.relativePath,line:a+1,ruleId:`line-width`,message:`单行 ${o} 字符超过上限 ${t} 字符,请拆条或下沉明细`})}),n},k=(e,t)=>{let n=[],r=e.content.split(`
|
|
4
|
+
`),i=v(r);return r.forEach((r,a)=>{if(i[a]!==!0)for(let i of b(r)){if(A(i))continue;let r=i.split(`#`)[0]?.trim()??``;r!==``&&(j(r,e.relativePath,t)||n.push({file:e.relativePath,line:a+1,ruleId:`link-resolution`,message:`链接目标 ${r} 不存在,请修正或改为指针文本`}))}}),n},A=e=>/^(https?:|mailto:|tel:)/iu.test(e)?!0:e.includes(`xxx`),j=(t,n,a)=>{let s=c(a,r(n),t);if(e(s))return!0;let l=i(t)?c(a,`.${t}`):c(a,t);return l.startsWith(`${a}${a.endsWith(`/`)?``:`/`}`)===!1||e(l)||o(s)===o(l)},M=/^已并入 \d{3}$/u,N=/* @__PURE__ */ new Set([``,`—`,`——`]),P=(e,t)=>{let n=[],r=e.content.split(`
|
|
5
|
+
`),i=null;return r.forEach((r,a)=>{if(!r.trimStart().startsWith(`|`)){i=null;return}let o=F(r);if(i===null){let e=o.findIndex(e=>e.trim()===`状态`);e!==-1&&!I(o)&&(i=e);return}if(I(o))return;let s=o[i]?.trim()??``;L(s,t)||n.push({file:e.relativePath,line:a+1,ruleId:`status-vocabulary`,message:`聚合表状态值「${s}」未命中词表,详细状态描述请归逐仓档`})}),n},F=e=>e.trim().replace(/^\|/u,``).replace(/\|$/u,``).split(`|`),I=e=>e.every(e=>/^[-: ]*$/.test(e.trim())),L=(e,t)=>N.has(e)||M.test(e)?!0:t.includes(e),R=[`/tmp/`,`/private/tmp/`,`/var/folders/`],z=(e,t,n)=>{let r=e.relativePath.startsWith(`${t}/`)?e.relativePath.slice(t.length+1):e.relativePath;if(_(r,n))return[];let i=[];return e.content.split(`
|
|
6
|
+
`).forEach((t,n)=>{let r=R.find(e=>t.includes(e));r!==void 0&&i.push({file:e.relativePath,line:n+1,ruleId:`temp-path`,message:`引用临时目录路径 ${r},临时产物路径不入台账`})}),i},B=(e,t)=>{let n=e.relativePath.startsWith(`${t.ledgersRoot}/`)?e.relativePath.slice(t.ledgersRoot.length+1):e.relativePath;if(_(n,t.sizeExemptGlobs))return[];let r=[],i=e.content.split(`
|
|
7
|
+
`).length,a=Buffer.byteLength(e.content,`utf8`);return i>t.maxWorkstreamLines&&r.push({file:e.relativePath,line:null,ruleId:`workstream-size`,message:`工作流档 ${i} 行超过上限 ${t.maxWorkstreamLines} 行,请拆分下沉`}),a>t.maxWorkstreamBytes&&r.push({file:e.relativePath,line:null,ruleId:`workstream-size`,message:`工作流档 ${a} 字节超过上限 ${t.maxWorkstreamBytes} 字节,请拆分下沉`}),r},V=e=>{let t=S(e.repoRoot,e.ledgersRoot),n=[];for(let r of t.indexFiles)n.push(...O(r,e.maxLineLength)),n.push(...D(r,e.ledgersRoot,e.hashExemptGlobs)),n.push(...k(r,e.repoRoot));for(let r of t.workstreamFiles)n.push(...B(r,{ledgersRoot:e.ledgersRoot,maxWorkstreamLines:e.maxWorkstreamLines,maxWorkstreamBytes:e.maxWorkstreamBytes,sizeExemptGlobs:e.sizeExemptGlobs}));for(let r of t.allFiles)r.relativePath.endsWith(`/ledger.md`)&&n.push(...P(r,e.statusVocabulary)),n.push(...z(r,e.ledgersRoot,e.tmpPathAllowGlobs));return n.sort((e,t)=>e.file===t.file?(e.line??0)-(t.line??0):e.file<t.file?-1:1),{violations:n,summary:{files:t.allFiles.length,indexFiles:t.indexFiles.length,errors:n.length}}},H=(e,t={})=>{let n=[];if(e.violations.length===0)return n.push(`台账形态门禁通过:扫描 ${e.summary.files} 份 markdown,索引位 ${e.summary.indexFiles} 份,零违例`),n.join(`
|
|
8
|
+
`);for(let t of e.violations){let e=t.line===null?t.file:`${t.file}:${t.line}`;n.push(`${e} [${t.ruleId}] ${t.message}`)}return t.rootLabel!==void 0&&n.push(`仓库根:${t.rootLabel}`),n.push(`台账形态门禁未通过:违例 ${e.summary.errors} 项,扫描 ${e.summary.files} 份 markdown,索引位 ${e.summary.indexFiles} 份`),n.join(`
|
|
9
|
+
`)};export{p as DEFAULT_LEDGERS_ROOT,u as DEFAULT_MAX_LINE_LENGTH,d as DEFAULT_MAX_WORKSTREAM_LINES,m as DEFAULT_STATUS_VOCABULARY,f as DEFAULT_WORKSTREAM_BYTES,D as checkCommitHash,O as checkLineWidth,k as checkLinkResolution,P as checkStatusVocabulary,z as checkTempPath,B as checkWorkstreamSize,S as collectLedgerFileSet,y as countLineLength,b as extractLinkTargets,H as formatLedgerCheckReport,C as isIndexFile,w as isWorkstreamFile,v as markFencedLines,_ as matchesAnyGlob,h as resolveLedgerCheckOptions,V as runLedgerCheck};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@longzai-intelligence-ledger/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Longzai Intelligence Ledger 台账形态校验引擎",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ledger",
|
|
7
|
+
"lint",
|
|
8
|
+
"longzai-intelligence",
|
|
9
|
+
"rules"
|
|
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
|
+
}
|