@bfra.me/doc-sync 0.1.0

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.
Files changed (50) hide show
  1. package/README.md +288 -0
  2. package/lib/chunk-6NKAJT2M.js +1233 -0
  3. package/lib/chunk-DR6UG237.js +1027 -0
  4. package/lib/chunk-G5KKGJYO.js +1560 -0
  5. package/lib/chunk-ROLA7SBB.js +12 -0
  6. package/lib/cli/index.d.ts +1 -0
  7. package/lib/cli/index.js +397 -0
  8. package/lib/generators/index.d.ts +170 -0
  9. package/lib/generators/index.js +76 -0
  10. package/lib/index.d.ts +141 -0
  11. package/lib/index.js +118 -0
  12. package/lib/parsers/index.d.ts +264 -0
  13. package/lib/parsers/index.js +113 -0
  14. package/lib/types.d.ts +388 -0
  15. package/lib/types.js +7 -0
  16. package/package.json +99 -0
  17. package/src/cli/commands/index.ts +3 -0
  18. package/src/cli/commands/sync.ts +146 -0
  19. package/src/cli/commands/validate.ts +151 -0
  20. package/src/cli/commands/watch.ts +74 -0
  21. package/src/cli/index.ts +71 -0
  22. package/src/cli/types.ts +19 -0
  23. package/src/cli/ui.ts +123 -0
  24. package/src/generators/api-reference-generator.ts +268 -0
  25. package/src/generators/code-example-formatter.ts +313 -0
  26. package/src/generators/component-mapper.ts +383 -0
  27. package/src/generators/content-merger.ts +295 -0
  28. package/src/generators/frontmatter-generator.ts +277 -0
  29. package/src/generators/index.ts +56 -0
  30. package/src/generators/mdx-generator.ts +289 -0
  31. package/src/index.ts +131 -0
  32. package/src/orchestrator/index.ts +21 -0
  33. package/src/orchestrator/package-scanner.ts +276 -0
  34. package/src/orchestrator/sync-orchestrator.ts +382 -0
  35. package/src/orchestrator/validation-pipeline.ts +328 -0
  36. package/src/parsers/export-analyzer.ts +335 -0
  37. package/src/parsers/guards.ts +350 -0
  38. package/src/parsers/index.ts +82 -0
  39. package/src/parsers/jsdoc-extractor.ts +313 -0
  40. package/src/parsers/package-info.ts +267 -0
  41. package/src/parsers/readme-parser.ts +334 -0
  42. package/src/parsers/typescript-parser.ts +299 -0
  43. package/src/types.ts +423 -0
  44. package/src/utils/index.ts +13 -0
  45. package/src/utils/safe-patterns.ts +280 -0
  46. package/src/utils/sanitization.ts +164 -0
  47. package/src/watcher/change-detector.ts +138 -0
  48. package/src/watcher/debouncer.ts +168 -0
  49. package/src/watcher/file-watcher.ts +164 -0
  50. package/src/watcher/index.ts +27 -0
