dsh-featherhunter-plugin-base 0.0.0-stage → 0.0.2-drill

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,1220 @@
1
+ // src/core/baseline.ts
2
+ var BASELINE = {
3
+ "manifest": {
4
+ "schema": 1,
5
+ "version": "0.0.2-drill",
6
+ "revision": 2,
7
+ "updatedAt": "2026-10-31T00:00:00+08:00",
8
+ "fallbackUrl": "https://github.com/FeatherHunter/featherhunter-plugin-manage",
9
+ "groups": [
10
+ {
11
+ "id": "feishu",
12
+ "platform": "feishu",
13
+ "order": 10,
14
+ "readmeTitle": {
15
+ "zh": "\u98DE\u4E66\u7FA4\uFF08\u4E3B\uFF09",
16
+ "en": "Feishu Group (Main)"
17
+ },
18
+ "alt": {
19
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4 \u98DE\u4E66\u7FA4\u4E8C\u7EF4\u7801",
20
+ "en": "DSH plugin community group Feishu QR code"
21
+ },
22
+ "card": "card-feishu.png",
23
+ "qr": {
24
+ "kind": "bundled",
25
+ "key": "qr-feishu"
26
+ },
27
+ "title": {
28
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
29
+ "en": "DSH Plugin Community"
30
+ },
31
+ "subtitle": {
32
+ "zh": "\u7528\u6237418832\u7684\u7EC4\u7EC7",
33
+ "en": "User 418832's organization"
34
+ },
35
+ "note": {
36
+ "zh": "\u8BE5\u4E8C\u7EF4\u7801\u6C38\u4E45\u6709\u6548",
37
+ "en": "This QR code never expires"
38
+ }
39
+ },
40
+ {
41
+ "id": "qq",
42
+ "platform": "qq",
43
+ "order": 20,
44
+ "readmeTitle": {
45
+ "zh": "QQ\u7FA4\uFF08\u65B0\uFF09",
46
+ "en": "QQ Group (New)"
47
+ },
48
+ "alt": {
49
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4 QQ \u7FA4\u4E8C\u7EF4\u7801",
50
+ "en": "DSH plugin community group QQ QR code"
51
+ },
52
+ "card": "card-qq.png",
53
+ "qr": {
54
+ "kind": "bundled",
55
+ "key": "qr-qq"
56
+ },
57
+ "title": {
58
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
59
+ "en": "DSH Plugin Community"
60
+ },
61
+ "subtitle": {
62
+ "zh": "\u7FA4\u53F7\uFF1A1020866453",
63
+ "en": "Group ID: 1020866453"
64
+ },
65
+ "note": {
66
+ "zh": "\u626B\u4E00\u626B\u4E8C\u7EF4\u7801\uFF0C\u52A0\u5165\u7FA4\u804A",
67
+ "en": "Scan the QR code to join the group chat"
68
+ }
69
+ },
70
+ {
71
+ "id": "wechat",
72
+ "platform": "wechat",
73
+ "order": 30,
74
+ "readmeTitle": {
75
+ "zh": "\u5FAE\u4FE1\u7FA4\uFF08\u65B0\uFF09",
76
+ "en": "WeChat Group (New)"
77
+ },
78
+ "alt": {
79
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4\u5FAE\u4FE1\u7FA4\u4E8C\u7EF4\u7801",
80
+ "en": "DSH plugin community group WeChat QR code"
81
+ },
82
+ "card": "card-wechat-2026-11-06.png",
83
+ "qr": {
84
+ "kind": "remote",
85
+ "path": "qr-wechat-2026-11-06.png"
86
+ },
87
+ "title": {
88
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
89
+ "en": "DSH Plugin Community"
90
+ },
91
+ "subtitle": {
92
+ "zh": "\u7FA4\u804A\uFF1ADSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
93
+ "en": "Group chat: DSH Plugin Community"
94
+ },
95
+ "validUntil": "2026-11-06"
96
+ }
97
+ ],
98
+ "plugins": [
99
+ {
100
+ "id": "deck",
101
+ "order": 10,
102
+ "verifiedAt": "2026-10-30",
103
+ "name": "dsh-mattpocock-skills-deck",
104
+ "repo": "FeatherHunter/dsh-mattpocock-skills-deck",
105
+ "desc": {
106
+ "zh": "\u8FD1 30 \u4E07 star \u7684 mattpocock/skills \u6574\u5957\u9884\u7F6E\u597D\uFF0827 \u4E2A\u6280\u80FD\uFF09\uFF0C\u88C5\u597D\u5373\u7528\u3002",
107
+ "en": "The whole mattpocock/skills set (nearly 300k stars) preinstalled \u2014 27 skills, ready as soon as it is installed."
108
+ },
109
+ "url": "https://github.com/FeatherHunter/dsh-mattpocock-skills-deck"
110
+ },
111
+ {
112
+ "id": "prompt",
113
+ "order": 20,
114
+ "verifiedAt": "2026-10-30",
115
+ "name": "dsh-prompt",
116
+ "repo": "FeatherHunter/dsh-prompt",
117
+ "desc": {
118
+ "zh": "\u7ECF\u5E38\u53CD\u590D\u91CD\u590D\u7684\u6A21\u677F\u5316\u63D0\u793A\u8BCD\uFF0C\u5B58\u6210\u81EA\u5B9A\u4E49\u6A21\u677F\uFF0C\u9009\u4E2D\u540E\u76F4\u63A5\u6CE8\u5165\uFF0C\u4E0D\u518D\u9700\u8981\u8017\u8D39\u7CBE\u529B\u3002",
119
+ "en": "The boilerplate prompts you keep retyping, saved as custom templates and injected on selection \u2014 no more wasted effort."
120
+ },
121
+ "url": "https://github.com/FeatherHunter/dsh-prompt"
122
+ },
123
+ {
124
+ "id": "palette",
125
+ "order": 30,
126
+ "verifiedAt": "2026-10-30",
127
+ "name": "dsh-opencode-palette",
128
+ "repo": "FeatherHunter/dsh-opencode-palette",
129
+ "desc": {
130
+ "zh": "38 \u6B3E opencode \u7ECF\u5178\u914D\u8272 + 20+\u81EA\u5B9A\u4E49\u4E3B\u9898 \u4E00\u952E\u6362\u88C5 DSH\u3002",
131
+ "en": "38 classic opencode themes + 20+ custom themes \u2014 reskin DSH in one click."
132
+ },
133
+ "url": "https://github.com/FeatherHunter/dsh-opencode-palette"
134
+ },
135
+ {
136
+ "id": "im",
137
+ "order": 40,
138
+ "verifiedAt": "2026-10-30",
139
+ "name": "dsh-im-companion",
140
+ "repo": "FeatherHunter/dsh-im-companion",
141
+ "desc": {
142
+ "zh": "\u7ED9 dsh-im \u52A0\u4E86\u300C\u52A9\u7406\u300D\u548C\u300C\u5BB6\u300D\u7684\u6982\u5FF5\u3002",
143
+ "en": "Adds the ideas of an \u201Cassistant\u201D and a \u201Chome\u201D to dsh-im."
144
+ },
145
+ "url": "https://github.com/FeatherHunter/dsh-im-companion"
146
+ },
147
+ {
148
+ "id": "ilife",
149
+ "order": 50,
150
+ "verifiedAt": "2026-10-30",
151
+ "name": "ilife",
152
+ "repo": "FeatherHunter/ilife",
153
+ "desc": {
154
+ "zh": "\u26A0\uFE0F\u5EFA\u8BBE\u4E2D\u26A0\uFE0F\u7231\u751F\u6D3B\uFF1A\u5C45\u5BB6\u751F\u6D3B\u5957\u4EF6\uFF0C\u8BB0\u8D26\u3001\u8FD0\u52A8\u3001\u996E\u98DF\u3001\u4F53\u91CD\u3001\u98DF\u8C31\u3001\u7269\u54C1\u7BA1\u7406\u3001\u4F5C\u606F\u89C4\u5212\u3001\u5907\u5FD8\u5F55\u7B49\u3002",
155
+ "en": "\u26A0\uFE0FWork in progress\u26A0\uFE0F iLife, the home-life suite: bookkeeping, exercise, diet, weight, recipes, item management, schedule planning, memos and more."
156
+ },
157
+ "url": "https://github.com/FeatherHunter/ilife"
158
+ }
159
+ ]
160
+ },
161
+ "qr": {
162
+ "qr-feishu": "data:image/png;base64,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",
163
+ "qr-qq": "data:image/png;base64,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"
164
+ }
165
+ };
166
+
167
+ // src/core/index.ts
168
+ var DAY_MS = 24 * 60 * 60 * 1e3;
169
+ function pickText(text, lang) {
170
+ if (!text) return "";
171
+ return text[lang] ?? text.zh ?? text.en ?? "";
172
+ }
173
+ function sortByOrder(items) {
174
+ return [...items].sort((a, b) => a.order - b.order);
175
+ }
176
+
177
+ // src/node/readme-sync.ts
178
+ import { randomBytes } from "node:crypto";
179
+ import {
180
+ chmodSync,
181
+ existsSync,
182
+ readFileSync,
183
+ renameSync,
184
+ statSync,
185
+ unlinkSync,
186
+ writeFileSync
187
+ } from "node:fs";
188
+ import { basename, dirname, join, resolve } from "node:path";
189
+
190
+ // src/node/readme-compare.ts
191
+ var MORE_HEADING = /\bMORE\b|作者的其他作品|More from the author|More by the author/i;
192
+ var THANKS_HEADING = /\bTHANKS\b|致谢|\bThanks\b|\bContributors\b/i;
193
+ var CONTACT_HEADING = /\bCONNECT\b|反馈与联系|Feedback and Contact/i;
194
+ var STAR_MARKER = /star-history[-a-z]*\.svg|star-history\.html|星标增长曲线|Star history chart/i;
195
+ var DIV_OPEN = /^\s*<div\b/i;
196
+ function headingKind(line) {
197
+ const trimmed = line.trim();
198
+ const isHtmlH2 = /^<h2\b/i.test(trimmed);
199
+ const isMarkdownH2 = /^##\s+/.test(trimmed) && !/^###/.test(trimmed);
200
+ if (!isHtmlH2 && !isMarkdownH2) return null;
201
+ if (MORE_HEADING.test(trimmed)) return "more";
202
+ if (THANKS_HEADING.test(trimmed)) return "thanks";
203
+ if (CONTACT_HEADING.test(trimmed)) return "contact";
204
+ return null;
205
+ }
206
+ function includeWrappingDiv(lines, start) {
207
+ let index = start - 1;
208
+ while (index >= 0 && lines[index].trim() === "") index -= 1;
209
+ if (index >= 0 && DIV_OPEN.test(lines[index])) return index;
210
+ return start;
211
+ }
212
+ function findStarBlockStart(lines, marker) {
213
+ for (let index = marker; index >= 0 && marker - index <= 8; index -= 1) {
214
+ if (DIV_OPEN.test(lines[index])) return index;
215
+ }
216
+ return marker;
217
+ }
218
+ function trimBlock(rawLines) {
219
+ const lines = [...rawLines];
220
+ while (lines.length > 0 && lines[0].trim() === "") lines.shift();
221
+ for (; ; ) {
222
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "") lines.pop();
223
+ if (lines.length > 0 && /^-{3,}$/.test(lines[lines.length - 1].trim())) {
224
+ lines.pop();
225
+ continue;
226
+ }
227
+ break;
228
+ }
229
+ return lines.join("\n");
230
+ }
231
+ function locateReadmeBlocks(markdown) {
232
+ const lines = markdown.split(/\r?\n/);
233
+ const candidates = [];
234
+ let inFence = false;
235
+ for (let index = 0; index < lines.length; index += 1) {
236
+ const line = lines[index];
237
+ if (/^\s*(?:```|~~~)/.test(line)) {
238
+ inFence = !inFence;
239
+ continue;
240
+ }
241
+ if (inFence) continue;
242
+ const kind = headingKind(line);
243
+ if (kind !== null) {
244
+ candidates.push({ kind, start: includeWrappingDiv(lines, index) });
245
+ continue;
246
+ }
247
+ if (STAR_MARKER.test(line)) {
248
+ candidates.push({ kind: "star-history", start: findStarBlockStart(lines, index) });
249
+ }
250
+ }
251
+ const seen = /* @__PURE__ */ new Set();
252
+ const ordered = [];
253
+ for (const candidate of candidates.sort((a, b) => a.start - b.start)) {
254
+ if (seen.has(candidate.kind)) continue;
255
+ seen.add(candidate.kind);
256
+ ordered.push(candidate);
257
+ }
258
+ const blocks = {
259
+ contact: null,
260
+ "star-history": null,
261
+ thanks: null,
262
+ more: null
263
+ };
264
+ const order = [];
265
+ for (let index = 0; index < ordered.length; index += 1) {
266
+ const candidate = ordered[index];
267
+ const end = index + 1 < ordered.length ? ordered[index + 1].start : lines.length;
268
+ blocks[candidate.kind] = trimBlock(lines.slice(candidate.start, end));
269
+ order.push(candidate.kind);
270
+ }
271
+ return { blocks, order, suspicious: findSuspiciousLines(markdown) };
272
+ }
273
+ var CONFLICT_START = /^\s*<{7}(?:\s|$)/;
274
+ var CONFLICT_SEPARATOR = /^\s*={7}\s*$/;
275
+ var CONFLICT_END = /^\s*>{7}(?:\s|$)/;
276
+ var MERGE_RESIDUE = /<{7}\s+\S|>{7}\s+\S/;
277
+ function findSuspiciousLines(markdown) {
278
+ const found = [];
279
+ markdown.split(/\r?\n/).forEach((line, index) => {
280
+ let reason = null;
281
+ if (CONFLICT_START.test(line)) reason = "conflict-start";
282
+ else if (CONFLICT_SEPARATOR.test(line)) reason = "conflict-separator";
283
+ else if (CONFLICT_END.test(line)) reason = "conflict-end";
284
+ else if (MERGE_RESIDUE.test(line)) reason = "merge-conflict-residue";
285
+ if (reason !== null) found.push({ line: index + 1, text: line, reason });
286
+ });
287
+ return found;
288
+ }
289
+ var NAMED_ENTITIES = {
290
+ amp: "&",
291
+ lt: "<",
292
+ gt: ">",
293
+ quot: '"',
294
+ apos: "'",
295
+ nbsp: " "
296
+ };
297
+ function decodeEntities(text) {
298
+ return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (entity, body) => {
299
+ if (body.startsWith("#x") || body.startsWith("#X")) {
300
+ const code = Number.parseInt(body.slice(2), 16);
301
+ return Number.isNaN(code) ? entity : String.fromCodePoint(code);
302
+ }
303
+ if (body.startsWith("#")) {
304
+ const code = Number.parseInt(body.slice(1), 10);
305
+ return Number.isNaN(code) ? entity : String.fromCodePoint(code);
306
+ }
307
+ return NAMED_ENTITIES[body.toLowerCase()] ?? entity;
308
+ });
309
+ }
310
+ function stripTags(html) {
311
+ let text = html.replace(/<!--[\s\S]*?-->/g, " ");
312
+ text = text.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
313
+ text = text.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1");
314
+ text = text.replace(/<[^>]+>/g, " ");
315
+ text = decodeEntities(text);
316
+ return text.replace(/\s+/g, " ").trim();
317
+ }
318
+ function parseAttributes(attributeText) {
319
+ const attributes = {};
320
+ const pattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>\`]+)))?/g;
321
+ let match;
322
+ while ((match = pattern.exec(attributeText)) !== null) {
323
+ const value = match[2] ?? match[3] ?? match[4] ?? "";
324
+ attributes[match[1].toLowerCase()] = decodeEntities(value);
325
+ }
326
+ return attributes;
327
+ }
328
+ function assetName(src) {
329
+ const clean = src.split(/[?#]/)[0].trim();
330
+ const segments = clean.split(/[\\/]+/).filter(Boolean);
331
+ return segments.length > 0 ? segments[segments.length - 1] : "";
332
+ }
333
+ function toWidth(value) {
334
+ if (value === void 0) return null;
335
+ const parsed = Number.parseInt(value, 10);
336
+ return Number.isNaN(parsed) ? null : parsed;
337
+ }
338
+ function parseHeading(raw) {
339
+ const html = /<h2\b[^>]*>([\s\S]*?)<\/h2>/i.exec(raw);
340
+ const markdown = /^##\s+(.+)$/m.exec(raw);
341
+ const inner = html !== null ? html[1] : markdown !== null ? markdown[1] : null;
342
+ if (inner === null) return null;
343
+ const subMatch = /<sub>([\s\S]*?)<\/sub>/i.exec(inner);
344
+ const sub = subMatch !== null ? stripTags(subMatch[1]) : null;
345
+ const text = stripTags(inner.replace(/<sub>[\s\S]*?<\/sub>/i, " "));
346
+ return { sub: sub !== null && sub !== "" ? sub : null, text };
347
+ }
348
+ function parseContactBlock(raw) {
349
+ const variant = /<h2\b/i.test(raw) ? "html-heading" : "markdown-heading";
350
+ const heading = parseHeading(raw);
351
+ const table = /<table\b[^>]*>([\s\S]*?)<\/table>/i.exec(raw);
352
+ const rows = table !== null ? [...table[1].matchAll(/<tr\b[^>]*>([\s\S]*?)<\/tr>/gi)] : [];
353
+ const titleRow = rows.find((row) => /<b\b/i.test(row[1]));
354
+ const imageRow = rows.find((row) => /<img\b/i.test(row[1]));
355
+ const titles = titleRow !== void 0 ? [...titleRow[1].matchAll(/<b\b[^>]*>([\s\S]*?)<\/b>/gi)].map((match) => stripTags(match[1])) : [];
356
+ const images = imageRow !== void 0 ? [...imageRow[1].matchAll(/<img\b([^>]*)>/gi)].map((match) => parseAttributes(match[1])) : [];
357
+ const groups = images.map((attributes, index) => {
358
+ const src = attributes.src ?? "";
359
+ return {
360
+ title: titles[index] ?? "",
361
+ src,
362
+ asset: assetName(src),
363
+ width: toWidth(attributes.width),
364
+ alt: attributes.alt ?? ""
365
+ };
366
+ });
367
+ let rest = raw;
368
+ const htmlHeading = /<h2\b[^>]*>[\s\S]*?<\/h2>/i.exec(rest);
369
+ if (htmlHeading !== null) rest = rest.replace(htmlHeading[0], " ");
370
+ else rest = rest.replace(/^##\s+.*$/m, " ");
371
+ rest = rest.replace(/<table\b[^>]*>[\s\S]*?<\/table>/gi, " ");
372
+ const welcome = stripTags(rest);
373
+ return { variant, heading, welcome: welcome === "" ? null : welcome, groups };
374
+ }
375
+ function firstSourceValue(attributes) {
376
+ const raw = attributes.srcset ?? attributes.src ?? "";
377
+ return raw.split(/[\s,]+/).filter(Boolean)[0] ?? "";
378
+ }
379
+ function sourceMedia(attributes) {
380
+ const media = attributes.media ?? "";
381
+ const match = /prefers-color-scheme:\s*(dark|light)/i.exec(media);
382
+ return match !== null ? match[1].toLowerCase() : null;
383
+ }
384
+ function toImage(attributes) {
385
+ const src = attributes.src ?? "";
386
+ return { alt: attributes.alt ?? "", src, asset: assetName(src), width: toWidth(attributes.width) };
387
+ }
388
+ function parseStarHistoryBlock(raw) {
389
+ const picture = /<picture\b[^>]*>([\s\S]*?)<\/picture>/i.exec(raw);
390
+ const imageTag = /<img\b([^>]*)>/i.exec(picture !== null ? picture[1] : raw);
391
+ let image = imageTag !== null ? toImage(parseAttributes(imageTag[1])) : null;
392
+ if (image === null) {
393
+ const markdownImage = /!\[([^\]]*)\]\(\s*([^)\s]+)/.exec(raw);
394
+ if (markdownImage !== null) {
395
+ const src = markdownImage[2];
396
+ image = { alt: markdownImage[1], src, asset: assetName(src), width: null };
397
+ }
398
+ }
399
+ const sources = [];
400
+ if (picture !== null) {
401
+ for (const match of picture[1].matchAll(/<source\b([^>]*)>/gi)) {
402
+ const attributes = parseAttributes(match[1]);
403
+ const src = firstSourceValue(attributes);
404
+ sources.push({ media: sourceMedia(attributes), src, asset: assetName(src) });
405
+ }
406
+ }
407
+ const linkTag = /<a\b[^>]*\bhref\s*=\s*["']([^"']+)["']/i.exec(raw);
408
+ const link = linkTag !== null ? decodeEntities(linkTag[1]) : null;
409
+ const sub = /<sub>([\s\S]*?)<\/sub>/i.exec(raw);
410
+ const caption = sub !== null ? stripTags(sub[1]) : null;
411
+ let variant;
412
+ if (picture !== null) variant = link !== null ? "picture-link" : "picture";
413
+ else if (/!\[[^\]]*\]\([^)]*\)/.test(raw)) variant = "markdown-image";
414
+ else variant = "unknown";
415
+ return {
416
+ variant,
417
+ link,
418
+ sources,
419
+ image,
420
+ caption: caption !== null && caption !== "" ? caption : null
421
+ };
422
+ }
423
+ function removeHeading(raw) {
424
+ const html = /<h2\b[^>]*>[\s\S]*?<\/h2>/i.exec(raw);
425
+ if (html !== null) return raw.replace(html[0], " ");
426
+ return raw.replace(/^##\s+.*$/m, " ");
427
+ }
428
+ function prose(lines) {
429
+ const text = stripTags(lines.filter((line) => !/^\s*-{3,}\s*$/.test(line)).join("\n"));
430
+ return text === "" ? null : text;
431
+ }
432
+ function splitTableRow(line) {
433
+ const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
434
+ const cells = [];
435
+ let buffer = "";
436
+ for (let index = 0; index < trimmed.length; index += 1) {
437
+ const character = trimmed[index];
438
+ if (character === "\\" && trimmed[index + 1] === "|") {
439
+ buffer += "|";
440
+ index += 1;
441
+ } else if (character === "|") {
442
+ cells.push(buffer);
443
+ buffer = "";
444
+ } else {
445
+ buffer += character;
446
+ }
447
+ }
448
+ cells.push(buffer);
449
+ return cells.map((cell) => cell.trim());
450
+ }
451
+ function isTableSeparator(line) {
452
+ return /^\s*\|?\s*:?-{3,}:?\s*\|?\s*(?:\|\s*:?-{3,}:?\s*)*\|?\s*$/.test(line);
453
+ }
454
+ function toThanksCell(rawCell) {
455
+ const links = [];
456
+ for (const match of rawCell.matchAll(/\[([^\]]*)\]\(([^)]*)\)/g)) links.push(match[2]);
457
+ return { text: stripTags(rawCell), links };
458
+ }
459
+ function parseThanksBlock(raw) {
460
+ const variant = /<h2\b/i.test(raw) ? "html-heading" : "markdown-heading";
461
+ const heading = parseHeading(raw);
462
+ const marker = /<!--\s*THANKS-TABLE-(ZH|EN)-START\s*-->/i.exec(raw);
463
+ const lang = marker !== null ? marker[1].toLowerCase() : null;
464
+ const tableLines = raw.split(/\r?\n/).filter((line) => /^\s*\|/.test(line));
465
+ const dataLines = tableLines.filter((line) => !isTableSeparator(line));
466
+ const headers = dataLines.length > 0 ? splitTableRow(dataLines[0]).map((cell) => stripTags(cell)) : [];
467
+ const rows = dataLines.slice(1).map((line) => ({ cells: splitTableRow(line).map(toThanksCell) }));
468
+ const body = removeHeading(raw);
469
+ const proseText = prose(body.split(/\r?\n/).filter((line) => !/^\s*\|/.test(line)));
470
+ return { variant, heading, lang, headers, rows, prose: proseText };
471
+ }
472
+ var MORE_ITEM = /^\s*\*\*\s*\[([^\]]+)\]\(([^)\s]+)\)\s*\*\*\s*(.*)$/;
473
+ function parseMoreBlock(raw) {
474
+ const variant = /<h2\b/i.test(raw) ? "html-heading" : "markdown-heading";
475
+ const heading = parseHeading(raw);
476
+ const lines = raw.split(/\r?\n/);
477
+ const itemIndexes = [];
478
+ const items = [];
479
+ lines.forEach((line, index) => {
480
+ const match = MORE_ITEM.exec(line);
481
+ if (match === null) return;
482
+ const description = match[3].replace(/^(?:——|—|--|-)\s*/, "").trim();
483
+ items.push({ name: stripTags(match[1]), url: match[2], description: stripTags(description) });
484
+ itemIndexes.push(index);
485
+ });
486
+ const headingRemoved = removeHeading(raw).split(/\r?\n/);
487
+ const firstItem = itemIndexes.length > 0 ? itemIndexes[0] : -1;
488
+ const lastItem = itemIndexes.length > 0 ? itemIndexes[itemIndexes.length - 1] : -1;
489
+ const intro = prose(headingRemoved.slice(0, firstItem === -1 ? headingRemoved.length : firstItem));
490
+ const footer = lastItem === -1 ? null : prose(headingRemoved.slice(lastItem + 1));
491
+ return { variant, heading, intro, items, footer };
492
+ }
493
+ var MARKUP_STAGES = [
494
+ "line-endings",
495
+ "whitespace",
496
+ "quotes",
497
+ "attribute-order",
498
+ "self-closing"
499
+ ];
500
+ var SELF_CLOSING_VOID = /<(img|source|br|hr|input|meta|link)\b([^>]*?)\s*\/>/gi;
501
+ function normalizeForCompare(value) {
502
+ if (value === void 0) return null;
503
+ if (Array.isArray(value)) return value.map(normalizeForCompare);
504
+ if (value !== null && typeof value === "object") {
505
+ const source = value;
506
+ const normalized = {};
507
+ for (const key of Object.keys(source).sort()) normalized[key] = normalizeForCompare(source[key]);
508
+ return normalized;
509
+ }
510
+ return value;
511
+ }
512
+ function sameValue(expected, actual) {
513
+ return JSON.stringify(normalizeForCompare(expected)) === JSON.stringify(normalizeForCompare(actual));
514
+ }
515
+ function pushDifference(differences, dimension, path, expected, actual) {
516
+ if (sameValue(expected, actual)) return;
517
+ differences.push({ dimension, path, expected, actual });
518
+ }
519
+ function canonicalTag(tag) {
520
+ const match = /^<([a-zA-Z][\w:-]*)((?:\s[^>]*?)?)\s*(\/?)>$/.exec(tag);
521
+ if (match === null) return tag;
522
+ const name = match[1];
523
+ const attributes = parseAttributes(match[2] ?? "");
524
+ const rebuilt = Object.keys(attributes).sort().map((key) => key + '="' + attributes[key] + '"').join(" ");
525
+ const selfClosing = match[3] === "/" ? " /" : "";
526
+ return "<" + name + (rebuilt === "" ? "" : " " + rebuilt) + selfClosing + ">";
527
+ }
528
+ function applyStage(text, stage) {
529
+ switch (stage) {
530
+ case "line-endings":
531
+ return text.replace(/\r\n?/g, "\n");
532
+ case "whitespace": {
533
+ const collapsedTags = text.replace(/<[a-zA-Z][^>]*>/g, (tag) => tag.replace(/\s+/g, " "));
534
+ const lines = collapsedTags.split(/\r?\n/).map((line) => line.replace(/[ \t]+/g, " ").trim()).filter((line) => line !== "");
535
+ return lines.join("\n").replace(/>\s*\n\s*</g, "><").trim();
536
+ }
537
+ case "quotes":
538
+ return text.replace(/<[a-zA-Z][^>]*>/g, (tag) => tag.replace(/([a-zA-Z-]+)\s*=\s*'([^']*)'/g, '$1="$2"'));
539
+ case "attribute-order":
540
+ return text.replace(/<[a-zA-Z][^>]*>/g, canonicalTag);
541
+ case "self-closing":
542
+ return text.replace(SELF_CLOSING_VOID, "<$1$2>");
543
+ }
544
+ }
545
+ function canonicalizeMarkup(markup) {
546
+ return MARKUP_STAGES.reduce((text, stage) => applyStage(text, stage), markup);
547
+ }
548
+ function detectFormatHints(expected, actual) {
549
+ const changed = [];
550
+ let expectedText = expected;
551
+ let actualText = actual;
552
+ for (const stage of MARKUP_STAGES) {
553
+ const nextExpected = applyStage(expectedText, stage);
554
+ const nextActual = applyStage(actualText, stage);
555
+ const stageChanged = nextExpected !== expectedText || nextActual !== actualText;
556
+ expectedText = nextExpected;
557
+ actualText = nextActual;
558
+ if (stageChanged) changed.push({ kind: stage });
559
+ if (expectedText === actualText) return changed;
560
+ }
561
+ return [{ kind: "markup" }];
562
+ }
563
+ function headingVariant(kind, raw) {
564
+ switch (kind) {
565
+ case "contact":
566
+ return parseContactBlock(raw).variant;
567
+ case "star-history":
568
+ return null;
569
+ case "thanks":
570
+ return parseThanksBlock(raw).variant;
571
+ case "more":
572
+ return parseMoreBlock(raw).variant;
573
+ }
574
+ }
575
+ function compareContactBlocks(expectedRaw, actualRaw, options) {
576
+ const expected = parseContactBlock(expectedRaw);
577
+ const actual = parseContactBlock(actualRaw);
578
+ const differences = [];
579
+ pushDifference(differences, "text", "contact.heading", expected.heading?.text ?? null, actual.heading?.text ?? null);
580
+ pushDifference(differences, "members", "contact.groups", expected.groups.length, actual.groups.length);
581
+ const count = Math.max(expected.groups.length, actual.groups.length);
582
+ for (let index = 0; index < count; index += 1) {
583
+ const expectedGroup = expected.groups[index];
584
+ const actualGroup = actual.groups[index];
585
+ const path = "contact.groups[" + index + "]";
586
+ if (expectedGroup === void 0 || actualGroup === void 0) {
587
+ pushDifference(differences, "members", path, expectedGroup ?? null, actualGroup ?? null);
588
+ continue;
589
+ }
590
+ pushDifference(differences, "text", path + ".title", expectedGroup.title, actualGroup.title);
591
+ pushDifference(differences, "text", path + ".alt", expectedGroup.alt, actualGroup.alt);
592
+ pushDifference(differences, "width", path + ".width", expectedGroup.width, actualGroup.width);
593
+ if (options.imageSrc === "exact") {
594
+ pushDifference(differences, "image", path + ".src", expectedGroup.src, actualGroup.src);
595
+ } else {
596
+ pushDifference(differences, "image", path + ".asset", expectedGroup.asset, actualGroup.asset);
597
+ }
598
+ }
599
+ return differences;
600
+ }
601
+ function sortedSources(sources) {
602
+ return [...sources].sort((left, right) => {
603
+ const byMedia = (left.media ?? "").localeCompare(right.media ?? "");
604
+ return byMedia !== 0 ? byMedia : left.asset.localeCompare(right.asset);
605
+ });
606
+ }
607
+ function compareStarHistoryBlocks(expectedRaw, actualRaw, options) {
608
+ const expected = parseStarHistoryBlock(expectedRaw);
609
+ const actual = parseStarHistoryBlock(actualRaw);
610
+ const differences = [];
611
+ pushDifference(differences, "links", "star-history.link", expected.link, actual.link);
612
+ if (expected.image === null || actual.image === null) {
613
+ pushDifference(
614
+ differences,
615
+ "image",
616
+ "star-history.image",
617
+ expected.image === null ? null : "present",
618
+ actual.image === null ? null : "present"
619
+ );
620
+ } else {
621
+ pushDifference(differences, "text", "star-history.image.alt", expected.image.alt, actual.image.alt);
622
+ pushDifference(differences, "width", "star-history.image.width", expected.image.width, actual.image.width);
623
+ if (options.imageSrc === "exact") {
624
+ pushDifference(differences, "image", "star-history.image.src", expected.image.src, actual.image.src);
625
+ } else {
626
+ pushDifference(differences, "image", "star-history.image.asset", expected.image.asset, actual.image.asset);
627
+ }
628
+ }
629
+ const expectedSources = sortedSources(expected.sources);
630
+ const actualSources = sortedSources(actual.sources);
631
+ if (expectedSources.length !== actualSources.length) {
632
+ pushDifference(
633
+ differences,
634
+ "image",
635
+ "star-history.sources",
636
+ expectedSources.map((source) => [source.media, source.asset]),
637
+ actualSources.map((source) => [source.media, source.asset])
638
+ );
639
+ } else {
640
+ expectedSources.forEach((source, index) => {
641
+ const actualSource = actualSources[index];
642
+ pushDifference(differences, "image", "star-history.sources[" + index + "].media", source.media, actualSource.media);
643
+ if (options.imageSrc === "exact") {
644
+ pushDifference(differences, "image", "star-history.sources[" + index + "].src", source.src, actualSource.src);
645
+ } else {
646
+ pushDifference(differences, "image", "star-history.sources[" + index + "].asset", source.asset, actualSource.asset);
647
+ }
648
+ });
649
+ }
650
+ pushDifference(differences, "text", "star-history.caption", expected.caption, actual.caption);
651
+ return differences;
652
+ }
653
+ function compareThanksBlocks(expectedRaw, actualRaw) {
654
+ const expected = parseThanksBlock(expectedRaw);
655
+ const actual = parseThanksBlock(actualRaw);
656
+ const differences = [];
657
+ pushDifference(differences, "text", "thanks.heading", expected.heading?.text ?? null, actual.heading?.text ?? null);
658
+ pushDifference(differences, "table", "thanks.headers", expected.headers, actual.headers);
659
+ const headerCount = Math.max(expected.headers.length, actual.headers.length);
660
+ for (let index = 0; index < headerCount; index += 1) {
661
+ pushDifference(differences, "table", "thanks.headers[" + index + "]", expected.headers[index] ?? null, actual.headers[index] ?? null);
662
+ }
663
+ pushDifference(differences, "table", "thanks.rows", expected.rows.length, actual.rows.length);
664
+ const rowCount = Math.max(expected.rows.length, actual.rows.length);
665
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
666
+ const expectedRow = expected.rows[rowIndex];
667
+ const actualRow = actual.rows[rowIndex];
668
+ const rowPath = "thanks.rows[" + rowIndex + "]";
669
+ if (expectedRow === void 0 || actualRow === void 0) {
670
+ pushDifference(differences, "table", rowPath, expectedRow ?? null, actualRow ?? null);
671
+ continue;
672
+ }
673
+ pushDifference(differences, "table", rowPath + ".cells", expectedRow.cells.length, actualRow.cells.length);
674
+ const cellCount = Math.max(expectedRow.cells.length, actualRow.cells.length);
675
+ for (let cellIndex = 0; cellIndex < cellCount; cellIndex += 1) {
676
+ const expectedCell = expectedRow.cells[cellIndex];
677
+ const actualCell = actualRow.cells[cellIndex];
678
+ const cellPath = rowPath + ".cells[" + cellIndex + "]";
679
+ if (expectedCell === void 0 || actualCell === void 0) {
680
+ pushDifference(differences, "table", cellPath, expectedCell ?? null, actualCell ?? null);
681
+ continue;
682
+ }
683
+ pushDifference(differences, "table", cellPath + ".text", expectedCell.text, actualCell.text);
684
+ pushDifference(differences, "links", cellPath + ".links", expectedCell.links, actualCell.links);
685
+ const linkCount = Math.max(expectedCell.links.length, actualCell.links.length);
686
+ for (let linkIndex = 0; linkIndex < linkCount; linkIndex += 1) {
687
+ pushDifference(
688
+ differences,
689
+ "links",
690
+ cellPath + ".links[" + linkIndex + "]",
691
+ expectedCell.links[linkIndex] ?? null,
692
+ actualCell.links[linkIndex] ?? null
693
+ );
694
+ }
695
+ }
696
+ }
697
+ return differences;
698
+ }
699
+ function compareMoreBlocks(expectedRaw, actualRaw) {
700
+ const expected = parseMoreBlock(expectedRaw);
701
+ const actual = parseMoreBlock(actualRaw);
702
+ const differences = [];
703
+ pushDifference(differences, "text", "more.heading", expected.heading?.text ?? null, actual.heading?.text ?? null);
704
+ const expectedNames = expected.items.map((item) => item.name);
705
+ const actualNames = actual.items.map((item) => item.name);
706
+ const expectedSorted = [...expectedNames].sort();
707
+ const actualSorted = [...actualNames].sort();
708
+ const sameMemberSet = sameValue(expectedSorted, actualSorted);
709
+ const sameOrder = sameValue(expectedNames, actualNames);
710
+ if (!sameOrder) {
711
+ if (sameMemberSet) {
712
+ pushDifference(differences, "members", "more.items", expectedNames, actualNames);
713
+ return differences;
714
+ }
715
+ pushDifference(differences, "members", "more.items", expectedNames, actualNames);
716
+ }
717
+ const count = Math.max(expected.items.length, actual.items.length);
718
+ for (let index = 0; index < count; index += 1) {
719
+ const expectedItem = expected.items[index];
720
+ const actualItem = actual.items[index];
721
+ const path = "more.items[" + index + "]";
722
+ if (expectedItem === void 0 || actualItem === void 0) {
723
+ pushDifference(differences, "members", path, expectedItem ?? null, actualItem ?? null);
724
+ continue;
725
+ }
726
+ pushDifference(differences, "text", path + ".name", expectedItem.name, actualItem.name);
727
+ pushDifference(differences, "links", path + ".url", expectedItem.url, actualItem.url);
728
+ pushDifference(differences, "text", path + ".description", expectedItem.description, actualItem.description);
729
+ }
730
+ return differences;
731
+ }
732
+ function compareBlockContent(kind, expectedRaw, actualRaw, options) {
733
+ switch (kind) {
734
+ case "contact":
735
+ return compareContactBlocks(expectedRaw, actualRaw, options);
736
+ case "star-history":
737
+ return compareStarHistoryBlocks(expectedRaw, actualRaw, options);
738
+ case "thanks":
739
+ return compareThanksBlocks(expectedRaw, actualRaw);
740
+ case "more":
741
+ return compareMoreBlocks(expectedRaw, actualRaw);
742
+ }
743
+ }
744
+ function compareBlocks(kind, expectedRaw, actualRaw, options = {}) {
745
+ if (expectedRaw === null && actualRaw === null) {
746
+ return { kind, identical: true, equivalent: true, contentDifferences: [], formatDifferences: [] };
747
+ }
748
+ if (expectedRaw === null || actualRaw === null) {
749
+ return {
750
+ kind,
751
+ identical: false,
752
+ equivalent: false,
753
+ contentDifferences: [
754
+ {
755
+ dimension: "presence",
756
+ path: kind,
757
+ expected: expectedRaw === null ? null : "present",
758
+ actual: actualRaw === null ? null : "present"
759
+ }
760
+ ],
761
+ formatDifferences: []
762
+ };
763
+ }
764
+ const contentDifferences = compareBlockContent(kind, expectedRaw, actualRaw, options);
765
+ const identical = expectedRaw === actualRaw;
766
+ let formatDifferences = [];
767
+ if (!identical && contentDifferences.length === 0) {
768
+ formatDifferences = detectFormatHints(expectedRaw, actualRaw);
769
+ const expectedVariant = headingVariant(kind, expectedRaw);
770
+ const actualVariant = headingVariant(kind, actualRaw);
771
+ if (expectedVariant !== null && actualVariant !== null && expectedVariant !== actualVariant) {
772
+ formatDifferences = [{ kind: "heading-variant" }, ...formatDifferences.filter((entry) => entry.kind !== "heading-variant")];
773
+ }
774
+ }
775
+ return { kind, identical, equivalent: contentDifferences.length === 0, contentDifferences, formatDifferences };
776
+ }
777
+ var BLOCK_KINDS = ["contact", "star-history", "thanks", "more"];
778
+ function compareReadmeBlocks(expected, actual, options = {}) {
779
+ const expectedLocated = typeof expected === "string" ? locateReadmeBlocks(expected) : expected;
780
+ const actualLocated = typeof actual === "string" ? locateReadmeBlocks(actual) : actual;
781
+ const blocks = {};
782
+ const contentDifferences = [];
783
+ const formatDifferences = [];
784
+ for (const kind of BLOCK_KINDS) {
785
+ const comparison = compareBlocks(kind, expectedLocated.blocks[kind], actualLocated.blocks[kind], options);
786
+ blocks[kind] = comparison;
787
+ contentDifferences.push(...comparison.contentDifferences);
788
+ for (const difference of comparison.formatDifferences) formatDifferences.push({ ...difference, block: kind });
789
+ }
790
+ return {
791
+ equivalent: contentDifferences.length === 0,
792
+ blocks,
793
+ contentDifferences,
794
+ formatDifferences,
795
+ order: {
796
+ expected: expectedLocated.order,
797
+ actual: actualLocated.order,
798
+ same: sameValue(expectedLocated.order, actualLocated.order)
799
+ },
800
+ suspicious: actualLocated.suspicious
801
+ };
802
+ }
803
+
804
+ // src/node/renderers.ts
805
+ var DEFAULT_CDN_BASE = "https://cdn.jsdelivr.net/npm/dsh-featherhunter-plugin-base";
806
+ var CONTACT_CARD_WIDTH = 260;
807
+ var CONTACT_TEXT = {
808
+ sub: "CONNECT",
809
+ heading: {
810
+ zh: "\u53CD\u9988\u4E0E\u8054\u7CFB",
811
+ en: "Feedback and Contact"
812
+ },
813
+ welcome: {
814
+ zh: "\u{1F44F}\u6B22\u8FCE\u63D0\u4EA4PR\u3001ISSUE\u3002\u661F\u661F\u4E4B\u706B\u53EF\u4EE5\u71CE\u539F\u{1F525}\u6709\u4EFB\u4F55\u5EFA\u8BAE\u3001\u610F\u89C1\u3001\u60F3\u6CD5\u3001\u5410\u69FD\u3001idea\u90FD\u53EF\u4EE5\u8FDB\u7FA4\u4EA4\u6D41\u3002",
815
+ en: "\u{1F44F}Welcome PRs and issues. A single spark can start a prairie fire \u{1F525}. Any suggestion, opinion, idea or rant \u2014 come join the group and talk."
816
+ }
817
+ };
818
+ var DATE_IN_FILENAME = /(\d{4})-(\d{2})-(\d{2})/;
819
+ var DATE_IN_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})/;
820
+ function resolveManifest(options) {
821
+ return options.manifest ?? BASELINE.manifest;
822
+ }
823
+ function resolveLang(options) {
824
+ return options.lang ?? "zh";
825
+ }
826
+ function escapeAttribute(value) {
827
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
828
+ }
829
+ function contactCardCacheDate(group, manifest) {
830
+ const fromCard = DATE_IN_FILENAME.exec(group.card);
831
+ if (fromCard !== null) return fromCard[1] + fromCard[2] + fromCard[3];
832
+ if (group.validUntil === void 0) return null;
833
+ const fromManifest = DATE_IN_TIMESTAMP.exec(manifest.updatedAt);
834
+ if (fromManifest === null) {
835
+ throw new Error(
836
+ "manifest.updatedAt must start with YYYY-MM-DD when a group has validUntil (group: " + group.id + ")"
837
+ );
838
+ }
839
+ return fromManifest[1] + fromManifest[2] + fromManifest[3];
840
+ }
841
+ function contactCardUrl(group, manifest, options = {}) {
842
+ const base = (options.cdnBase ?? DEFAULT_CDN_BASE).replace(/\/+$/, "");
843
+ if (!/^https:\/\/[^\s"'<>]+$/i.test(base)) {
844
+ throw new Error('contact CDN base must be an absolute https URL (got "' + base + '")');
845
+ }
846
+ const card = group.card.trim();
847
+ if (card === "") throw new Error('contact group "' + group.id + '" has an empty card file name');
848
+ if (card.includes("/") || card.includes("\\") || /^[a-z]+:/i.test(card)) {
849
+ throw new Error('contact card must be a bare file name under data/img/ (got "' + card + '")');
850
+ }
851
+ const version = options.version ?? manifest.version;
852
+ if (version === "") throw new Error("contact CDN URL needs a manifest version");
853
+ let url = base + "@" + version + "/data/img/" + card;
854
+ const cacheDate = contactCardCacheDate(group, manifest);
855
+ if (cacheDate !== null) url += "?v=" + cacheDate;
856
+ return url;
857
+ }
858
+ function contactHeading(lang, options) {
859
+ const text = CONTACT_TEXT.heading[lang];
860
+ if (options.variant === "markdown-heading") return "## " + text;
861
+ return '<h2 align="center"><sub>' + CONTACT_TEXT.sub + "</sub><br>" + text + "</h2>";
862
+ }
863
+ function renderContactBlock(options = {}) {
864
+ const manifest = resolveManifest(options);
865
+ const lang = resolveLang(options);
866
+ const groups = sortByOrder(manifest.groups);
867
+ if (groups.length === 0) throw new Error("contact block needs at least one group in the manifest");
868
+ const headerCells = groups.map((group) => '<td align="center"><b>' + escapeAttribute(pickText(group.readmeTitle, lang)) + "</b></td>").join("");
869
+ const cardCells = groups.map((group) => {
870
+ const src = contactCardUrl(group, manifest, options);
871
+ const alt = escapeAttribute(pickText(group.alt, lang));
872
+ return '<td><img src="' + src + '" width="' + CONTACT_CARD_WIDTH + '" alt="' + alt + '" /></td>';
873
+ }).join("");
874
+ return [
875
+ contactHeading(lang, options),
876
+ "",
877
+ '<div align="center">',
878
+ "",
879
+ CONTACT_TEXT.welcome[lang],
880
+ "",
881
+ '<table align="center"><tr>' + headerCells + "</tr><tr>" + cardCells + "</tr></table>",
882
+ "",
883
+ "</div>"
884
+ ].join("\n");
885
+ }
886
+
887
+ // src/node/readme-sync.ts
888
+ var THANKS_ZH_MARKERS = {
889
+ start: "<!-- THANKS-TABLE-ZH-START -->",
890
+ end: "<!-- THANKS-TABLE-ZH-END -->"
891
+ };
892
+ var THANKS_EN_MARKERS = {
893
+ start: "<!-- THANKS-TABLE-EN-START -->",
894
+ end: "<!-- THANKS-TABLE-EN-END -->"
895
+ };
896
+ var BLOCK_MARKERS = {
897
+ contact: { start: "<!-- CONTACT-START -->", end: "<!-- CONTACT-END -->" },
898
+ more: { start: "<!-- MORE-START -->", end: "<!-- MORE-END -->" },
899
+ starHistory: { start: "<!-- STAR-HISTORY-START -->", end: "<!-- STAR-HISTORY-END -->" },
900
+ thanks: {
901
+ ...THANKS_ZH_MARKERS,
902
+ zh: THANKS_ZH_MARKERS,
903
+ en: THANKS_EN_MARKERS
904
+ }
905
+ };
906
+ function detectContact(raw) {
907
+ const parsed = parseContactBlock(raw);
908
+ const heading = parsed.heading?.text ?? "";
909
+ const lang = /[A-Za-z]/.test(heading) ? "en" : "zh";
910
+ const variant = parsed.variant === "markdown-heading" ? "markdown-heading" : "html-heading";
911
+ return { lang, variant };
912
+ }
913
+ function locateLegacyContact(markdown) {
914
+ const headingPattern = /^(?:<h2\b[^\n]*?(?:CONNECT|反馈与联系|Feedback and Contact)[^\n]*?|<sub>\s*CONNECT\s*<\/sub>[^\n]*?|<h2\b[^\n]*?>[^\n]*?(?:反馈与联系|Feedback and Contact)[^\n]*?>|##\s+[^\n]*(?:反馈与联系|Feedback and Contact)[^\n]*)\s*$/im;
915
+ const heading = headingPattern.exec(markdown);
916
+ if (heading === null) return null;
917
+ const start = heading.index;
918
+ const closingDiv = /^[ \t]*<\/div>[ \t]*$/m;
919
+ const rest = markdown.slice(start + heading[0].length);
920
+ const closing = closingDiv.exec(rest);
921
+ if (closing === null) return null;
922
+ return { start, end: start + heading[0].length + closing.index + closing[0].length };
923
+ }
924
+ var BLOCK_DEFINITIONS = [
925
+ {
926
+ name: "contact",
927
+ label: "contact",
928
+ markers: [{ start: BLOCK_MARKERS.contact.start, end: BLOCK_MARKERS.contact.end }],
929
+ render: (context) => renderContactBlock(context),
930
+ locateLegacy: locateLegacyContact,
931
+ detect: detectContact
932
+ },
933
+ // Reserved for ticket 09: renderer + legacy anchor for the author-plugins
934
+ // (MORE) block. Marker pair is fixed now so init/sync never invents one.
935
+ {
936
+ name: "more",
937
+ label: "more",
938
+ markers: [{ start: BLOCK_MARKERS.more.start, end: BLOCK_MARKERS.more.end }]
939
+ },
940
+ // Reserved for ticket 10.
941
+ {
942
+ name: "star-history",
943
+ label: "star-history",
944
+ markers: [{ start: BLOCK_MARKERS.starHistory.start, end: BLOCK_MARKERS.starHistory.end }]
945
+ },
946
+ // Reserved for ticket 10. One marker pair per language; which pair exists
947
+ // tells the language of the README.
948
+ {
949
+ name: "thanks",
950
+ label: "thanks",
951
+ markers: [
952
+ { lang: "zh", start: THANKS_ZH_MARKERS.start, end: THANKS_ZH_MARKERS.end },
953
+ { lang: "en", start: THANKS_EN_MARKERS.start, end: THANKS_EN_MARKERS.end }
954
+ ]
955
+ }
956
+ ];
957
+ function blockDefinition(name) {
958
+ return BLOCK_DEFINITIONS.find((definition) => definition.name === name);
959
+ }
960
+ function implementedBlockDefinitions() {
961
+ return BLOCK_DEFINITIONS.filter((definition) => definition.render !== void 0);
962
+ }
963
+ function writeFileAtomic(filePath, content, hooks = {}) {
964
+ const directory = dirname(filePath);
965
+ const tempPath = join(
966
+ directory,
967
+ "." + basename(filePath) + "." + process.pid + "." + randomBytes(6).toString("hex") + ".tmp"
968
+ );
969
+ let mode;
970
+ try {
971
+ mode = statSync(filePath).mode & 511;
972
+ } catch {
973
+ mode = void 0;
974
+ }
975
+ try {
976
+ writeFileSync(tempPath, content, "utf8");
977
+ if (mode !== void 0) chmodSync(tempPath, mode);
978
+ hooks.beforeRename?.(tempPath);
979
+ renameSync(tempPath, filePath);
980
+ } catch (error) {
981
+ try {
982
+ if (existsSync(tempPath)) unlinkSync(tempPath);
983
+ } catch {
984
+ }
985
+ throw error;
986
+ }
987
+ }
988
+ function detectLineEnding(markdown) {
989
+ return markdown.includes("\r\n") ? "\r\n" : "\n";
990
+ }
991
+ function markerIndexes(markdown, token) {
992
+ const indexes = [];
993
+ let from = 0;
994
+ for (; ; ) {
995
+ const index = markdown.indexOf(token, from);
996
+ if (index === -1) return indexes;
997
+ indexes.push(index);
998
+ from = index + token.length;
999
+ }
1000
+ }
1001
+ function renderSegment(definition, markerSet, context) {
1002
+ if (definition.render === void 0) throw new Error("block has no renderer: " + definition.name);
1003
+ return definition.render({ ...context, lang: markerSet.lang ?? context.lang });
1004
+ }
1005
+ function applyMarkerSet(markdown, definition, markerSet, context, command) {
1006
+ const errors = [];
1007
+ const { start, end } = markerSet;
1008
+ const starts = markerIndexes(markdown, start);
1009
+ const ends = markerIndexes(markdown, end);
1010
+ const eol = detectLineEnding(markdown);
1011
+ if (starts.length === 0 && ends.length === 0) {
1012
+ if (definition.render === void 0) {
1013
+ return { markdown, changed: false, status: "skipped", errors };
1014
+ }
1015
+ if (command === "sync") {
1016
+ errors.push(definition.label + " markers are missing; run readme:init first");
1017
+ return { markdown, changed: false, status: "skipped", errors };
1018
+ }
1019
+ const legacy = definition.locateLegacy?.(markdown) ?? null;
1020
+ if (legacy === null) {
1021
+ errors.push(
1022
+ "cannot locate the legacy " + definition.label + " block; add " + start + " / " + end + " markers manually"
1023
+ );
1024
+ return { markdown, changed: false, status: "skipped", errors };
1025
+ }
1026
+ const content = renderSegment(definition, markerSet, context).split(/\r?\n/).join(eol);
1027
+ const replacement = start + eol + content + eol + end;
1028
+ return {
1029
+ markdown: markdown.slice(0, legacy.start) + replacement + markdown.slice(legacy.end),
1030
+ changed: true,
1031
+ status: "inserted",
1032
+ errors
1033
+ };
1034
+ }
1035
+ if (starts.length === 1 && ends.length === 1 && starts[0] < ends[0]) {
1036
+ if (definition.render === void 0) {
1037
+ return { markdown, changed: false, status: "skipped", errors };
1038
+ }
1039
+ const startIndex = starts[0];
1040
+ const endIndex = ends[0];
1041
+ const inner = markdown.slice(startIndex + start.length, endIndex);
1042
+ const content = renderSegment(definition, markerSet, context).split(/\r?\n/).join(eol);
1043
+ const expectedInner = eol + content + eol;
1044
+ if (inner === expectedInner) {
1045
+ return { markdown, changed: false, status: "unchanged", errors };
1046
+ }
1047
+ const next = markdown.slice(0, startIndex + start.length) + expectedInner + markdown.slice(endIndex);
1048
+ return { markdown: next, changed: true, status: "updated", errors };
1049
+ }
1050
+ if (starts.length > 1 || ends.length > 1) {
1051
+ errors.push(
1052
+ "duplicate " + definition.label + " markers (" + start + " x" + starts.length + ", " + end + " x" + ends.length + "); refusing to guess"
1053
+ );
1054
+ } else if (starts.length !== ends.length) {
1055
+ errors.push(
1056
+ "unpaired " + definition.label + " markers (" + start + " x" + starts.length + ", " + end + " x" + ends.length + ")"
1057
+ );
1058
+ } else {
1059
+ errors.push("end marker appears before start marker for the " + definition.label + " block");
1060
+ }
1061
+ return { markdown, changed: false, status: "skipped", errors };
1062
+ }
1063
+ function detectContext(markdown, options) {
1064
+ let lang = options.lang;
1065
+ let variant = options.variant;
1066
+ for (const definition of BLOCK_DEFINITIONS) {
1067
+ if (definition.detect === void 0) continue;
1068
+ let raw = null;
1069
+ for (const markerSet of definition.markers) {
1070
+ const starts = markerIndexes(markdown, markerSet.start);
1071
+ const ends = markerIndexes(markdown, markerSet.end);
1072
+ if (starts.length === 1 && ends.length === 1 && starts[0] < ends[0]) {
1073
+ raw = markdown.slice(starts[0] + markerSet.start.length, ends[0]);
1074
+ break;
1075
+ }
1076
+ }
1077
+ if (raw === null) {
1078
+ const legacy = definition.locateLegacy?.(markdown) ?? null;
1079
+ if (legacy !== null) raw = markdown.slice(legacy.start, legacy.end);
1080
+ }
1081
+ if (raw === null) continue;
1082
+ const detected = definition.detect(raw);
1083
+ lang ??= detected.lang;
1084
+ variant ??= detected.variant;
1085
+ }
1086
+ return {
1087
+ manifest: options.manifest,
1088
+ version: options.version,
1089
+ cdnBase: options.cdnBase,
1090
+ lang: lang ?? "zh",
1091
+ variant
1092
+ };
1093
+ }
1094
+ function updateReadme(options) {
1095
+ const readmePath = resolve(options.root, options.readme ?? "README.md");
1096
+ const command = options.command ?? "sync";
1097
+ const result = {
1098
+ readmePath,
1099
+ ok: false,
1100
+ changed: false,
1101
+ written: false,
1102
+ blocks: [],
1103
+ errors: []
1104
+ };
1105
+ let markdown;
1106
+ try {
1107
+ markdown = readFileSync(readmePath, "utf8");
1108
+ } catch (error) {
1109
+ const code = error.code;
1110
+ result.errors.push(
1111
+ code === "ENOENT" ? "README not found: " + readmePath : "cannot read " + readmePath + ": " + error.message
1112
+ );
1113
+ return result;
1114
+ }
1115
+ const suspicious = findSuspiciousLines(markdown);
1116
+ if (suspicious.length > 0) {
1117
+ for (const line of suspicious) {
1118
+ result.errors.push(
1119
+ readmePath + ":" + line.line + ": suspicious merge-conflict residue (" + line.reason + '): "' + line.text + '"; refusing to modify the README, fix it manually first'
1120
+ );
1121
+ }
1122
+ return result;
1123
+ }
1124
+ const context = detectContext(markdown, options);
1125
+ let next = markdown;
1126
+ for (const definition of implementedBlockDefinitions()) {
1127
+ for (const markerSet of definition.markers) {
1128
+ const applied = applyMarkerSet(next, definition, markerSet, context, command);
1129
+ next = applied.markdown;
1130
+ result.blocks.push({ name: definition.name, status: applied.status });
1131
+ for (const error of applied.errors) result.errors.push(readmePath + ": " + error);
1132
+ }
1133
+ }
1134
+ if (result.errors.length > 0) return result;
1135
+ result.changed = next !== markdown;
1136
+ if (options.check === true) {
1137
+ if (result.changed) {
1138
+ result.errors.push(
1139
+ readmePath + ": managed blocks are out of date; run readme:" + command + " to fix"
1140
+ );
1141
+ return result;
1142
+ }
1143
+ result.ok = true;
1144
+ return result;
1145
+ }
1146
+ if (result.changed) {
1147
+ writeFileAtomic(readmePath, next);
1148
+ result.written = true;
1149
+ }
1150
+ result.ok = true;
1151
+ return result;
1152
+ }
1153
+ function updateReadmes(options) {
1154
+ const files = options.roots.map(
1155
+ (root) => updateReadme({
1156
+ root,
1157
+ command: options.command ?? "sync",
1158
+ check: options.check,
1159
+ manifest: options.manifest,
1160
+ version: options.version,
1161
+ cdnBase: options.cdnBase,
1162
+ lang: options.lang,
1163
+ variant: options.variant
1164
+ })
1165
+ );
1166
+ return { ok: files.every((file) => file.ok), files };
1167
+ }
1168
+
1169
+ // src/node/index.ts
1170
+ function renderStarHistoryBlock(options = {}) {
1171
+ return [BLOCK_MARKERS.starHistory.start, "", BLOCK_MARKERS.starHistory.end].join("\n");
1172
+ }
1173
+ function renderThanksBlock(options = {}) {
1174
+ return [BLOCK_MARKERS.thanks.start, "", BLOCK_MARKERS.thanks.end].join("\n");
1175
+ }
1176
+ function renderMoreBlock(options = {}) {
1177
+ return [BLOCK_MARKERS.more.start, "", BLOCK_MARKERS.more.end].join("\n");
1178
+ }
1179
+ function verifyBlock(block, name) {
1180
+ const markers = BLOCK_MARKERS[name];
1181
+ const errors = [];
1182
+ if (!block.includes(markers.start)) errors.push(`missing start marker for ${name}`);
1183
+ if (!block.includes(markers.end)) errors.push(`missing end marker for ${name}`);
1184
+ return { ok: errors.length === 0, errors };
1185
+ }
1186
+ function sortedPlugins(manifest, selfId) {
1187
+ return sortByOrder(manifest.plugins).filter((plugin) => plugin.id !== selfId);
1188
+ }
1189
+ export {
1190
+ BLOCK_DEFINITIONS,
1191
+ BLOCK_MARKERS,
1192
+ CONTACT_CARD_WIDTH,
1193
+ CONTACT_TEXT,
1194
+ DEFAULT_CDN_BASE,
1195
+ assetName,
1196
+ blockDefinition,
1197
+ canonicalizeMarkup,
1198
+ compareBlocks,
1199
+ compareReadmeBlocks,
1200
+ contactCardCacheDate,
1201
+ contactCardUrl,
1202
+ findSuspiciousLines,
1203
+ implementedBlockDefinitions,
1204
+ locateReadmeBlocks,
1205
+ parseAttributes,
1206
+ parseContactBlock,
1207
+ parseHeading,
1208
+ parseMoreBlock,
1209
+ parseStarHistoryBlock,
1210
+ parseThanksBlock,
1211
+ renderContactBlock,
1212
+ renderMoreBlock,
1213
+ renderStarHistoryBlock,
1214
+ renderThanksBlock,
1215
+ sortedPlugins,
1216
+ updateReadme,
1217
+ updateReadmes,
1218
+ verifyBlock,
1219
+ writeFileAtomic
1220
+ };