@aigne/doc-smith 0.9.5 → 0.9.6-beta
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/CHANGELOG.md +13 -0
- package/agents/init/check.mjs +1 -1
- package/agents/update/check-generate-diagram.mjs +4 -3
- package/agents/update/update-single/update-single-document-detail.mjs +140 -0
- package/agents/update/user-review-document.mjs +1 -1
- package/aigne.yaml +1 -0
- package/package.json +1 -1
- package/prompts/detail/diagram/user-prompt.md +17 -0
- package/prompts/detail/generate/system-prompt.md +0 -1
- package/prompts/detail/update/system-prompt.md +40 -32
- package/utils/auth-utils.mjs +32 -16
- package/utils/d2-utils.mjs +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.6-beta](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.5...v0.9.6-beta) (2025-11-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* smaller granularity of updated single-document ([#320](https://github.com/AIGNE-io/aigne-doc-smith/issues/320)) ([588b924](https://github.com/AIGNE-io/aigne-doc-smith/commit/588b924649f5f116a07586a1f6760ee6f7e79953))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* always use short url during doc publish process ([#319](https://github.com/AIGNE-io/aigne-doc-smith/issues/319)) ([5fcf067](https://github.com/AIGNE-io/aigne-doc-smith/commit/5fcf067c2caf822576ee60e3f58a69040e5813f4))
|
|
14
|
+
* tune document detail update output constraint ([#322](https://github.com/AIGNE-io/aigne-doc-smith/issues/322)) ([6ac8aa4](https://github.com/AIGNE-io/aigne-doc-smith/commit/6ac8aa49e9bb761164c60ccddc4b601b9c612203))
|
|
15
|
+
|
|
3
16
|
## [0.9.5](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.5-beta.1...v0.9.5) (2025-11-14)
|
|
4
17
|
|
|
5
18
|
## [0.9.5-beta.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.5-beta...v0.9.5-beta.1) (2025-11-14)
|
package/agents/init/check.mjs
CHANGED
|
@@ -11,6 +11,6 @@ export default async function checkNeedGenerate({ docsDir, locale, documentExecu
|
|
|
11
11
|
process.exit(0);
|
|
12
12
|
}
|
|
13
13
|
return {
|
|
14
|
-
message: 'Documents found in the docs directory, skipping "
|
|
14
|
+
message: 'Documents found in the docs directory, skipping "create" step',
|
|
15
15
|
};
|
|
16
16
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { DIAGRAM_PLACEHOLDER } from "../../utils/d2-utils.mjs";
|
|
2
|
+
|
|
2
3
|
const DEFAULT_DIAGRAMMING_EFFORT = 5;
|
|
3
4
|
const MIN_DIAGRAMMING_EFFORT = 0;
|
|
4
5
|
const MAX_DIAGRAMMING_EFFORT = 10;
|
|
@@ -66,8 +67,8 @@ export default async function checkGenerateDiagram(
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
if (diagramSourceCode && !skipGenerateDiagram) {
|
|
69
|
-
if (content.includes(
|
|
70
|
-
content = content.replace(
|
|
70
|
+
if (content.includes(DIAGRAM_PLACEHOLDER)) {
|
|
71
|
+
content = content.replace(DIAGRAM_PLACEHOLDER, diagramSourceCode);
|
|
71
72
|
} else {
|
|
72
73
|
const mergeAgent = options.context?.agents?.["mergeDiagramToDocument"];
|
|
73
74
|
({ content } = await options.context.invoke(mergeAgent, {
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { AIAgent } from "@aigne/core";
|
|
2
|
+
import { pick } from "@aigne/core/utils/type-utils.js";
|
|
3
|
+
import z from "zod";
|
|
4
|
+
import { DIAGRAM_PLACEHOLDER, replacePlaceholder } from "../../../utils/d2-utils.mjs";
|
|
5
|
+
|
|
6
|
+
async function getIntentType(input, options) {
|
|
7
|
+
const instructions = `<role>
|
|
8
|
+
You are a feedback intent analyzer. Your task is to determine which type of content modifications are needed based on the user's feedback.
|
|
9
|
+
</role>
|
|
10
|
+
|
|
11
|
+
<user_feedback>
|
|
12
|
+
{{feedback}}
|
|
13
|
+
</user_feedback>`;
|
|
14
|
+
const analyzeUpdateFeedbackIntentAgent = AIAgent.from({
|
|
15
|
+
name: "analyzeUpdateFeedbackIntent",
|
|
16
|
+
description:
|
|
17
|
+
"Analyze user feedback to determine if document are needed for content modifications",
|
|
18
|
+
task_render_mode: "hide",
|
|
19
|
+
instructions,
|
|
20
|
+
// TODO: can't set reasoningEffort
|
|
21
|
+
// modelOptions: {
|
|
22
|
+
// reasoningEffort: 1,
|
|
23
|
+
// },
|
|
24
|
+
inputSchema: z.object({
|
|
25
|
+
feedback: z.string().describe("User feedback for content modifications"),
|
|
26
|
+
}),
|
|
27
|
+
outputSchema: z.object({
|
|
28
|
+
intentType: z
|
|
29
|
+
.enum(["addDiagram", "deleteDiagram", "updateDiagram", "updateDocument"])
|
|
30
|
+
.describe(
|
|
31
|
+
"The primary type of user intention: one of addDiagram, deleteDiagram, updateDiagram, updateDocument",
|
|
32
|
+
),
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
const { intentType } = await options.context.invoke(analyzeUpdateFeedbackIntentAgent, {
|
|
36
|
+
feedback: input.feedback,
|
|
37
|
+
});
|
|
38
|
+
return intentType;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function saveDoc(input, options, { content }) {
|
|
42
|
+
const saveAgent = options.context?.agents?.["saveDoc"];
|
|
43
|
+
await options.context.invoke(saveAgent, {
|
|
44
|
+
...pick(input, ["path", "docsDir", "labels", "locale"]),
|
|
45
|
+
content,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function addDiagram(input, options) {
|
|
50
|
+
const generateDiagramAgent = options.context.agents["checkGenerateDiagram"];
|
|
51
|
+
const generateDiagramResult = await options.context.invoke(generateDiagramAgent, {
|
|
52
|
+
...pick(input, ["locale", "path", "diagramming", "feedback"]),
|
|
53
|
+
documentContent: options.context.userContext.currentContent,
|
|
54
|
+
});
|
|
55
|
+
const content = generateDiagramResult.content;
|
|
56
|
+
await saveDoc(input, options, { content });
|
|
57
|
+
return { content };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function updateDiagram(input, options) {
|
|
61
|
+
let [content, previousDiagramContent] = replacePlaceholder({
|
|
62
|
+
content: options.context.userContext.currentContent,
|
|
63
|
+
});
|
|
64
|
+
const generateAgent = options.context?.agents?.["generateDiagram"];
|
|
65
|
+
const { diagramSourceCode } = await options.context.invoke(generateAgent, {
|
|
66
|
+
documentContent: content,
|
|
67
|
+
locale: input.locale,
|
|
68
|
+
previousDiagramContent,
|
|
69
|
+
feedback: input.feedback,
|
|
70
|
+
});
|
|
71
|
+
content = content.replace(DIAGRAM_PLACEHOLDER, diagramSourceCode);
|
|
72
|
+
await saveDoc(input, options, { content });
|
|
73
|
+
return { content };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function deleteDiagram(input, options) {
|
|
77
|
+
const [documentContent] = replacePlaceholder({
|
|
78
|
+
content: options.context.userContext.currentContent,
|
|
79
|
+
});
|
|
80
|
+
const instructions = `<role>
|
|
81
|
+
Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (based on the user's feedback) to make it easier to understand.
|
|
82
|
+
</role>
|
|
83
|
+
|
|
84
|
+
<document_content>
|
|
85
|
+
{{documentContent}}
|
|
86
|
+
</document_content>
|
|
87
|
+
|
|
88
|
+
<user_feedback>
|
|
89
|
+
{{feedback}}
|
|
90
|
+
</user_feedback>`;
|
|
91
|
+
const deleteAgent = AIAgent.from({
|
|
92
|
+
name: "deleteDiagram",
|
|
93
|
+
description: "Remove a diagram from the document content",
|
|
94
|
+
task_render_mode: "hide",
|
|
95
|
+
instructions,
|
|
96
|
+
inputSchema: z.object({
|
|
97
|
+
documentContent: z.string().describe("Source content of the document"),
|
|
98
|
+
feedback: z.string().describe("User feedback for content modifications"),
|
|
99
|
+
}),
|
|
100
|
+
outputKey: "message",
|
|
101
|
+
});
|
|
102
|
+
const { message: content } = await options.context.invoke(deleteAgent, {
|
|
103
|
+
documentContent,
|
|
104
|
+
feedback: input.feedback,
|
|
105
|
+
});
|
|
106
|
+
await saveDoc(input, options, { content });
|
|
107
|
+
|
|
108
|
+
return { content };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function updateDocument(input, options) {
|
|
112
|
+
const updateAgent = options.context.agents["updateDocumentDetail"];
|
|
113
|
+
const updateResult = await options.context.invoke(updateAgent, {
|
|
114
|
+
...input,
|
|
115
|
+
originalContent: options.context.userContext.currentContent,
|
|
116
|
+
});
|
|
117
|
+
if (updateResult.message === "success") {
|
|
118
|
+
await saveDoc(input, options, { content: options.context.userContext.currentContent });
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
content: options.context.userContext.currentContent,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default async function updateSingleDocumentDetail(input, options) {
|
|
126
|
+
const intentType = await getIntentType(input, options);
|
|
127
|
+
|
|
128
|
+
const fnMap = {
|
|
129
|
+
addDiagram,
|
|
130
|
+
updateDiagram,
|
|
131
|
+
deleteDiagram,
|
|
132
|
+
updateDocument,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
if (fnMap[intentType]) {
|
|
136
|
+
const result = await fnMap[intentType](input, options);
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
return {};
|
|
140
|
+
}
|
|
@@ -200,7 +200,7 @@ export default async function userReviewDocument({ content, description, ...rest
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
// Get the updateDocument agent
|
|
203
|
-
const updateAgent = options.context.agents["
|
|
203
|
+
const updateAgent = options.context.agents["updateSingleDocumentDetail"];
|
|
204
204
|
if (!updateAgent) {
|
|
205
205
|
console.log(
|
|
206
206
|
"We can't process your feedback right now. The document update feature is temporarily unavailable.",
|
package/aigne.yaml
CHANGED
package/package.json
CHANGED
|
@@ -9,6 +9,9 @@ Generate a d2 diagram that represents the following document content:
|
|
|
9
9
|
<user_rules>
|
|
10
10
|
|
|
11
11
|
- Output only the diagram labels and text in the {{ locale }} language — keep all variable names, component names, and syntax unchanged.
|
|
12
|
+
{% if previousDiagramContent %}
|
|
13
|
+
- Update the diagram based on `<feedback>` and `<previous_diagram_content>`.
|
|
14
|
+
{% endif %}
|
|
12
15
|
|
|
13
16
|
</user_rules>
|
|
14
17
|
|
|
@@ -24,3 +27,17 @@ Generate a d2 diagram that represents the following document content:
|
|
|
24
27
|
|
|
25
28
|
</diagram_check_feedback>
|
|
26
29
|
{% endif %}
|
|
30
|
+
|
|
31
|
+
{% if previousDiagramContent %}
|
|
32
|
+
<previous_diagram_content>
|
|
33
|
+
{{ previousDiagramContent }}
|
|
34
|
+
</previous_diagram_content>
|
|
35
|
+
|
|
36
|
+
{% if feedback %}
|
|
37
|
+
<feedback>
|
|
38
|
+
{{ feedback }}
|
|
39
|
+
</feedback>
|
|
40
|
+
{% endif %}
|
|
41
|
+
|
|
42
|
+
{% endif %}
|
|
43
|
+
|
|
@@ -3,9 +3,35 @@
|
|
|
3
3
|
</role_and_goal>
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
<task_instructions>
|
|
7
|
+
Your task is to:
|
|
8
|
+
|
|
9
|
+
Processing workflow:
|
|
10
|
+
- If user feedback is not in English, translate it to English first to better understand user intent
|
|
11
|
+
- Analyze user feedback to understand the exact intent and scope of changes
|
|
12
|
+
- Generate a unified diff patch that implements the requested improvements
|
|
13
|
+
- Use the available tool to apply the changes and get the final content
|
|
14
|
+
- Tool calls only need to return toolCalls information
|
|
15
|
+
- Ensure all modifications maintain document quality and consistency
|
|
16
|
+
- Return 'success' when the latest version of content meets user feedback(Don't add any explanation)
|
|
17
|
+
|
|
18
|
+
Tool usage guidelines:
|
|
19
|
+
|
|
20
|
+
**updateDocumentContent**: Use this tool to apply changes to the document content
|
|
21
|
+
- Generate a precise unified diff patch based on the user feedback
|
|
22
|
+
- Forbidden change diagram source code
|
|
23
|
+
- If user ask to add/update diagram, use `generateDiagram` tool instead.
|
|
24
|
+
- If user ask to remove diagram, should remove diagram content and update document context to get better understanding.
|
|
25
|
+
- The diff should include context lines for accurate application
|
|
26
|
+
- Only consider content within `<page_content>` tag when calculating line numbers, ensure line number calculation is accurate
|
|
27
|
+
- Test the patch application to ensure it works correctly
|
|
28
|
+
|
|
29
|
+
Error handling:
|
|
30
|
+
- If user intent is unclear, ask for clarification
|
|
31
|
+
- If the requested changes conflict with best practices, explain the issues and suggest alternatives
|
|
32
|
+
- If the diff patch fails to apply, revise the approach and try again
|
|
33
|
+
</task_instructions>
|
|
34
|
+
|
|
9
35
|
|
|
10
36
|
<current_document>
|
|
11
37
|
Current {{nodeName}} information:
|
|
@@ -16,6 +42,11 @@ parentId: {{parentId}}
|
|
|
16
42
|
</current_document>
|
|
17
43
|
|
|
18
44
|
|
|
45
|
+
<document_structure>
|
|
46
|
+
{{ documentStructureYaml }}
|
|
47
|
+
</document_structure>
|
|
48
|
+
|
|
49
|
+
|
|
19
50
|
{% if glossary %}
|
|
20
51
|
<terms>
|
|
21
52
|
Glossary of specialized terms. Please ensure correct spelling when using these terms.
|
|
@@ -39,7 +70,10 @@ Documentation content optimization rules:
|
|
|
39
70
|
|
|
40
71
|
{% include "../../common/document/media-file-list-usage-rules.md" %}
|
|
41
72
|
|
|
42
|
-
{% include "
|
|
73
|
+
{% include "../../common/document/openapi-usage-rules.md" %}
|
|
74
|
+
|
|
75
|
+
** Update Constraints: **
|
|
76
|
+
- Forbidden change diagram source code
|
|
43
77
|
|
|
44
78
|
</content_optimization_rules>
|
|
45
79
|
|
|
@@ -75,37 +109,11 @@ Analyze the user feedback to determine the specific improvements needed:
|
|
|
75
109
|
|
|
76
110
|
</feedback_analysis_guidelines>
|
|
77
111
|
|
|
78
|
-
<task_instructions>
|
|
79
|
-
Your task is to:
|
|
80
|
-
|
|
81
|
-
Processing workflow:
|
|
82
|
-
- If user feedback is not in English, translate it to English first to better understand user intent
|
|
83
|
-
- Analyze user feedback to understand the exact intent and scope of changes
|
|
84
|
-
- Generate a unified diff patch that implements the requested improvements
|
|
85
|
-
- Use the available tool to apply the changes and get the final content
|
|
86
|
-
- Tool calls only need to return toolCalls information
|
|
87
|
-
- Ensure all modifications maintain document quality and consistency
|
|
88
|
-
- Return 'success' when the latest version of content meets user feedback
|
|
89
|
-
|
|
90
|
-
Tool usage guidelines:
|
|
91
|
-
|
|
92
|
-
**updateDocumentContent**: Use this tool to apply changes to the document content
|
|
93
|
-
- Generate a precise unified diff patch based on the user feedback
|
|
94
|
-
- The diff should include context lines for accurate application
|
|
95
|
-
- Only consider content within `<page_content>` tag when calculating line numbers, ensure line number calculation is accurate
|
|
96
|
-
- Test the patch application to ensure it works correctly
|
|
97
|
-
|
|
98
|
-
Error handling:
|
|
99
|
-
- If user intent is unclear, ask for clarification
|
|
100
|
-
- If the requested changes conflict with best practices, explain the issues and suggest alternatives
|
|
101
|
-
- If the diff patch fails to apply, revise the approach and try again
|
|
102
|
-
</task_instructions>
|
|
103
|
-
|
|
104
112
|
{% include "../generate/detail-example.md" %}
|
|
105
113
|
|
|
106
114
|
|
|
107
|
-
<
|
|
115
|
+
<output_constraints>
|
|
108
116
|
** Only output operation execution status **:
|
|
109
117
|
- Only return 'success' if operation executed successfully
|
|
110
118
|
- Return brief error message if operation failed
|
|
111
|
-
</
|
|
119
|
+
</output_constraints>
|
package/utils/auth-utils.mjs
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
DISCUSS_KIT_STORE_URL,
|
|
22
22
|
PAYMENT_KIT_DID,
|
|
23
23
|
} from "./constants/index.mjs";
|
|
24
|
-
import { requestWithAuthToken } from "./request.mjs";
|
|
25
24
|
import { withQuery } from "ufo";
|
|
26
25
|
|
|
27
26
|
const WELLKNOWN_SERVICE_PATH_PREFIX = "/.well-known/service";
|
|
@@ -143,16 +142,15 @@ export async function getAccessToken(appUrl, ltToken = "", locale = "en") {
|
|
|
143
142
|
|
|
144
143
|
try {
|
|
145
144
|
const officialBaseUrl = process.env.DOC_SMITH_BASE_URL || CLOUD_SERVICE_URL_PROD;
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
);
|
|
145
|
+
const mountPoint = await getComponentMountPoint(officialBaseUrl, PAYMENT_KIT_DID);
|
|
146
|
+
const response = await fetch(
|
|
147
|
+
withQuery(joinURL(officialBaseUrl, mountPoint, "/api/tool/short-connect-url"), {
|
|
148
|
+
url: connectUrl,
|
|
149
|
+
locale,
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
const data = await response.json();
|
|
153
|
+
if (data.url) {
|
|
156
154
|
connectUrl = data.url;
|
|
157
155
|
}
|
|
158
156
|
} catch {
|
|
@@ -160,7 +158,7 @@ export async function getAccessToken(appUrl, ltToken = "", locale = "en") {
|
|
|
160
158
|
}
|
|
161
159
|
|
|
162
160
|
console.log(
|
|
163
|
-
"🔗 Please open the following URL in your browser to authorize access:
|
|
161
|
+
"🔗 Please open the following URL in your browser to authorize access:",
|
|
164
162
|
chalk.cyan(connectUrl),
|
|
165
163
|
"\n",
|
|
166
164
|
);
|
|
@@ -220,16 +218,34 @@ export async function getOfficialAccessToken(baseUrl, openPage = true, locale =
|
|
|
220
218
|
fetchInterval: FETCH_INTERVAL,
|
|
221
219
|
appName: "AIGNE DocSmith",
|
|
222
220
|
appLogo: "https://docsmith.aigne.io/image-bin/uploads/9645caf64b4232699982c4d940b03b90.svg",
|
|
223
|
-
openPage: (pageUrl) => {
|
|
221
|
+
openPage: async (pageUrl) => {
|
|
224
222
|
const url = new URL(pageUrl);
|
|
225
223
|
if (locale) {
|
|
226
224
|
url.searchParams.set("locale", locale);
|
|
227
225
|
}
|
|
228
|
-
|
|
226
|
+
|
|
227
|
+
let connectUrl = url.toString();
|
|
228
|
+
open(connectUrl);
|
|
229
|
+
try {
|
|
230
|
+
const officialBaseUrl = process.env.DOC_SMITH_BASE_URL || CLOUD_SERVICE_URL_PROD;
|
|
231
|
+
const mountPoint = await getComponentMountPoint(officialBaseUrl, PAYMENT_KIT_DID);
|
|
232
|
+
const response = await fetch(
|
|
233
|
+
withQuery(joinURL(officialBaseUrl, mountPoint, "/api/tool/short-connect-url"), {
|
|
234
|
+
url: connectUrl,
|
|
235
|
+
locale,
|
|
236
|
+
}),
|
|
237
|
+
);
|
|
238
|
+
const data = await response.json();
|
|
239
|
+
if (data.url) {
|
|
240
|
+
connectUrl = data.url;
|
|
241
|
+
}
|
|
242
|
+
} catch {
|
|
243
|
+
// Ignore error
|
|
244
|
+
}
|
|
229
245
|
|
|
230
246
|
console.log(
|
|
231
|
-
"🔗 Please open the following URL in your browser to authorize access:
|
|
232
|
-
chalk.cyan(
|
|
247
|
+
"🔗 Please open the following URL in your browser to authorize access:",
|
|
248
|
+
chalk.cyan(connectUrl),
|
|
233
249
|
"\n",
|
|
234
250
|
);
|
|
235
251
|
},
|
package/utils/d2-utils.mjs
CHANGED
|
@@ -19,6 +19,8 @@ import { getContentHash } from "./utils.mjs";
|
|
|
19
19
|
|
|
20
20
|
const codeBlockRegex = /```d2.*\n([\s\S]*?)```/g;
|
|
21
21
|
|
|
22
|
+
export const DIAGRAM_PLACEHOLDER = "DIAGRAM_PLACEHOLDER";
|
|
23
|
+
|
|
22
24
|
export async function getChart({ content, strict }) {
|
|
23
25
|
const d2 = new D2();
|
|
24
26
|
const iconUrlList = Object.keys(iconMap);
|
|
@@ -203,3 +205,14 @@ export function wrapCode({ content }) {
|
|
|
203
205
|
|
|
204
206
|
return `\`\`\`d2\n${content}\n\`\`\``;
|
|
205
207
|
}
|
|
208
|
+
|
|
209
|
+
export function replacePlaceholder({ content }) {
|
|
210
|
+
const [firstMatch] = Array.from(content.matchAll(codeBlockRegex));
|
|
211
|
+
if (firstMatch) {
|
|
212
|
+
const matchContent = firstMatch[0];
|
|
213
|
+
const cleanContent = content.replace(matchContent, DIAGRAM_PLACEHOLDER);
|
|
214
|
+
return [cleanContent, matchContent];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return [content, ""];
|
|
218
|
+
}
|