@@ -0,0 +1,1560 @@
1
+ import {
2
+ SENTINEL_MARKERS
3
+ } from "./chunk-ROLA7SBB.js";
4
+
5
+ // src/generators/api-reference-generator.ts
6
+ function generateAPIReference(api) {
7
+ const sections = [];
8
+ if (api.functions.length > 0) {
9
+ sections.push("### Functions");
10
+ sections.push("");
11
+ sections.push(generateFunctionsTable(api.functions));
12
+ sections.push("");
13
+ sections.push(generateFunctionDetails(api.functions));
14
+ }
15
+ if (api.types.length > 0) {
16
+ sections.push("### Types");
17
+ sections.push("");
18
+ sections.push(generateTypesTable(api.types));
19
+ sections.push("");
20
+ sections.push(generateTypeDetails(api.types));
21
+ }
22
+ return sections.join("\n");
23
+ }
24
+ function generateFunctionsTable(functions) {
25
+ const lines = [];
26
+ lines.push("| Function | Description |");
27
+ lines.push("| -------- | ----------- |");
28
+ for (const fn of functions) {
29
+ const name = formatFunctionName(fn);
30
+ const description = fn.jsdoc?.description ?? "";
31
+ const firstLine = getFirstLine(description);
32
+ lines.push(`| ${name} | ${escapeTableCell(firstLine)} |`);
33
+ }
34
+ return lines.join("\n");
35
+ }
36
+ function generateFunctionDetails(functions) {
37
+ const sections = [];
38
+ for (const fn of functions) {
39
+ sections.push(generateFunctionDetail(fn));
40
+ }
41
+ return sections.join("\n\n");
42
+ }
43
+ function generateFunctionDetail(fn) {
44
+ const lines = [];
45
+ lines.push(`#### \`${fn.name}\``);
46
+ lines.push("");
47
+ if (fn.jsdoc?.description !== void 0) {
48
+ lines.push(fn.jsdoc.description);
49
+ lines.push("");
50
+ }
51
+ lines.push("```typescript");
52
+ lines.push(fn.signature);
53
+ lines.push("```");
54
+ if (fn.parameters.length > 0) {
55
+ lines.push("");
56
+ lines.push("**Parameters:**");
57
+ lines.push("");
58
+ lines.push("| Name | Type | Description |");
59
+ lines.push("| ---- | ---- | ----------- |");
60
+ for (const param of fn.parameters) {
61
+ const paramDoc = fn.jsdoc?.params?.find((p) => p.name === param.name);
62
+ const description = paramDoc?.description ?? "";
63
+ const optional = param.optional ? " (optional)" : "";
64
+ lines.push(
65
+ `| \`${param.name}\`${optional} | \`${escapeCode(param.type)}\` | ${escapeTableCell(description)} |`
66
+ );
67
+ }
68
+ }
69
+ if (fn.returnType !== "void") {
70
+ lines.push("");
71
+ lines.push(`**Returns:** \`${escapeCode(fn.returnType)}\``);
72
+ if (fn.jsdoc?.returns !== void 0) {
73
+ lines.push("");
74
+ lines.push(fn.jsdoc.returns);
75
+ }
76
+ }
77
+ if (fn.jsdoc?.deprecated !== void 0) {
78
+ lines.push("");
79
+ lines.push(`:::caution[Deprecated]`);
80
+ lines.push(fn.jsdoc.deprecated);
81
+ lines.push(":::");
82
+ }
83
+ if (fn.jsdoc?.since !== void 0) {
84
+ lines.push("");
85
+ lines.push(`*Since: ${fn.jsdoc.since}*`);
86
+ }
87
+ return lines.join("\n");
88
+ }
89
+ function generateTypesTable(types) {
90
+ const lines = [];
91
+ lines.push("| Type | Kind | Description |");
92
+ lines.push("| ---- | ---- | ----------- |");
93
+ for (const type of types) {
94
+ const name = `[\`${type.name}\`](#${type.name.toLowerCase()})`;
95
+ const kind = type.kind;
96
+ const description = type.jsdoc?.description ?? "";
97
+ const firstLine = getFirstLine(description);
98
+ lines.push(`| ${name} | ${kind} | ${escapeTableCell(firstLine)} |`);
99
+ }
100
+ return lines.join("\n");
101
+ }
102
+ function generateTypeDetails(types) {
103
+ const sections = [];
104
+ for (const type of types) {
105
+ sections.push(generateTypeDetail(type));
106
+ }
107
+ return sections.join("\n\n");
108
+ }
109
+ function generateTypeDetail(type) {
110
+ const lines = [];
111
+ lines.push(`#### \`${type.name}\``);
112
+ lines.push("");
113
+ if (type.jsdoc?.description !== void 0) {
114
+ lines.push(type.jsdoc.description);
115
+ lines.push("");
116
+ }
117
+ lines.push("```typescript");
118
+ lines.push(type.definition);
119
+ lines.push("```");
120
+ if (type.typeParameters !== void 0 && type.typeParameters.length > 0) {
121
+ lines.push("");
122
+ lines.push(`**Type Parameters:** ${type.typeParameters.map((t) => `\`${t}\``).join(", ")}`);
123
+ }
124
+ if (type.jsdoc?.deprecated !== void 0) {
125
+ lines.push("");
126
+ lines.push(`:::caution[Deprecated]`);
127
+ lines.push(type.jsdoc.deprecated);
128
+ lines.push(":::");
129
+ }
130
+ if (type.jsdoc?.since !== void 0) {
131
+ lines.push("");
132
+ lines.push(`*Since: ${type.jsdoc.since}*`);
133
+ }
134
+ return lines.join("\n");
135
+ }
136
+ function formatFunctionName(fn) {
137
+ const name = `[\`${fn.name}\`](#${fn.name.toLowerCase()})`;
138
+ const badges = [];
139
+ if (fn.isAsync) {
140
+ badges.push('<Badge text="async" variant="note" size="small" />');
141
+ }
142
+ if (fn.isGenerator) {
143
+ badges.push('<Badge text="generator" variant="tip" size="small" />');
144
+ }
145
+ if (fn.isDefault) {
146
+ badges.push('<Badge text="default" variant="caution" size="small" />');
147
+ }
148
+ return badges.length > 0 ? `${name} ${badges.join(" ")}` : name;
149
+ }
150
+ function getFirstLine(text) {
151
+ const firstLine = text.split("\n")[0]?.trim() ?? "";
152
+ if (firstLine.length > 100) {
153
+ const truncated = firstLine.slice(0, 97);
154
+ const lastSpace = truncated.lastIndexOf(" ");
155
+ if (lastSpace > 50) {
156
+ return `${truncated.slice(0, lastSpace)}...`;
157
+ }
158
+ return `${truncated}...`;
159
+ }
160
+ return firstLine;
161
+ }
162
+ function escapeTableCell(content) {
163
+ return content.replaceAll("|", String.raw`\|`).replaceAll("\n", " ");
164
+ }
165
+ function escapeCode(code) {
166
+ return code.replaceAll("`", "\\`");
167
+ }
168
+ function generateAPICompact(api) {
169
+ const lines = [];
170
+ if (api.functions.length > 0) {
171
+ lines.push("**Functions:**");
172
+ for (const fn of api.functions) {
173
+ lines.push(`- \`${fn.name}(${formatParameterList(fn)})\` \u2192 \`${fn.returnType}\``);
174
+ }
175
+ }
176
+ if (api.types.length > 0) {
177
+ if (lines.length > 0) lines.push("");
178
+ lines.push("**Types:**");
179
+ for (const type of api.types) {
180
+ lines.push(`- \`${type.name}\` (${type.kind})`);
181
+ }
182
+ }
183
+ return lines.join("\n");
184
+ }
185
+ function formatParameterList(fn) {
186
+ return fn.parameters.map((p) => p.optional ? `${p.name}?` : p.name).join(", ");
187
+ }
188
+ function generateCategoryReference(functions, types, categoryName) {
189
+ const sections = [];
190
+ sections.push(`### ${categoryName}`);
191
+ sections.push("");
192
+ if (functions.length > 0) {
193
+ sections.push("#### Functions");
194
+ sections.push("");
195
+ sections.push(generateFunctionsTable(functions));
196
+ sections.push("");
197
+ sections.push(generateFunctionDetails(functions));
198
+ }
199
+ if (types.length > 0) {
200
+ sections.push("#### Types");
201
+ sections.push("");
202
+ sections.push(generateTypesTable(types));
203
+ sections.push("");
204
+ sections.push(generateTypeDetails(types));
205
+ }
206
+ return sections.join("\n");
207
+ }
208
+
209
+ // src/generators/code-example-formatter.ts
210
+ var DEFAULT_OPTIONS = {
211
+ defaultLanguage: "typescript",
212
+ includeTitle: true,
213
+ maxExamplesPerFunction: 3,
214
+ collapsible: false
215
+ };
216
+ function formatCodeExamples(api, options = {}) {
217
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
218
+ const examples = [];
219
+ for (const fn of api.functions) {
220
+ const fnExamples = formatFunctionExamples(fn, mergedOptions);
221
+ if (fnExamples.length > 0) {
222
+ examples.push(fnExamples);
223
+ }
224
+ }
225
+ for (const type of api.types) {
226
+ const typeExamples = formatTypeExamples(type, mergedOptions);
227
+ if (typeExamples.length > 0) {
228
+ examples.push(typeExamples);
229
+ }
230
+ }
231
+ return examples.join("\n\n");
232
+ }
233
+ function formatFunctionExamples(fn, options = {}) {
234
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
235
+ if (fn.jsdoc?.examples === void 0 || fn.jsdoc.examples.length === 0) {
236
+ return "";
237
+ }
238
+ const exampleCount = Math.min(fn.jsdoc.examples.length, mergedOptions.maxExamplesPerFunction);
239
+ const examples = fn.jsdoc.examples.slice(0, exampleCount);
240
+ const sections = [];
241
+ if (mergedOptions.includeTitle) {
242
+ sections.push(`### ${fn.name}`);
243
+ sections.push("");
244
+ }
245
+ for (const [index, example] of examples.entries()) {
246
+ const formattedExample = formatCodeBlock(example, mergedOptions.defaultLanguage);
247
+ if (mergedOptions.collapsible && examples.length > 1) {
248
+ sections.push(`<details>`);
249
+ sections.push(`<summary>Example ${index + 1}</summary>`);
250
+ sections.push("");
251
+ sections.push(formattedExample);
252
+ sections.push("");
253
+ sections.push(`</details>`);
254
+ } else {
255
+ sections.push(formattedExample);
256
+ }
257
+ if (index < examples.length - 1) {
258
+ sections.push("");
259
+ }
260
+ }
261
+ return sections.join("\n");
262
+ }
263
+ function formatTypeExamples(type, options = {}) {
264
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
265
+ if (type.jsdoc?.examples === void 0 || type.jsdoc.examples.length === 0) {
266
+ return "";
267
+ }
268
+ const exampleCount = Math.min(type.jsdoc.examples.length, mergedOptions.maxExamplesPerFunction);
269
+ const examples = type.jsdoc.examples.slice(0, exampleCount);
270
+ const sections = [];
271
+ if (mergedOptions.includeTitle) {
272
+ sections.push(`### ${type.name}`);
273
+ sections.push("");
274
+ }
275
+ for (const [index, example] of examples.entries()) {
276
+ const formattedExample = formatCodeBlock(example, mergedOptions.defaultLanguage);
277
+ if (mergedOptions.collapsible && examples.length > 1) {
278
+ sections.push(`<details>`);
279
+ sections.push(`<summary>Example ${index + 1}</summary>`);
280
+ sections.push("");
281
+ sections.push(formattedExample);
282
+ sections.push("");
283
+ sections.push(`</details>`);
284
+ } else {
285
+ sections.push(formattedExample);
286
+ }
287
+ if (index < examples.length - 1) {
288
+ sections.push("");
289
+ }
290
+ }
291
+ return sections.join("\n");
292
+ }
293
+ function formatCodeBlock(code, language = "typescript") {
294
+ const cleanedCode = cleanCodeExample(code);
295
+ const detectedLanguage = detectLanguage(cleanedCode) ?? language;
296
+ return `\`\`\`${detectedLanguage}
297
+ ${cleanedCode}
298
+ \`\`\``;
299
+ }
300
+ function cleanCodeExample(code) {
301
+ let cleaned = code.trim();
302
+ if (cleaned.startsWith("```")) {
303
+ const lines2 = cleaned.split("\n");
304
+ lines2.shift();
305
+ if (lines2.at(-1)?.trim() === "```") {
306
+ lines2.pop();
307
+ }
308
+ cleaned = lines2.join("\n");
309
+ }
310
+ cleaned = cleaned.split("\n").map((line) => {
311
+ if (line.startsWith(" * ")) {
312
+ return line.slice(3);
313
+ }
314
+ if (line.startsWith("* ")) {
315
+ return line.slice(2);
316
+ }
317
+ return line;
318
+ }).join("\n");
319
+ const lines = cleaned.split("\n");
320
+ const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
321
+ if (nonEmptyLines.length === 0) {
322
+ return cleaned;
323
+ }
324
+ const minIndent = Math.min(
325
+ ...nonEmptyLines.map((line) => {
326
+ const match = /^(\s*)/.exec(line);
327
+ return match?.[1]?.length ?? 0;
328
+ })
329
+ );
330
+ if (minIndent > 0) {
331
+ cleaned = lines.map((line) => line.slice(minIndent)).join("\n");
332
+ }
333
+ return cleaned.trim();
334
+ }
335
+ function detectLanguage(code) {
336
+ if (code.includes("import ") || code.includes("export ") || code.includes(": ")) {
337
+ if (code.includes("<") && code.includes("/>")) {
338
+ return "tsx";
339
+ }
340
+ return "typescript";
341
+ }
342
+ if (code.includes("const ") || code.includes("let ") || code.includes("function ")) {
343
+ if (code.includes("<") && code.includes("/>")) {
344
+ return "jsx";
345
+ }
346
+ return "javascript";
347
+ }
348
+ if (code.startsWith("{") || code.startsWith("[")) {
349
+ return "json";
350
+ }
351
+ if (code.includes("$ ") || code.includes("npm ") || code.includes("pnpm ")) {
352
+ return "bash";
353
+ }
354
+ return void 0;
355
+ }
356
+ function formatUsageExample(fn) {
357
+ const params = fn.parameters.map((p) => {
358
+ if (p.optional && p.defaultValue !== void 0) {
359
+ return `${p.name} = ${p.defaultValue}`;
360
+ }
361
+ if (p.optional) {
362
+ return `${p.name}?`;
363
+ }
364
+ return p.name;
365
+ });
366
+ const call = `${fn.name}(${params.join(", ")})`;
367
+ if (fn.isAsync) {
368
+ return `const result = await ${call}`;
369
+ }
370
+ if (fn.returnType !== "void") {
371
+ return `const result = ${call}`;
372
+ }
373
+ return call;
374
+ }
375
+ function groupExamplesByCategory(api) {
376
+ const categories = /* @__PURE__ */ new Map();
377
+ for (const fn of api.functions) {
378
+ if (fn.jsdoc?.examples === void 0 || fn.jsdoc.examples.length === 0) {
379
+ continue;
380
+ }
381
+ const category = inferCategory(fn.name);
382
+ const existing = categories.get(category) ?? { functions: [], types: [] };
383
+ existing.functions.push(fn);
384
+ categories.set(category, existing);
385
+ }
386
+ for (const type of api.types) {
387
+ if (type.jsdoc?.examples === void 0 || type.jsdoc.examples.length === 0) {
388
+ continue;
389
+ }
390
+ const category = inferCategory(type.name);
391
+ const existing = categories.get(category) ?? { functions: [], types: [] };
392
+ existing.types.push(type);
393
+ categories.set(category, existing);
394
+ }
395
+ return categories;
396
+ }
397
+ function inferCategory(name) {
398
+ const prefixes = ["create", "get", "set", "is", "has", "parse", "format", "validate", "build"];
399
+ for (const prefix of prefixes) {
400
+ if (name.toLowerCase().startsWith(prefix)) {
401
+ return capitalizeFirst(prefix);
402
+ }
403
+ }
404
+ return "General";
405
+ }
406
+ function capitalizeFirst(str) {
407
+ if (str.length === 0) return str;
408
+ return str.charAt(0).toUpperCase() + str.slice(1);
409
+ }
410
+ function formatGroupedExamples(api, options = {}) {
411
+ const categories = groupExamplesByCategory(api);
412
+ const sections = [];
413
+ for (const [category, items] of categories) {
414
+ sections.push(`### ${category}`);
415
+ sections.push("");
416
+ for (const fn of items.functions) {
417
+ const examples = formatFunctionExamples(fn, { ...options, includeTitle: false });
418
+ if (examples.length > 0) {
419
+ sections.push(`#### \`${fn.name}\``);
420
+ sections.push("");
421
+ sections.push(examples);
422
+ sections.push("");
423
+ }
424
+ }
425
+ for (const type of items.types) {
426
+ const examples = formatTypeExamples(type, { ...options, includeTitle: false });
427
+ if (examples.length > 0) {
428
+ sections.push(`#### \`${type.name}\``);
429
+ sections.push("");
430
+ sections.push(examples);
431
+ sections.push("");
432
+ }
433
+ }
434
+ }
435
+ return sections.join("\n").trim();
436
+ }
437
+
438
+ // src/utils/sanitization.ts
439
+ import { sanitizeInput } from "@bfra.me/es/validation";
440
+ import escapeHtml from "escape-html";
441
+ function sanitizeForMDX(content) {
442
+ const escaped = sanitizeInput(content, { trim: false });
443
+ return escaped.replaceAll("{", "&#123;").replaceAll("}", "&#125;");
444
+ }
445
+ function sanitizeAttribute(value) {
446
+ return escapeHtml(value);
447
+ }
448
+ function parseJSXAttributes(tag) {
449
+ const attrs = [];
450
+ const spaceIndex = tag.indexOf(" ");
451
+ if (spaceIndex === -1) return attrs;
452
+ const closeIndex = tag.lastIndexOf(">");
453
+ if (closeIndex === -1) return attrs;
454
+ const attrRegion = tag.slice(spaceIndex + 1, closeIndex).trim();
455
+ let i = 0;
456
+ while (i < attrRegion.length) {
457
+ while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
458
+ if (i >= attrRegion.length) break;
459
+ let name = "";
460
+ while (i < attrRegion.length && /[\w-]/.test(attrRegion.charAt(i))) {
461
+ name += attrRegion[i];
462
+ i++;
463
+ }
464
+ if (!name) break;
465
+ while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
466
+ if (i >= attrRegion.length || attrRegion[i] !== "=") {
467
+ attrs.push({ name, value: null });
468
+ continue;
469
+ }
470
+ i++;
471
+ while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
472
+ if (i >= attrRegion.length) {
473
+ attrs.push({ name, value: "" });
474
+ break;
475
+ }
476
+ let value = "";
477
+ const quote = attrRegion[i];
478
+ if (quote === '"' || quote === "'") {
479
+ i++;
480
+ while (i < attrRegion.length && attrRegion[i] !== quote) {
481
+ value += attrRegion[i];
482
+ i++;
483
+ }
484
+ if (i < attrRegion.length) i++;
485
+ } else {
486
+ while (i < attrRegion.length && !/[\s/>]/.test(attrRegion.charAt(i))) {
487
+ value += attrRegion[i];
488
+ i++;
489
+ }
490
+ }
491
+ attrs.push({ name, value });
492
+ }
493
+ return attrs;
494
+ }
495
+ function sanitizeJSXTag(tag) {
496
+ const tagMatch = tag.match(/^<([A-Z][a-zA-Z0-9]*)/);
497
+ if (!tagMatch || typeof tagMatch[1] !== "string" || tagMatch[1].length === 0) {
498
+ return escapeHtml(tag);
499
+ }
500
+ const tagName = tagMatch[1];
501
+ const selfClosing = tag.endsWith("/>");
502
+ const attributes = parseJSXAttributes(tag);
503
+ const sanitizedAttrs = attributes.map(({ name, value }) => {
504
+ if (value === null) return name;
505
+ const escaped = escapeHtml(value);
506
+ return `${name}="${escaped}"`;
507
+ });
508
+ const attrString = sanitizedAttrs.length > 0 ? ` ${sanitizedAttrs.join(" ")}` : "";
509
+ return `<${tagName}${attrString}${selfClosing ? " />" : ">"}`;
510
+ }
511
+
512
+ // src/generators/component-mapper.ts
513
+ var DEFAULT_CONFIG = {
514
+ featureSections: ["features", "highlights", "key features"],
515
+ tabSections: ["installation", "getting started", "setup"],
516
+ excludeSections: ["license", "contributing", "contributors", "changelog"]
517
+ };
518
+ function mapToStarlightComponents(readme, packageInfo, config = {}) {
519
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
520
+ const sections = [];
521
+ if (readme.preamble !== void 0 && readme.preamble.trim().length > 0) {
522
+ sections.push(readme.preamble);
523
+ sections.push("");
524
+ }
525
+ for (const section of readme.sections) {
526
+ const output = mapSection(section, packageInfo, mergedConfig);
527
+ if (output.length > 0) {
528
+ sections.push(output);
529
+ sections.push("");
530
+ }
531
+ }
532
+ return sections.join("\n").trim();
533
+ }
534
+ function mapSection(section, packageInfo, config) {
535
+ const normalizedHeading = section.heading.toLowerCase().trim();
536
+ if (isExcludedSection(normalizedHeading, config.excludeSections, packageInfo)) {
537
+ return "";
538
+ }
539
+ if (config.customMappings?.[normalizedHeading] !== void 0) {
540
+ return config.customMappings[normalizedHeading](section, packageInfo);
541
+ }
542
+ if (isFeatureSection(normalizedHeading, config.featureSections)) {
543
+ return mapFeatureSection(section);
544
+ }
545
+ if (isInstallationSection(normalizedHeading, config.tabSections)) {
546
+ return mapInstallationSection(section, packageInfo);
547
+ }
548
+ return mapDefaultSection(section, packageInfo, config);
549
+ }
550
+ function isExcludedSection(heading, excludeSections, packageInfo) {
551
+ if (excludeSections.some((excluded) => heading.includes(excluded.toLowerCase()))) {
552
+ return true;
553
+ }
554
+ if (packageInfo.docsConfig?.excludeSections !== void 0) {
555
+ return packageInfo.docsConfig.excludeSections.some(
556
+ (excluded) => heading.includes(excluded.toLowerCase())
557
+ );
558
+ }
559
+ return false;
560
+ }
561
+ function isFeatureSection(heading, featureSections) {
562
+ return featureSections.some((feature) => heading.includes(feature.toLowerCase()));
563
+ }
564
+ function isInstallationSection(heading, tabSections) {
565
+ return tabSections.some((tab) => heading.includes(tab.toLowerCase()));
566
+ }
567
+ function mapFeatureSection(section) {
568
+ const lines = [];
569
+ lines.push(`## ${section.heading}`);
570
+ lines.push("");
571
+ const features = extractFeatureItems(section.content);
572
+ if (features.length > 0) {
573
+ lines.push("<CardGrid>");
574
+ for (const feature of features) {
575
+ const icon = inferFeatureIcon(feature.title, feature.emoji);
576
+ lines.push(` <Card title="${sanitizeAttribute(feature.title)}" icon="${icon}">`);
577
+ lines.push(` ${feature.description}`);
578
+ lines.push(" </Card>");
579
+ }
580
+ lines.push("</CardGrid>");
581
+ } else {
582
+ lines.push(section.content);
583
+ }
584
+ return lines.join("\n");
585
+ }
586
+ var EMOJI_TO_ICON_MAP = {
587
+ "\u{1F4DD}": "document",
588
+ "\u{1F4D6}": "document",
589
+ "\u{1F504}": "seti:refresh",
590
+ "\u{1F441}\uFE0F": "eye-open",
591
+ "\u2728": "star",
592
+ "\u{1F6E1}\uFE0F": "shield",
593
+ "\u{1F3A8}": "seti:settings",
594
+ "\u{1F512}": "lock"
595
+ };
596
+ function extractFeatureItems(content) {
597
+ const features = [];
598
+ const boldListPattern = /^[-*] ([^*\r\n]*)\*\*([^*\r\n]+)\*\* ?[:—–-] ?([^\r\n]+)$/gm;
599
+ for (const match of content.matchAll(boldListPattern)) {
600
+ if (match[2] !== void 0 && match[3] !== void 0) {
601
+ const prefix = match[1] ?? "";
602
+ const emoji = extractEmoji(prefix);
603
+ features.push({
604
+ title: match[2].trim(),
605
+ description: match[3].trim(),
606
+ emoji
607
+ });
608
+ }
609
+ }
610
+ if (features.length === 0) {
611
+ const dashSeparatedPattern = /^[-*] ([^—–\n]+)[—–] (.+)$/gm;
612
+ for (const match of content.matchAll(dashSeparatedPattern)) {
613
+ if (match[1] !== void 0 && match[2] !== void 0) {
614
+ const rawTitle = match[1].trim();
615
+ const description = match[2].trim();
616
+ const emoji = extractEmoji(rawTitle);
617
+ const title = rawTitle.replace(
618
+ /^[\p{Emoji_Presentation}\p{Extended_Pictographic}]+\s*/u,
619
+ ""
620
+ );
621
+ if (title.length > 0 && description.length > 0 && description.length < 300) {
622
+ features.push({ title, description, emoji });
623
+ }
624
+ }
625
+ }
626
+ }
627
+ if (features.length === 0) {
628
+ const boldPattern = /\*\*([^*]+)\*\*/g;
629
+ const boldMatches = [...content.matchAll(boldPattern)];
630
+ for (const match of boldMatches) {
631
+ if (match[1] !== void 0) {
632
+ const title = match[1].trim();
633
+ const afterMatch = content.slice((match.index ?? 0) + match[0].length);
634
+ const description = afterMatch.split(/\n\n|\*\*/)[0]?.trim() ?? "";
635
+ if (description.length > 0 && description.length < 200) {
636
+ features.push({ title, description });
637
+ }
638
+ }
639
+ }
640
+ }
641
+ return features;
642
+ }
643
+ function extractEmoji(text) {
644
+ const emojiMatch = text.match(/^[\p{Emoji_Presentation}\p{Extended_Pictographic}]+/u);
645
+ return emojiMatch?.[0];
646
+ }
647
+ function inferFeatureIcon(title, emoji) {
648
+ if (emoji !== void 0 && EMOJI_TO_ICON_MAP[emoji] !== void 0) {
649
+ return EMOJI_TO_ICON_MAP[emoji];
650
+ }
651
+ const lowerTitle = title.toLowerCase();
652
+ const keywordIconMap = {
653
+ typescript: "approve-check",
654
+ type: "approve-check",
655
+ test: "approve-check",
656
+ fast: "rocket",
657
+ speed: "rocket",
658
+ performance: "rocket",
659
+ tree: "seti:plan",
660
+ modular: "puzzle",
661
+ plugin: "puzzle",
662
+ extensible: "puzzle",
663
+ document: "document",
664
+ doc: "document",
665
+ config: "setting",
666
+ setting: "setting",
667
+ star: "star",
668
+ feature: "star",
669
+ safe: "approve-check",
670
+ secure: "approve-check",
671
+ error: "warning",
672
+ async: "rocket",
673
+ result: "approve-check",
674
+ function: "puzzle",
675
+ watch: "eye-open",
676
+ incremental: "seti:refresh",
677
+ preservation: "shield",
678
+ mdx: "document",
679
+ parsing: "document"
680
+ };
681
+ for (const [keyword, icon] of Object.entries(keywordIconMap)) {
682
+ if (lowerTitle.includes(keyword)) {
683
+ return icon;
684
+ }
685
+ }
686
+ return "star";
687
+ }
688
+ function mapInstallationSection(section, packageInfo) {
689
+ const lines = [];
690
+ lines.push(`## ${section.heading}`);
691
+ lines.push("");
692
+ const hasPnpm = /\bpnpm\b/.test(section.content);
693
+ const hasNpm = /\bnpm\b/.test(section.content);
694
+ const hasYarn = /\byarn\b/.test(section.content);
695
+ const packageManagerCount = [hasPnpm, hasNpm, hasYarn].filter(Boolean).length;
696
+ const hasExistingTabs = section.content.includes("```bash");
697
+ const hasMultiplePackageManagers = packageManagerCount >= 2;
698
+ if (hasExistingTabs && hasMultiplePackageManagers) {
699
+ lines.push(section.content);
700
+ } else {
701
+ lines.push(generateInstallTabs(packageInfo.name));
702
+ const contentWithoutInstall = removeInstallCommand(section.content);
703
+ if (contentWithoutInstall.trim().length > 0) {
704
+ lines.push("");
705
+ lines.push(contentWithoutInstall);
706
+ }
707
+ }
708
+ return lines.join("\n");
709
+ }
710
+ function generateInstallTabs(packageName) {
711
+ return `<Tabs>
712
+ <TabItem label="pnpm">
713
+ \`\`\`bash
714
+ pnpm add ${packageName}
715
+ \`\`\`
716
+ </TabItem>
717
+ <TabItem label="npm">
718
+ \`\`\`bash
719
+ npm install ${packageName}
720
+ \`\`\`
721
+ </TabItem>
722
+ <TabItem label="yarn">
723
+ \`\`\`bash
724
+ yarn add ${packageName}
725
+ \`\`\`
726
+ </TabItem>
727
+ </Tabs>`;
728
+ }
729
+ function removeInstallCommand(content) {
730
+ return content.replaceAll(/```(?:bash|sh)\n(?:npm|pnpm|yarn)\s+(?:install|add|i)\s+\S+\n```/g, "").trim();
731
+ }
732
+ function mapDefaultSection(section, packageInfo, config) {
733
+ const lines = [];
734
+ const headingLevel = "#".repeat(Math.min(section.level + 1, 6));
735
+ lines.push(`${headingLevel} ${section.heading}`);
736
+ lines.push("");
737
+ lines.push(section.content);
738
+ for (const child of section.children) {
739
+ const childOutput = mapSection(child, packageInfo, config);
740
+ if (childOutput.length > 0) {
741
+ lines.push("");
742
+ lines.push(childOutput);
743
+ }
744
+ }
745
+ return lines.join("\n");
746
+ }
747
+ function createBadge(text, variant = "note") {
748
+ return `<Badge text="${sanitizeAttribute(text)}" variant="${variant}" />`;
749
+ }
750
+ function createCard(title, content, icon) {
751
+ const iconAttr = icon === void 0 ? "" : ` icon="${icon}"`;
752
+ return `<Card title="${sanitizeAttribute(title)}"${iconAttr}>
753
+ ${content}
754
+ </Card>`;
755
+ }
756
+ function createCardGrid(cards) {
757
+ const cardElements = cards.map((card) => createCard(card.title, card.content, card.icon));
758
+ return `<CardGrid>
759
+ ${cardElements.map((c) => ` ${c}`).join("\n")}
760
+ </CardGrid>`;
761
+ }
762
+ function createTabs(items) {
763
+ const tabItems = items.map(
764
+ (item) => ` <TabItem label="${sanitizeAttribute(item.label)}">
765
+ ${item.content}
766
+ </TabItem>`
767
+ );
768
+ return `<Tabs>
769
+ ${tabItems.join("\n")}
770
+ </Tabs>`;
771
+ }
772
+
773
+ // src/generators/content-merger.ts
774
+ import { err, ok } from "@bfra.me/es/result";
775
+ function mergeContent(existingContent, newContent, options = {}) {
776
+ const { conflictStrategy = "keep-manual", preserveEmptyManual = true } = options;
777
+ try {
778
+ const existingManualSections = extractManualSections(existingContent);
779
+ const newAutoSections = extractAutoSections(newContent);
780
+ if (existingManualSections.length === 0 && newAutoSections.length === 0) {
781
+ const hasChanges2 = existingContent.trim() !== newContent.trim();
782
+ return ok({
783
+ content: newContent,
784
+ preservedCount: 0,
785
+ updatedCount: hasChanges2 ? 1 : 0,
786
+ hasChanges: hasChanges2
787
+ });
788
+ }
789
+ let merged = newContent;
790
+ let preservedCount = 0;
791
+ for (const manual of existingManualSections) {
792
+ if (!preserveEmptyManual && manual.content.trim().length === 0) {
793
+ continue;
794
+ }
795
+ const manualMarker = `${SENTINEL_MARKERS.MANUAL_START}
796
+ ${manual.content}
797
+ ${SENTINEL_MARKERS.MANUAL_END}`;
798
+ if (!merged.includes(SENTINEL_MARKERS.MANUAL_START)) {
799
+ const autoEndIndex = merged.indexOf(SENTINEL_MARKERS.AUTO_END);
800
+ if (autoEndIndex === -1) {
801
+ merged = `${merged}
802
+
803
+ ${manualMarker}`;
804
+ } else {
805
+ merged = `${merged.slice(0, autoEndIndex + SENTINEL_MARKERS.AUTO_END.length)}
806
+
807
+ ${manualMarker}
808
+ ${merged.slice(autoEndIndex + SENTINEL_MARKERS.AUTO_END.length)}`;
809
+ }
810
+ } else if (conflictStrategy === "keep-manual") {
811
+ const existingManualInNew = extractManualSections(merged);
812
+ if (existingManualInNew.length > 0) {
813
+ const firstManualInNew = existingManualInNew[0];
814
+ if (firstManualInNew !== void 0) {
815
+ merged = replaceSection(merged, firstManualInNew, manual.content);
816
+ }
817
+ }
818
+ }
819
+ preservedCount++;
820
+ }
821
+ const hasChanges = existingContent.trim() !== merged.trim();
822
+ return ok({
823
+ content: merged,
824
+ preservedCount,
825
+ updatedCount: newAutoSections.length,
826
+ hasChanges
827
+ });
828
+ } catch (error) {
829
+ return err({
830
+ code: "GENERATION_ERROR",
831
+ message: `Failed to merge content: ${error instanceof Error ? error.message : String(error)}`,
832
+ cause: error
833
+ });
834
+ }
835
+ }
836
+ function extractManualSections(content) {
837
+ const sections = [];
838
+ let searchStart = 0;
839
+ while (searchStart < content.length) {
840
+ const startIndex = content.indexOf(SENTINEL_MARKERS.MANUAL_START, searchStart);
841
+ if (startIndex === -1) break;
842
+ const endIndex = content.indexOf(SENTINEL_MARKERS.MANUAL_END, startIndex);
843
+ if (endIndex === -1) break;
844
+ const contentStart = startIndex + SENTINEL_MARKERS.MANUAL_START.length;
845
+ const sectionContent = content.slice(contentStart, endIndex).trim();
846
+ sections.push({
847
+ type: "manual",
848
+ content: sectionContent,
849
+ startIndex,
850
+ endIndex: endIndex + SENTINEL_MARKERS.MANUAL_END.length
851
+ });
852
+ searchStart = endIndex + SENTINEL_MARKERS.MANUAL_END.length;
853
+ }
854
+ return sections;
855
+ }
856
+ function extractAutoSections(content) {
857
+ const sections = [];
858
+ let searchStart = 0;
859
+ while (searchStart < content.length) {
860
+ const startIndex = content.indexOf(SENTINEL_MARKERS.AUTO_START, searchStart);
861
+ if (startIndex === -1) break;
862
+ const endIndex = content.indexOf(SENTINEL_MARKERS.AUTO_END, startIndex);
863
+ if (endIndex === -1) break;
864
+ const contentStart = startIndex + SENTINEL_MARKERS.AUTO_START.length;
865
+ const sectionContent = content.slice(contentStart, endIndex).trim();
866
+ sections.push({
867
+ type: "auto",
868
+ content: sectionContent,
869
+ startIndex,
870
+ endIndex: endIndex + SENTINEL_MARKERS.AUTO_END.length
871
+ });
872
+ searchStart = endIndex + SENTINEL_MARKERS.AUTO_END.length;
873
+ }
874
+ return sections;
875
+ }
876
+ function replaceSection(content, section, newContent) {
877
+ const marker = section.type === "manual" ? SENTINEL_MARKERS.MANUAL_START : SENTINEL_MARKERS.AUTO_START;
878
+ const endMarker = section.type === "manual" ? SENTINEL_MARKERS.MANUAL_END : SENTINEL_MARKERS.AUTO_END;
879
+ const before = content.slice(0, section.startIndex);
880
+ const after = content.slice(section.endIndex);
881
+ return `${before}${marker}
882
+ ${newContent}
883
+ ${endMarker}${after}`;
884
+ }
885
+ function hasManualContent(content) {
886
+ return content.includes(SENTINEL_MARKERS.MANUAL_START);
887
+ }
888
+ function hasAutoContent(content) {
889
+ return content.includes(SENTINEL_MARKERS.AUTO_START);
890
+ }
891
+ function wrapManualSection(content) {
892
+ return `${SENTINEL_MARKERS.MANUAL_START}
893
+ ${content}
894
+ ${SENTINEL_MARKERS.MANUAL_END}`;
895
+ }
896
+ function wrapAutoSection(content) {
897
+ return `${SENTINEL_MARKERS.AUTO_START}
898
+ ${content}
899
+ ${SENTINEL_MARKERS.AUTO_END}`;
900
+ }
901
+ function stripSentinelMarkers(content) {
902
+ return content.replaceAll(SENTINEL_MARKERS.AUTO_START, "").replaceAll(SENTINEL_MARKERS.AUTO_END, "").replaceAll(SENTINEL_MARKERS.MANUAL_START, "").replaceAll(SENTINEL_MARKERS.MANUAL_END, "").replaceAll(/\n{3,}/g, "\n\n").trim();
903
+ }
904
+ function validateMarkerPairing(content) {
905
+ const autoStartCount = countOccurrences(content, SENTINEL_MARKERS.AUTO_START);
906
+ const autoEndCount = countOccurrences(content, SENTINEL_MARKERS.AUTO_END);
907
+ const manualStartCount = countOccurrences(content, SENTINEL_MARKERS.MANUAL_START);
908
+ const manualEndCount = countOccurrences(content, SENTINEL_MARKERS.MANUAL_END);
909
+ if (autoStartCount !== autoEndCount) {
910
+ return err({
911
+ code: "VALIDATION_ERROR",
912
+ message: `Mismatched AUTO-GENERATED markers: ${autoStartCount} starts, ${autoEndCount} ends`
913
+ });
914
+ }
915
+ if (manualStartCount !== manualEndCount) {
916
+ return err({
917
+ code: "VALIDATION_ERROR",
918
+ message: `Mismatched MANUAL-CONTENT markers: ${manualStartCount} starts, ${manualEndCount} ends`
919
+ });
920
+ }
921
+ const autoNesting = checkNesting(content, SENTINEL_MARKERS.AUTO_START, SENTINEL_MARKERS.AUTO_END);
922
+ if (!autoNesting) {
923
+ return err({
924
+ code: "VALIDATION_ERROR",
925
+ message: "AUTO-GENERATED markers are improperly nested"
926
+ });
927
+ }
928
+ const manualNesting = checkNesting(
929
+ content,
930
+ SENTINEL_MARKERS.MANUAL_START,
931
+ SENTINEL_MARKERS.MANUAL_END
932
+ );
933
+ if (!manualNesting) {
934
+ return err({
935
+ code: "VALIDATION_ERROR",
936
+ message: "MANUAL-CONTENT markers are improperly nested"
937
+ });
938
+ }
939
+ return ok(true);
940
+ }
941
+ function countOccurrences(content, substring) {
942
+ let count = 0;
943
+ let position = content.indexOf(substring, 0);
944
+ while (position !== -1) {
945
+ count++;
946
+ position = content.indexOf(substring, position + substring.length);
947
+ }
948
+ return count;
949
+ }
950
+ function checkNesting(content, startMarker, endMarker) {
951
+ let depth = 0;
952
+ let position = 0;
953
+ while (position < content.length) {
954
+ const startPos = content.indexOf(startMarker, position);
955
+ const endPos = content.indexOf(endMarker, position);
956
+ if (startPos === -1 && endPos === -1) break;
957
+ if (startPos !== -1 && (endPos === -1 || startPos < endPos)) {
958
+ depth++;
959
+ position = startPos + startMarker.length;
960
+ } else {
961
+ depth--;
962
+ if (depth < 0) return false;
963
+ position = endPos + endMarker.length;
964
+ }
965
+ }
966
+ return depth === 0;
967
+ }
968
+ function createDiffSummary(oldContent, newContent) {
969
+ const oldLines = oldContent.split("\n");
970
+ const newLines = newContent.split("\n");
971
+ const added = newLines.filter((line) => !oldLines.includes(line)).length;
972
+ const removed = oldLines.filter((line) => !newLines.includes(line)).length;
973
+ return `${added} lines added, ${removed} lines removed`;
974
+ }
975
+
976
+ // src/generators/frontmatter-generator.ts
977
+ function generateFrontmatter(packageInfo, readme, overrides) {
978
+ const title = resolveTitle(packageInfo, readme, overrides?.title);
979
+ const description = resolveDescription(packageInfo, readme, overrides?.description);
980
+ const frontmatter = {
981
+ title,
982
+ ...description !== void 0 && { description },
983
+ ...overrides?.sidebar !== void 0 && { sidebar: overrides.sidebar },
984
+ ...overrides?.tableOfContents !== void 0 && { tableOfContents: overrides.tableOfContents },
985
+ ...overrides?.template !== void 0 && { template: overrides.template },
986
+ ...overrides?.hero !== void 0 && { hero: overrides.hero }
987
+ };
988
+ if (packageInfo.docsConfig?.sidebar !== void 0) {
989
+ frontmatter.sidebar = {
990
+ ...packageInfo.docsConfig.sidebar,
991
+ ...frontmatter.sidebar
992
+ };
993
+ }
994
+ if (packageInfo.docsConfig?.frontmatter !== void 0) {
995
+ const customFrontmatter = packageInfo.docsConfig.frontmatter;
996
+ return { ...customFrontmatter, ...frontmatter };
997
+ }
998
+ return frontmatter;
999
+ }
1000
+ function resolveTitle(packageInfo, readme, override) {
1001
+ if (override !== void 0) {
1002
+ return override;
1003
+ }
1004
+ if (packageInfo.docsConfig?.title !== void 0) {
1005
+ return packageInfo.docsConfig.title;
1006
+ }
1007
+ if (readme?.title !== void 0) {
1008
+ return readme.title;
1009
+ }
1010
+ return packageInfo.name;
1011
+ }
1012
+ function resolveDescription(packageInfo, readme, override) {
1013
+ if (override !== void 0) {
1014
+ return override;
1015
+ }
1016
+ if (packageInfo.docsConfig?.description !== void 0) {
1017
+ return packageInfo.docsConfig.description;
1018
+ }
1019
+ if (packageInfo.description !== void 0) {
1020
+ return packageInfo.description;
1021
+ }
1022
+ if (readme?.preamble !== void 0) {
1023
+ return extractFirstSentence(readme.preamble);
1024
+ }
1025
+ return void 0;
1026
+ }
1027
+ function extractFirstSentence(text) {
1028
+ const cleaned = text.trim().replaceAll(/\s+/g, " ");
1029
+ const sentenceEnd = cleaned.search(/[.!?](?:\s|$)/);
1030
+ if (sentenceEnd > 0) {
1031
+ return cleaned.slice(0, sentenceEnd + 1);
1032
+ }
1033
+ if (cleaned.length > 160) {
1034
+ const truncated = cleaned.slice(0, 157);
1035
+ const lastSpace = truncated.lastIndexOf(" ");
1036
+ if (lastSpace > 100) {
1037
+ return `${truncated.slice(0, lastSpace)}...`;
1038
+ }
1039
+ return `${truncated}...`;
1040
+ }
1041
+ return cleaned;
1042
+ }
1043
+ function stringifyFrontmatter(frontmatter) {
1044
+ const lines = [];
1045
+ lines.push(`title: ${yamlString(frontmatter.title)}`);
1046
+ if (frontmatter.description !== void 0) {
1047
+ lines.push(`description: ${yamlString(frontmatter.description)}`);
1048
+ }
1049
+ if (frontmatter.sidebar !== void 0) {
1050
+ lines.push("sidebar:");
1051
+ const sidebar = frontmatter.sidebar;
1052
+ if (sidebar.label !== void 0) {
1053
+ lines.push(` label: ${yamlString(sidebar.label)}`);
1054
+ }
1055
+ if (sidebar.order !== void 0) {
1056
+ lines.push(` order: ${sidebar.order}`);
1057
+ }
1058
+ if (sidebar.hidden !== void 0) {
1059
+ lines.push(` hidden: ${sidebar.hidden}`);
1060
+ }
1061
+ if (sidebar.badge !== void 0) {
1062
+ if (typeof sidebar.badge === "string") {
1063
+ lines.push(` badge: ${yamlString(sidebar.badge)}`);
1064
+ } else {
1065
+ lines.push(" badge:");
1066
+ lines.push(` text: ${yamlString(sidebar.badge.text)}`);
1067
+ if (sidebar.badge.variant !== void 0) {
1068
+ lines.push(` variant: ${sidebar.badge.variant}`);
1069
+ }
1070
+ }
1071
+ }
1072
+ }
1073
+ if (frontmatter.tableOfContents !== void 0) {
1074
+ if (typeof frontmatter.tableOfContents === "boolean") {
1075
+ lines.push(`tableOfContents: ${frontmatter.tableOfContents}`);
1076
+ } else {
1077
+ lines.push("tableOfContents:");
1078
+ if (frontmatter.tableOfContents.minHeadingLevel !== void 0) {
1079
+ lines.push(` minHeadingLevel: ${frontmatter.tableOfContents.minHeadingLevel}`);
1080
+ }
1081
+ if (frontmatter.tableOfContents.maxHeadingLevel !== void 0) {
1082
+ lines.push(` maxHeadingLevel: ${frontmatter.tableOfContents.maxHeadingLevel}`);
1083
+ }
1084
+ }
1085
+ }
1086
+ if (frontmatter.template !== void 0) {
1087
+ lines.push(`template: ${frontmatter.template}`);
1088
+ }
1089
+ if (frontmatter.hero !== void 0) {
1090
+ lines.push("hero:");
1091
+ const hero = frontmatter.hero;
1092
+ if (hero.title !== void 0) {
1093
+ lines.push(` title: ${yamlString(hero.title)}`);
1094
+ }
1095
+ if (hero.tagline !== void 0) {
1096
+ lines.push(` tagline: ${yamlString(hero.tagline)}`);
1097
+ }
1098
+ if (hero.image !== void 0) {
1099
+ lines.push(" image:");
1100
+ lines.push(` src: ${yamlString(hero.image.src)}`);
1101
+ lines.push(` alt: ${yamlString(hero.image.alt)}`);
1102
+ }
1103
+ if (hero.actions !== void 0 && hero.actions.length > 0) {
1104
+ lines.push(" actions:");
1105
+ for (const action of hero.actions) {
1106
+ lines.push(` - text: ${yamlString(action.text)}`);
1107
+ lines.push(` link: ${yamlString(action.link)}`);
1108
+ if (action.icon !== void 0) {
1109
+ lines.push(` icon: ${yamlString(action.icon)}`);
1110
+ }
1111
+ if (action.variant !== void 0) {
1112
+ lines.push(` variant: ${action.variant}`);
1113
+ }
1114
+ }
1115
+ }
1116
+ }
1117
+ return lines.join("\n");
1118
+ }
1119
+ function yamlString(value) {
1120
+ if (needsQuoting(value)) {
1121
+ return `'${value.replaceAll("'", "''")}'`;
1122
+ }
1123
+ return value;
1124
+ }
1125
+ function needsQuoting(value) {
1126
+ if (value.length === 0) {
1127
+ return true;
1128
+ }
1129
+ if (value.startsWith(" ") || value.endsWith(" ")) {
1130
+ return true;
1131
+ }
1132
+ const specialChars = /[:#{}[\]&*?|<>=!%@`"',]/;
1133
+ if (specialChars.test(value)) {
1134
+ return true;
1135
+ }
1136
+ const reserved = ["true", "false", "null", "yes", "no", "on", "off"];
1137
+ if (reserved.includes(value.toLowerCase())) {
1138
+ return true;
1139
+ }
1140
+ if (/^-?\d+(?:\.\d+)?$/.test(value)) {
1141
+ return true;
1142
+ }
1143
+ return false;
1144
+ }
1145
+ function parseFrontmatter(yaml) {
1146
+ const result = {};
1147
+ const lines = yaml.split("\n");
1148
+ for (const line of lines) {
1149
+ const trimmedLine = line.trim();
1150
+ if (trimmedLine.startsWith("title:")) {
1151
+ const value = trimmedLine.slice(6).trim();
1152
+ result.title = stripQuotes(value);
1153
+ }
1154
+ if (trimmedLine.startsWith("description:")) {
1155
+ const value = trimmedLine.slice(12).trim();
1156
+ result.description = stripQuotes(value);
1157
+ }
1158
+ }
1159
+ return result;
1160
+ }
1161
+ function stripQuotes(value) {
1162
+ if (value.startsWith("'") && value.endsWith("'") || value.startsWith('"') && value.endsWith('"')) {
1163
+ return value.slice(1, -1);
1164
+ }
1165
+ return value;
1166
+ }
1167
+
1168
+ // src/generators/mdx-generator.ts
1169
+ import { err as err2, ok as ok2 } from "@bfra.me/es/result";
1170
+
1171
+ // src/utils/safe-patterns.ts
1172
+ import remarkParse from "remark-parse";
1173
+ import { unified } from "unified";
1174
+ function createHeadingPattern(level) {
1175
+ if (level < 1 || level > 6) {
1176
+ throw new Error("Heading level must be between 1 and 6");
1177
+ }
1178
+ const hashes = "#".repeat(level);
1179
+ return new RegExp(`^${hashes} ([^\r
1180
+ ]+)$`, "gm");
1181
+ }
1182
+ function hasComponent(content, componentName) {
1183
+ const escaped = componentName.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
1184
+ const pattern = new RegExp(String.raw`<${escaped}(?:\s[^>]*)?(?:>|\/>)`);
1185
+ return pattern.test(content);
1186
+ }
1187
+ function extractCodeBlocks(content) {
1188
+ const processor = unified().use(remarkParse);
1189
+ let tree;
1190
+ try {
1191
+ tree = processor.parse(content);
1192
+ } catch {
1193
+ return [];
1194
+ }
1195
+ const blocks = [];
1196
+ function visit(node) {
1197
+ if (node.type === "code") {
1198
+ const lang = node.lang ?? "";
1199
+ const value = node.value ?? "";
1200
+ blocks.push(`\`\`\`${lang}
1201
+ ${value}
1202
+ \`\`\``);
1203
+ }
1204
+ if (Array.isArray(node.children)) {
1205
+ for (const child of node.children) {
1206
+ visit(child);
1207
+ }
1208
+ }
1209
+ }
1210
+ visit(tree);
1211
+ return blocks;
1212
+ }
1213
+ function parseJSXTags(content) {
1214
+ const results = [];
1215
+ let i = 0;
1216
+ while (i < content.length) {
1217
+ if (content[i] !== "<") {
1218
+ i++;
1219
+ continue;
1220
+ }
1221
+ const startIndex = i;
1222
+ i++;
1223
+ if (i >= content.length) break;
1224
+ const isClosing = content[i] === "/";
1225
+ if (isClosing) {
1226
+ i++;
1227
+ if (i >= content.length) break;
1228
+ }
1229
+ if (!/^[A-Z]/.test(content[i] ?? "")) {
1230
+ continue;
1231
+ }
1232
+ let tagName = "";
1233
+ while (i < content.length && /^[a-z0-9]/i.test(content[i] ?? "")) {
1234
+ tagName += content[i];
1235
+ i++;
1236
+ }
1237
+ if (tagName.length === 0) {
1238
+ continue;
1239
+ }
1240
+ if (isClosing) {
1241
+ if (i < content.length && content[i] === ">") {
1242
+ results.push({
1243
+ tag: `</${tagName}>`,
1244
+ index: startIndex,
1245
+ isClosing: true,
1246
+ isSelfClosing: false
1247
+ });
1248
+ i++;
1249
+ }
1250
+ continue;
1251
+ }
1252
+ let depth = 0;
1253
+ let foundEnd = false;
1254
+ let isSelfClosing = false;
1255
+ while (i < content.length && !foundEnd) {
1256
+ const char = content[i];
1257
+ if ((char === '"' || char === "'") && depth === 0) {
1258
+ const quote = char;
1259
+ i++;
1260
+ while (i < content.length && content[i] !== quote) {
1261
+ if (content[i] === "\\" && i + 1 < content.length) {
1262
+ i += 2;
1263
+ } else {
1264
+ i++;
1265
+ }
1266
+ }
1267
+ if (i < content.length) i++;
1268
+ continue;
1269
+ }
1270
+ if (char === "{") {
1271
+ depth++;
1272
+ i++;
1273
+ continue;
1274
+ }
1275
+ if (char === "}") {
1276
+ depth = Math.max(0, depth - 1);
1277
+ i++;
1278
+ continue;
1279
+ }
1280
+ if (depth === 0) {
1281
+ if (char === "/" && i + 1 < content.length && content[i + 1] === ">") {
1282
+ isSelfClosing = true;
1283
+ foundEnd = true;
1284
+ i += 2;
1285
+ continue;
1286
+ }
1287
+ if (char === ">") {
1288
+ foundEnd = true;
1289
+ i++;
1290
+ continue;
1291
+ }
1292
+ }
1293
+ i++;
1294
+ }
1295
+ if (foundEnd) {
1296
+ const fullTag = content.slice(startIndex, i);
1297
+ results.push({ tag: fullTag, index: startIndex, isClosing: false, isSelfClosing });
1298
+ }
1299
+ }
1300
+ return results;
1301
+ }
1302
+ function findEmptyMarkdownLinks(content) {
1303
+ const positions = [];
1304
+ let pos = 0;
1305
+ while (pos < content.length) {
1306
+ const openBracket = content.indexOf("[", pos);
1307
+ if (openBracket === -1) break;
1308
+ let bracketDepth = 1;
1309
+ let closeBracket = openBracket + 1;
1310
+ while (closeBracket < content.length && bracketDepth > 0) {
1311
+ if (content[closeBracket] === "[") {
1312
+ bracketDepth++;
1313
+ } else if (content[closeBracket] === "]") {
1314
+ bracketDepth--;
1315
+ }
1316
+ closeBracket++;
1317
+ }
1318
+ if (bracketDepth !== 0) {
1319
+ pos = openBracket + 1;
1320
+ continue;
1321
+ }
1322
+ closeBracket--;
1323
+ if (closeBracket + 1 < content.length && content[closeBracket + 1] === "(") {
1324
+ let parenPos = closeBracket + 2;
1325
+ let isEmptyOrWhitespace = true;
1326
+ while (parenPos < content.length && content[parenPos] !== ")") {
1327
+ if (!/^\s/.test(content[parenPos] ?? "")) {
1328
+ isEmptyOrWhitespace = false;
1329
+ break;
1330
+ }
1331
+ parenPos++;
1332
+ }
1333
+ if (isEmptyOrWhitespace && parenPos < content.length && content[parenPos] === ")") {
1334
+ positions.push(openBracket);
1335
+ }
1336
+ }
1337
+ pos = closeBracket + 1;
1338
+ }
1339
+ return positions;
1340
+ }
1341
+
1342
+ // src/generators/mdx-generator.ts
1343
+ var DEFAULT_OPTIONS2 = {
1344
+ includeAPI: true,
1345
+ includeExamples: true,
1346
+ preserveManualContent: true
1347
+ };
1348
+ var STARLIGHT_IMPORTS = `import { Badge, Card, CardGrid, Tabs, TabItem } from '@astrojs/starlight/components';`;
1349
+ function generateMDXDocument(packageInfo, readme, api, options = {}) {
1350
+ const mergedOptions = { ...DEFAULT_OPTIONS2, ...options };
1351
+ try {
1352
+ const frontmatter = generateFrontmatter(packageInfo, readme, options.frontmatterOverrides);
1353
+ const contentSections = buildContentSections(packageInfo, readme, api, mergedOptions);
1354
+ const content = contentSections.join("\n\n");
1355
+ const rendered = renderMDXDocument(frontmatter, content);
1356
+ return ok2({
1357
+ frontmatter,
1358
+ content,
1359
+ rendered
1360
+ });
1361
+ } catch (error) {
1362
+ return err2({
1363
+ code: "GENERATION_ERROR",
1364
+ message: `Failed to generate MDX for ${packageInfo.name}: ${error instanceof Error ? error.message : String(error)}`,
1365
+ packageName: packageInfo.name,
1366
+ cause: error
1367
+ });
1368
+ }
1369
+ }
1370
+ function buildContentSections(packageInfo, readme, api, options) {
1371
+ const sections = [];
1372
+ sections.push(STARLIGHT_IMPORTS);
1373
+ sections.push("");
1374
+ sections.push(generatePackageHeader(packageInfo));
1375
+ if (readme !== void 0) {
1376
+ const mappedContent = mapToStarlightComponents(readme, packageInfo);
1377
+ sections.push(mappedContent);
1378
+ }
1379
+ if (options.includeAPI && api !== void 0 && hasAPIContent(api)) {
1380
+ sections.push(SENTINEL_MARKERS.AUTO_START);
1381
+ sections.push("");
1382
+ sections.push("## API Reference");
1383
+ sections.push("");
1384
+ sections.push(generateAPIReference(api));
1385
+ if (options.includeExamples) {
1386
+ const examples = formatCodeExamples(api);
1387
+ if (examples.length > 0) {
1388
+ sections.push("");
1389
+ sections.push("## Examples");
1390
+ sections.push("");
1391
+ sections.push(examples);
1392
+ }
1393
+ }
1394
+ sections.push("");
1395
+ sections.push(SENTINEL_MARKERS.AUTO_END);
1396
+ }
1397
+ return sections;
1398
+ }
1399
+ function generatePackageHeader(packageInfo) {
1400
+ const lines = [];
1401
+ lines.push(`# ${packageInfo.name}`);
1402
+ lines.push("");
1403
+ const badges = [];
1404
+ if (packageInfo.keywords?.includes("cli")) {
1405
+ badges.push(`<Badge text="CLI Tool" variant="tip" />`);
1406
+ } else if (packageInfo.keywords?.includes("library")) {
1407
+ badges.push(`<Badge text="Library" variant="tip" />`);
1408
+ } else if (packageInfo.keywords?.includes("config")) {
1409
+ badges.push(`<Badge text="Config" variant="tip" />`);
1410
+ }
1411
+ badges.push(`<Badge text="${sanitizeAttribute(`v${packageInfo.version}`)}" variant="note" />`);
1412
+ if (badges.length > 0) {
1413
+ lines.push(badges.join("\n"));
1414
+ lines.push("");
1415
+ }
1416
+ if (packageInfo.description !== void 0) {
1417
+ lines.push(packageInfo.description);
1418
+ lines.push("");
1419
+ }
1420
+ return lines.join("\n");
1421
+ }
1422
+ function hasAPIContent(api) {
1423
+ return api.functions.length > 0 || api.types.length > 0;
1424
+ }
1425
+ function renderMDXDocument(frontmatter, content) {
1426
+ const frontmatterYaml = stringifyFrontmatter(frontmatter);
1427
+ return `---
1428
+ ${frontmatterYaml}
1429
+ ---
1430
+
1431
+ ${content}
1432
+ `;
1433
+ }
1434
+ function sanitizeContent(content) {
1435
+ return sanitizeForMDX(content);
1436
+ }
1437
+ function sanitizeTextContent(content) {
1438
+ const jsxTags = parseJSXTags(content);
1439
+ const parts = [];
1440
+ let lastIndex = 0;
1441
+ for (const { tag, index, isClosing } of jsxTags) {
1442
+ if (index > lastIndex) {
1443
+ parts.push(sanitizeContent(content.slice(lastIndex, index)));
1444
+ }
1445
+ if (isClosing) {
1446
+ parts.push(tag);
1447
+ } else {
1448
+ parts.push(sanitizeJSXTag(tag));
1449
+ }
1450
+ lastIndex = index + tag.length;
1451
+ }
1452
+ if (lastIndex < content.length) {
1453
+ parts.push(sanitizeContent(content.slice(lastIndex)));
1454
+ }
1455
+ return parts.join("");
1456
+ }
1457
+ function validateMDXSyntax(mdx) {
1458
+ const unclosedTags = checkForUnclosedTags(mdx);
1459
+ if (unclosedTags.length > 0) {
1460
+ return err2({
1461
+ code: "VALIDATION_ERROR",
1462
+ message: `Unclosed MDX tags: ${unclosedTags.join(", ")}`
1463
+ });
1464
+ }
1465
+ const invalidFrontmatter = checkFrontmatter(mdx);
1466
+ if (invalidFrontmatter !== void 0) {
1467
+ return err2({
1468
+ code: "VALIDATION_ERROR",
1469
+ message: invalidFrontmatter
1470
+ });
1471
+ }
1472
+ return ok2(true);
1473
+ }
1474
+ function checkForUnclosedTags(mdx) {
1475
+ const unclosed = [];
1476
+ const tagStack = [];
1477
+ const codeBlocks = extractCodeBlocks(mdx);
1478
+ let contentWithoutCodeBlocks = mdx;
1479
+ for (const block of codeBlocks) {
1480
+ const lineCount = block.split("\n").length;
1481
+ const placeholder = "\n".repeat(lineCount);
1482
+ contentWithoutCodeBlocks = contentWithoutCodeBlocks.replace(block, placeholder);
1483
+ }
1484
+ const jsxTags = parseJSXTags(contentWithoutCodeBlocks);
1485
+ for (const { tag, isClosing, isSelfClosing } of jsxTags) {
1486
+ const tagNameMatch = isClosing ? tag.match(/^<\/([A-Z][a-zA-Z0-9]*)>$/) : tag.match(/^<([A-Z][a-zA-Z0-9]*)/);
1487
+ const tagName = tagNameMatch?.[1];
1488
+ if (tagName === void 0) continue;
1489
+ if (isClosing) {
1490
+ const lastOpenTag = tagStack.pop();
1491
+ if (lastOpenTag !== tagName && lastOpenTag !== void 0) {
1492
+ unclosed.push(lastOpenTag);
1493
+ }
1494
+ } else if (!isSelfClosing) {
1495
+ tagStack.push(tagName);
1496
+ }
1497
+ }
1498
+ unclosed.push(...tagStack);
1499
+ return unclosed;
1500
+ }
1501
+ function checkFrontmatter(mdx) {
1502
+ if (!mdx.startsWith("---")) {
1503
+ return "MDX document must start with frontmatter";
1504
+ }
1505
+ const secondDashIndex = mdx.indexOf("---", 3);
1506
+ if (secondDashIndex === -1) {
1507
+ return "Frontmatter is not properly closed";
1508
+ }
1509
+ const frontmatterContent = mdx.slice(3, secondDashIndex).trim();
1510
+ if (frontmatterContent.length === 0) {
1511
+ return "Frontmatter cannot be empty";
1512
+ }
1513
+ if (!frontmatterContent.includes("title:")) {
1514
+ return "Frontmatter must include a title";
1515
+ }
1516
+ return void 0;
1517
+ }
1518
+
1519
+ export {
1520
+ generateAPIReference,
1521
+ generateAPICompact,
1522
+ generateCategoryReference,
1523
+ formatCodeExamples,
1524
+ formatFunctionExamples,
1525
+ formatTypeExamples,
1526
+ formatCodeBlock,
1527
+ cleanCodeExample,
1528
+ detectLanguage,
1529
+ formatUsageExample,
1530
+ groupExamplesByCategory,
1531
+ formatGroupedExamples,
1532
+ mapToStarlightComponents,
1533
+ generateInstallTabs,
1534
+ createBadge,
1535
+ createCard,
1536
+ createCardGrid,
1537
+ createTabs,
1538
+ mergeContent,
1539
+ extractManualSections,
1540
+ extractAutoSections,
1541
+ hasManualContent,
1542
+ hasAutoContent,
1543
+ wrapManualSection,
1544
+ wrapAutoSection,
1545
+ stripSentinelMarkers,
1546
+ validateMarkerPairing,
1547
+ createDiffSummary,
1548
+ generateFrontmatter,
1549
+ stringifyFrontmatter,
1550
+ parseFrontmatter,
1551
+ createHeadingPattern,
1552
+ hasComponent,
1553
+ extractCodeBlocks,
1554
+ findEmptyMarkdownLinks,
1555
+ generateMDXDocument,
1556
+ sanitizeContent,
1557
+ sanitizeTextContent,
1558
+ validateMDXSyntax
1559
+ };
1560
+ //# sourceMappingURL=chunk-G5KKGJYO.js.map