@aigne/doc-smith 0.5.1 → 0.7.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.
- package/.github/workflows/ci.yml +46 -0
- package/.github/workflows/reviewer.yml +2 -1
- package/CHANGELOG.md +17 -0
- package/agents/chat.yaml +30 -0
- package/agents/check-detail-result.mjs +2 -1
- package/agents/check-detail.mjs +1 -0
- package/agents/check-structure-plan.mjs +1 -1
- package/agents/docs-fs.yaml +25 -0
- package/agents/exit.mjs +6 -0
- package/agents/feedback-refiner.yaml +5 -1
- package/agents/find-items-by-paths.mjs +10 -4
- package/agents/fs.mjs +60 -0
- package/agents/input-generator.mjs +159 -90
- package/agents/load-config.mjs +0 -5
- package/agents/load-sources.mjs +119 -12
- package/agents/publish-docs.mjs +28 -11
- package/agents/retranslate.yaml +1 -1
- package/agents/team-publish-docs.yaml +2 -2
- package/aigne.yaml +1 -0
- package/package.json +13 -10
- package/prompts/content-detail-generator.md +12 -4
- package/prompts/document/custom-components.md +80 -0
- package/prompts/document/d2-chart/diy-examples.md +44 -0
- package/prompts/document/d2-chart/official-examples.md +708 -0
- package/prompts/document/d2-chart/rules.md +48 -0
- package/prompts/document/detail-generator.md +13 -15
- package/prompts/document/structure-planning.md +1 -3
- package/prompts/feedback-refiner.md +81 -60
- package/prompts/structure-planning.md +20 -3
- package/tests/check-detail-result.test.mjs +50 -2
- package/tests/conflict-resolution.test.mjs +237 -0
- package/tests/input-generator.test.mjs +940 -0
- package/tests/load-sources.test.mjs +627 -3
- package/tests/preferences-utils.test.mjs +94 -0
- package/tests/save-value-to-config.test.mjs +182 -5
- package/tests/utils.test.mjs +49 -0
- package/utils/auth-utils.mjs +1 -1
- package/utils/conflict-detector.mjs +72 -1
- package/utils/constants.mjs +139 -126
- package/utils/kroki-utils.mjs +162 -0
- package/utils/markdown-checker.mjs +175 -67
- package/utils/utils.mjs +97 -29
package/utils/constants.mjs
CHANGED
|
@@ -86,15 +86,27 @@ export const DEFAULT_INCLUDE_PATTERNS = [
|
|
|
86
86
|
"*.yml",
|
|
87
87
|
"*Dockerfile",
|
|
88
88
|
"*Makefile",
|
|
89
|
+
// Media files
|
|
90
|
+
"*.jpg",
|
|
91
|
+
"*.jpeg",
|
|
92
|
+
"*.png",
|
|
93
|
+
"*.gif",
|
|
94
|
+
"*.bmp",
|
|
95
|
+
"*.webp",
|
|
96
|
+
"*.svg",
|
|
97
|
+
"*.mp4",
|
|
98
|
+
"*.mov",
|
|
99
|
+
"*.avi",
|
|
100
|
+
"*.mkv",
|
|
101
|
+
"*.webm",
|
|
102
|
+
"*.m4v",
|
|
89
103
|
];
|
|
90
104
|
|
|
91
105
|
export const DEFAULT_EXCLUDE_PATTERNS = [
|
|
92
106
|
"**/aigne-docs/**",
|
|
93
107
|
"**/doc-smith/**",
|
|
94
108
|
"**/.aigne/**",
|
|
95
|
-
"**/assets/**",
|
|
96
109
|
"**/data/**",
|
|
97
|
-
"**/images/**",
|
|
98
110
|
"**/public/**",
|
|
99
111
|
"**/static/**",
|
|
100
112
|
"**/vendor/**",
|
|
@@ -331,79 +343,8 @@ export const SUPPORTED_FILE_EXTENSIONS = [".txt", ".md", ".json", ".yaml", ".yml
|
|
|
331
343
|
export const CONFLICT_RULES = {
|
|
332
344
|
// Internal conflicts within the same question (multi-select conflicts)
|
|
333
345
|
internalConflicts: {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
conflictItems: ["getStarted", "findAnswers"],
|
|
337
|
-
severity: "severe",
|
|
338
|
-
reason:
|
|
339
|
-
"Quick start guide (skips complex cases) conflicts with comprehensive API reference (skips beginner explanations)",
|
|
340
|
-
suggestion: "Choose one as primary goal, or consider creating layered documentation",
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
conflictItems: ["getStarted", "understandSystem"],
|
|
344
|
-
severity: "severe",
|
|
345
|
-
reason: "30-minute quick start conflicts with deep architectural concept explanations",
|
|
346
|
-
suggestion: "Consider creating separate quick start and architecture design docs",
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
conflictItems: ["completeTasks", "understandSystem"],
|
|
350
|
-
severity: "moderate",
|
|
351
|
-
reason:
|
|
352
|
-
"Practical task guidance and theoretical concept explanation have different focuses",
|
|
353
|
-
suggestion:
|
|
354
|
-
"Can be handled through layered document structure: concepts first, then practice",
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
conflictItems: ["getStarted", "solveProblems"],
|
|
358
|
-
severity: "moderate",
|
|
359
|
-
reason:
|
|
360
|
-
"Quick start (success cases) and troubleshooting (error scenarios) have different focuses",
|
|
361
|
-
suggestion: "Create separate tutorial and troubleshooting guides",
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
conflictItems: ["findAnswers", "solveProblems"],
|
|
365
|
-
severity: "moderate",
|
|
366
|
-
reason: "API reference and diagnostic documentation have different organizational logic",
|
|
367
|
-
suggestion: "Add troubleshooting section to reference documentation",
|
|
368
|
-
},
|
|
369
|
-
],
|
|
370
|
-
targetAudienceTypes: [
|
|
371
|
-
{
|
|
372
|
-
conflictItems: ["endUsers", "developers"],
|
|
373
|
-
severity: "severe",
|
|
374
|
-
reason:
|
|
375
|
-
"Non-technical users (avoid technical terms) conflict with developers (code-first approach)",
|
|
376
|
-
suggestion:
|
|
377
|
-
"Create separate documentation for different audiences or use layered content design",
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
conflictItems: ["endUsers", "devops"],
|
|
381
|
-
severity: "severe",
|
|
382
|
-
reason: "Non-technical users and operations technical personnel have very different needs",
|
|
383
|
-
suggestion: "Consider creating separate user guides and operations documentation",
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
conflictItems: ["endUsers", "decisionMakers"],
|
|
387
|
-
severity: "severe",
|
|
388
|
-
reason:
|
|
389
|
-
"Non-technical users (simple language) and decision makers (architecture diagrams) have different needs",
|
|
390
|
-
suggestion: "Create high-level overview for management and user operation manuals",
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
conflictItems: ["developers", "decisionMakers"],
|
|
394
|
-
severity: "moderate",
|
|
395
|
-
reason:
|
|
396
|
-
"Developers (code details) and decision makers (high-level overview) have different focus areas",
|
|
397
|
-
suggestion: "Use progressive disclosure: high-level first, then details",
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
conflictItems: ["supportTeams", "decisionMakers"],
|
|
401
|
-
severity: "moderate",
|
|
402
|
-
reason:
|
|
403
|
-
"Support teams (problem diagnosis) and decision makers (architecture decisions) have different focus areas",
|
|
404
|
-
suggestion: "Include operational considerations in decision documentation",
|
|
405
|
-
},
|
|
406
|
-
],
|
|
346
|
+
// Note: Most conflicts can be resolved through intelligent document structure planning
|
|
347
|
+
// Only keeping conflicts that represent fundamental incompatibilities
|
|
407
348
|
},
|
|
408
349
|
|
|
409
350
|
// Cross-question conflicts (conflicts between different questions)
|
|
@@ -471,66 +412,138 @@ export const CONFLICT_RULES = {
|
|
|
471
412
|
readerKnowledgeLevel: ["emergencyTroubleshooting"],
|
|
472
413
|
},
|
|
473
414
|
},
|
|
415
|
+
],
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
// Conflict resolution rules - defines how to handle conflicts when users select conflicting options
|
|
419
|
+
export const CONFLICT_RESOLUTION_RULES = {
|
|
420
|
+
// Document purpose conflicts that can be resolved through structure planning
|
|
421
|
+
documentPurpose: [
|
|
474
422
|
{
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
},
|
|
479
|
-
severity: "severe",
|
|
480
|
-
reason: "Quick start tutorials contradict comprehensive coverage documentation",
|
|
481
|
-
action: "filter",
|
|
482
|
-
conflictingOptions: {
|
|
483
|
-
documentationDepth: ["comprehensive"],
|
|
484
|
-
},
|
|
423
|
+
conflictItems: ["getStarted", "findAnswers"],
|
|
424
|
+
strategy: "layered_structure",
|
|
425
|
+
description: "Quick start and API reference conflict, resolved through layered structure",
|
|
485
426
|
},
|
|
486
427
|
{
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
severity: "moderate",
|
|
492
|
-
reason:
|
|
493
|
-
"Troubleshooting usually needs to cover edge cases, basic content alone may not be sufficient",
|
|
494
|
-
action: "filter",
|
|
495
|
-
conflictingOptions: {
|
|
496
|
-
documentationDepth: ["essentialOnly"],
|
|
497
|
-
},
|
|
428
|
+
conflictItems: ["getStarted", "understandSystem"],
|
|
429
|
+
strategy: "separate_sections",
|
|
430
|
+
description:
|
|
431
|
+
"Quick start and system understanding conflict, resolved through separate sections",
|
|
498
432
|
},
|
|
499
433
|
{
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
severity: "moderate",
|
|
505
|
-
reason: "Non-technical users typically do not need comprehensive technical coverage",
|
|
506
|
-
action: "filter",
|
|
507
|
-
conflictingOptions: {
|
|
508
|
-
documentationDepth: ["comprehensive"],
|
|
509
|
-
},
|
|
434
|
+
conflictItems: ["completeTasks", "understandSystem"],
|
|
435
|
+
strategy: "concepts_then_practice",
|
|
436
|
+
description:
|
|
437
|
+
"Task guidance and system understanding conflict, resolved through concepts-then-practice structure",
|
|
510
438
|
},
|
|
511
439
|
{
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
severity: "moderate",
|
|
517
|
-
reason: "Decision makers may need more comprehensive information to make decisions",
|
|
518
|
-
action: "filter",
|
|
519
|
-
conflictingOptions: {
|
|
520
|
-
documentationDepth: ["essentialOnly"],
|
|
521
|
-
},
|
|
440
|
+
conflictItems: ["findAnswers", "solveProblems"],
|
|
441
|
+
strategy: "reference_with_troubleshooting",
|
|
442
|
+
description:
|
|
443
|
+
"API reference and problem solving conflict, resolved through reference with troubleshooting",
|
|
522
444
|
},
|
|
445
|
+
],
|
|
446
|
+
|
|
447
|
+
// Target audience conflicts that can be resolved through structure planning
|
|
448
|
+
targetAudienceTypes: [
|
|
523
449
|
{
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
450
|
+
conflictItems: ["endUsers", "developers"],
|
|
451
|
+
strategy: "separate_user_paths",
|
|
452
|
+
description: "End users and developers conflict, resolved through separate user paths",
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
conflictItems: ["endUsers", "devops"],
|
|
456
|
+
strategy: "role_based_sections",
|
|
457
|
+
description: "End users and DevOps conflict, resolved through role-based sections",
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
conflictItems: ["developers", "decisionMakers"],
|
|
461
|
+
strategy: "progressive_disclosure",
|
|
462
|
+
description:
|
|
463
|
+
"Developers and decision makers conflict, resolved through progressive disclosure",
|
|
534
464
|
},
|
|
535
465
|
],
|
|
536
466
|
};
|
|
467
|
+
|
|
468
|
+
// Resolution strategy descriptions
|
|
469
|
+
export const RESOLUTION_STRATEGIES = {
|
|
470
|
+
layered_structure: (items) =>
|
|
471
|
+
`Detected "${items.join('" and "')}" purpose conflict. Resolution strategy: Create layered document structure
|
|
472
|
+
- Quick start section: Uses "get started" style - optimizes for speed, key steps, working examples, skips complex edge cases
|
|
473
|
+
- API reference section: Uses "find answers" style - comprehensive coverage, searchability, rich examples, skips narrative flow
|
|
474
|
+
- Ensure sections complement rather than conflict with each other`,
|
|
475
|
+
|
|
476
|
+
separate_sections: (items) =>
|
|
477
|
+
`Detected "${items.join('" and "')}" purpose conflict. Resolution strategy: Create separate sections
|
|
478
|
+
- Quick start section: Uses "get started" style - focuses on practical operations, completable within 30 minutes
|
|
479
|
+
- System understanding section: Uses "understand system" style - dedicated to explaining architecture, concepts, design decision rationale
|
|
480
|
+
- Meet different depth needs through clear section separation`,
|
|
481
|
+
|
|
482
|
+
concepts_then_practice: (items) =>
|
|
483
|
+
`Detected "${items.join('" and "')}" purpose conflict. Resolution strategy: Use progressive "concepts-then-practice" structure
|
|
484
|
+
- Concepts section: Uses "understand system" style - first explains core concepts and architecture principles
|
|
485
|
+
- Practice section: Uses "complete tasks" style - then provides specific step guidance and practical scenarios
|
|
486
|
+
- Ensure smooth transition between theory and practice`,
|
|
487
|
+
|
|
488
|
+
reference_with_troubleshooting: (items) =>
|
|
489
|
+
`Detected "${items.join('" and "')}" purpose conflict. Resolution strategy: Integrate troubleshooting into API reference
|
|
490
|
+
- API reference section: Uses "find answers" style - comprehensive feature documentation and parameter descriptions
|
|
491
|
+
- Troubleshooting section: Uses "solve problems" style - add common issues and diagnostic methods for each feature
|
|
492
|
+
- Create dedicated problem diagnosis index for quick location`,
|
|
493
|
+
|
|
494
|
+
separate_user_paths: (items) =>
|
|
495
|
+
`Detected "${items.join('" and "')}" audience conflict. Resolution strategy: Create separate user paths
|
|
496
|
+
- User guide path: Uses "end users" style - simple language, UI operations, screenshot instructions, business outcome oriented
|
|
497
|
+
- Developer guide path: Uses "developers" style - code-first, technical precision, SDK examples, configuration snippets
|
|
498
|
+
- Provide clear path navigation for users to choose appropriate entry point`,
|
|
499
|
+
|
|
500
|
+
role_based_sections: (items) =>
|
|
501
|
+
`Detected "${items.join('" and "')}" audience conflict. Resolution strategy: Organize content by role
|
|
502
|
+
- Create dedicated sections for different roles, each section uses corresponding audience style
|
|
503
|
+
- Ensure content depth and expression precisely match the needs and background of corresponding audience
|
|
504
|
+
- Provide cross-references between sections to facilitate collaborative understanding between roles`,
|
|
505
|
+
|
|
506
|
+
progressive_disclosure: (items) =>
|
|
507
|
+
`Detected "${items.join('" and "')}" audience conflict. Resolution strategy: Use progressive information disclosure
|
|
508
|
+
- Overview level: Uses "decision makers" style - high-level architecture diagrams, decision points, business value
|
|
509
|
+
- Detail level: Uses "developers" style - technical implementation details, code examples, best practices
|
|
510
|
+
- Ensure smooth transition from strategic to tactical`,
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
export const D2_CONFIG = `vars: {
|
|
514
|
+
d2-config: {
|
|
515
|
+
layout-engine: elk
|
|
516
|
+
theme-id: 0
|
|
517
|
+
theme-overrides: {
|
|
518
|
+
N1: "#2AA7A1"
|
|
519
|
+
N2: "#73808C"
|
|
520
|
+
|
|
521
|
+
N4: "#FFFFFF"
|
|
522
|
+
N5: "#FAFBFC"
|
|
523
|
+
|
|
524
|
+
N7: "#ffffff"
|
|
525
|
+
|
|
526
|
+
B1: "#8EDDD9"
|
|
527
|
+
B2: "#C9DCE6"
|
|
528
|
+
B3: "#EEF9F9"
|
|
529
|
+
B4: "#F7F8FA"
|
|
530
|
+
B5: "#FCFDFD"
|
|
531
|
+
B6: "#E3E9F0"
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
AA2: "#9EB7C5"
|
|
535
|
+
AA4: "#E3EBF2"
|
|
536
|
+
AA5: "#F6FAFC"
|
|
537
|
+
|
|
538
|
+
AB4: "#B8F1F6"
|
|
539
|
+
AB5: "#E3F8FA"
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}`;
|
|
543
|
+
|
|
544
|
+
export const KROKI_CONCURRENCY = 5;
|
|
545
|
+
export const FILE_CONCURRENCY = 3;
|
|
546
|
+
export const TMP_DIR = ".tmp";
|
|
547
|
+
export const TMP_DOCS_DIR = "docs";
|
|
548
|
+
|
|
549
|
+
export const TMP_ASSETS_DIR = "assets";
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import { glob } from "glob";
|
|
5
|
+
import pMap from "p-map";
|
|
6
|
+
import { joinURL } from "ufo";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
D2_CONFIG,
|
|
10
|
+
FILE_CONCURRENCY,
|
|
11
|
+
KROKI_CONCURRENCY,
|
|
12
|
+
TMP_ASSETS_DIR,
|
|
13
|
+
TMP_DIR,
|
|
14
|
+
} from "./constants.mjs";
|
|
15
|
+
import { getContentHash } from "./utils.mjs";
|
|
16
|
+
|
|
17
|
+
export async function getChart({ chart = "d2", format = "svg", content, strict }) {
|
|
18
|
+
const baseUrl = "https://chart.abtnet.io";
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const res = await fetch(joinURL(baseUrl, chart, format), {
|
|
22
|
+
method: "POST",
|
|
23
|
+
body: content,
|
|
24
|
+
headers: {
|
|
25
|
+
Accept: "image/svg+xml",
|
|
26
|
+
"Content-Type": "text/plain",
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
if (strict && !res.ok) {
|
|
30
|
+
throw new Error(`Failed to fetch chart: ${res.status} ${res.statusText}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const data = await res.text();
|
|
34
|
+
return data;
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (strict) throw err;
|
|
37
|
+
|
|
38
|
+
console.error("Failed to generate chart from:", baseUrl, err);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function getD2Svg({ content, strict = false }) {
|
|
44
|
+
const svgContent = await getChart({
|
|
45
|
+
chart: "d2",
|
|
46
|
+
format: "svg",
|
|
47
|
+
content,
|
|
48
|
+
strict,
|
|
49
|
+
});
|
|
50
|
+
return svgContent;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Helper: save d2 svg assets alongside document
|
|
54
|
+
export async function saveD2Assets({ markdown, docsDir }) {
|
|
55
|
+
const codeBlockRegex = /```d2\n([\s\S]*?)```/g;
|
|
56
|
+
|
|
57
|
+
const { replaced } = await runIterator({
|
|
58
|
+
input: markdown,
|
|
59
|
+
regexp: codeBlockRegex,
|
|
60
|
+
replace: true,
|
|
61
|
+
fn: async ([_match, _code]) => {
|
|
62
|
+
const assetDir = path.join(docsDir, "../", TMP_ASSETS_DIR, "d2");
|
|
63
|
+
await fs.ensureDir(assetDir);
|
|
64
|
+
const d2Content = [D2_CONFIG, _code].join("\n");
|
|
65
|
+
const fileName = `${getContentHash(d2Content)}.svg`;
|
|
66
|
+
const svgPath = path.join(assetDir, fileName);
|
|
67
|
+
|
|
68
|
+
if (await fs.pathExists(svgPath)) {
|
|
69
|
+
if (process.env.DEBUG) {
|
|
70
|
+
console.log("Found assets cache, skipping generation", svgPath);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
if (process.env.DEBUG) {
|
|
74
|
+
console.log("start generate d2 chart", svgPath);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const svg = await getD2Svg({ content: d2Content });
|
|
78
|
+
if (svg) {
|
|
79
|
+
await fs.writeFile(svgPath, svg, { encoding: "utf8" });
|
|
80
|
+
}
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (process.env.DEBUG) {
|
|
83
|
+
console.warn("Failed to generate D2 chart:", error);
|
|
84
|
+
}
|
|
85
|
+
return _code;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return ``;
|
|
89
|
+
},
|
|
90
|
+
options: { concurrency: KROKI_CONCURRENCY },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return replaced;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function beforePublishHook({ docsDir }) {
|
|
97
|
+
// Example: process each markdown file (replace with your logic)
|
|
98
|
+
const mdFilePaths = await glob("**/*.md", { cwd: docsDir });
|
|
99
|
+
await pMap(
|
|
100
|
+
mdFilePaths,
|
|
101
|
+
async (filePath) => {
|
|
102
|
+
let finalContent = await fs.readFile(path.join(docsDir, filePath), { encoding: "utf8" });
|
|
103
|
+
finalContent = await saveD2Assets({ markdown: finalContent, docsDir });
|
|
104
|
+
|
|
105
|
+
await fs.writeFile(path.join(docsDir, filePath), finalContent, { encoding: "utf8" });
|
|
106
|
+
},
|
|
107
|
+
{ concurrency: FILE_CONCURRENCY },
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function runIterator({ input, regexp, fn = () => {}, options, replace = false }) {
|
|
112
|
+
if (!input) return input;
|
|
113
|
+
const matches = [...input.matchAll(regexp)];
|
|
114
|
+
const results = [];
|
|
115
|
+
await pMap(
|
|
116
|
+
matches,
|
|
117
|
+
async (...args) => {
|
|
118
|
+
const resultItem = await fn(...args);
|
|
119
|
+
results.push(resultItem);
|
|
120
|
+
},
|
|
121
|
+
options,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
let replaced = input;
|
|
125
|
+
if (replace) {
|
|
126
|
+
let index = 0;
|
|
127
|
+
replaced = replaced.replace(regexp, () => {
|
|
128
|
+
return results[index++];
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
results,
|
|
134
|
+
replaced,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function checkD2Content({ content }) {
|
|
139
|
+
await ensureTmpDir();
|
|
140
|
+
const assetDir = path.join(".aigne", "doc-smith", TMP_DIR, TMP_ASSETS_DIR, "d2");
|
|
141
|
+
await fs.ensureDir(assetDir);
|
|
142
|
+
const d2Content = [D2_CONFIG, content].join("\n");
|
|
143
|
+
const fileName = `${getContentHash(d2Content)}.svg`;
|
|
144
|
+
const svgPath = path.join(assetDir, fileName);
|
|
145
|
+
if (await fs.pathExists(svgPath)) {
|
|
146
|
+
if (process.env.DEBUG) {
|
|
147
|
+
console.log("Found assets cache, skipping generation", svgPath);
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const svg = await getD2Svg({ content: d2Content, strict: true });
|
|
153
|
+
await fs.writeFile(svgPath, svg, { encoding: "utf8" });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function ensureTmpDir() {
|
|
157
|
+
const tmpDir = path.join(".aigne", "doc-smith", TMP_DIR);
|
|
158
|
+
if (!(await fs.pathExists(path.join(tmpDir, ".gitignore")))) {
|
|
159
|
+
await fs.ensureDir(tmpDir);
|
|
160
|
+
await fs.writeFile(path.join(tmpDir, ".gitignore"), "**/*", { encoding: "utf8" });
|
|
161
|
+
}
|
|
162
|
+
}
|