@aigne/doc-smith 0.3.1 โ†’ 0.4.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.
@@ -1,9 +1,6 @@
1
1
  type: team
2
- name: retranslate
3
- alias:
4
- - rt
5
- - translate-again
6
- description: Re-translate individual document content to selected languages
2
+ name: translate
3
+ description: Translate document content to selected languages
7
4
  skills:
8
5
  - url: ./input-generator.mjs
9
6
  default_input:
@@ -11,6 +8,7 @@ skills:
11
8
  - ./load-config.mjs
12
9
  - ./load-sources.mjs
13
10
  - type: transform
11
+ task_render_mode: hide
14
12
  jsonata: |
15
13
  $merge([
16
14
  $,
@@ -26,49 +24,39 @@ skills:
26
24
  })
27
25
  }
28
26
  ])
29
- - url: ./find-item-by-path.mjs
27
+ - url: ./find-items-by-paths.mjs
30
28
  default_input:
31
29
  isTranslate: true
32
30
  - ./language-selector.mjs
33
- - type: transform
34
- jsonata: |
35
- $merge([
36
- $,
37
- {
38
- 'translates': [$map(selectedLanguages, function($lang) { {"language": $lang} })]
39
- }
40
- ])
41
- - ./batch-translate.yaml
42
- - url: ./save-single-doc.mjs
31
+ - type: team
32
+ name: batchDocsTranslate
33
+ skills:
34
+ - ./batch-translate.yaml
35
+ - url: ./save-single-doc.mjs
36
+ default_input:
37
+ isTranslate: true
38
+ iterate_on: selectedDocs
39
+ concurrency: 3
40
+ - url: ./action-success.mjs
43
41
  default_input:
44
- isTranslate: true
45
- isShowMessage: true
42
+ action: "Document translated"
46
43
  input_schema:
47
44
  type: object
48
45
  properties:
49
46
  glossary:
50
47
  type: string
51
- description: Glossary of terms for consistent terminology
52
- doc-path:
53
- type: string
54
- description: Document path to retranslate
55
- # languages:
56
- # type: array
57
- # items:
58
- # type: string
59
- # description: Languages to translate to
48
+ description: Glossary of terms for consistent terminology, use @<file> to read from a file
49
+ docs:
50
+ type: array
51
+ items:
52
+ type: string
53
+ description: Document paths to translate
54
+ langs:
55
+ type: array
56
+ items:
57
+ type: string
58
+ description: Languages to translate to
60
59
  feedback:
61
60
  type: string
62
61
  description: Feedback for translation improvement
63
- output_schema:
64
- type: object
65
- properties:
66
- title:
67
- type: string
68
- description:
69
- type: string
70
- path:
71
- type: string
72
- content:
73
- type: string
74
62
  mode: sequential
@@ -1,4 +1,4 @@
1
- name: translate
1
+ name: translateDoc
2
2
  description: Translate the wiki article to another language
3
3
  instructions:
4
4
  url: ../prompts/translator.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/doc-smith",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -22,8 +22,10 @@
22
22
  <goal>
23
23
  ไฝ ็š„ไธป่ฆ็›ฎๆ ‡ๆ˜ฏ้ชŒ่ฏไธ‰ๆกๅ…ณ้”ฎ่ง„ๅˆ™๏ผš
24
24
  1. **ๅ้ฆˆ็š„ๅฎž็Žฐ**๏ผšๆ–ฐ็š„็ป“ๆž„่ง„ๅˆ’**ๅฟ…้กป**ๆญฃ็กฎๅœฐๅฎž็Žฐ็”จๆˆทๅ้ฆˆไธญ่ฆๆฑ‚็š„ๆ‰€ๆœ‰ๅ˜ๆ›ดใ€‚
25
- 2. **ๆ— ๅ…ณ่Š‚็‚น็š„็จณๅฎšๆ€ง**๏ผšๆฒกๆœ‰ๅœจ็”จๆˆทๅ้ฆˆไธญ่ขซๆๅŠ็š„่Š‚็‚น ** pathใ€sourcesIds ๅฑžๆ€งไธ่ƒฝ่ขซไฟฎๆ”น **ใ€‚`path`ใ€`sourcesIds` ๆ˜ฏๅ…ณ่”็Žฐๆœ‰ๅ†…ๅฎน็š„ๅ…ณ้”ฎๆ ‡่ฏ†็ฌฆ๏ผŒๅ…ถ็จณๅฎšๆ€ง่‡ณๅ…ณ้‡่ฆใ€‚
26
- 3. **ๆ•ฐๆฎๆœ‰ๆ•ˆๆ€ง**: ๆ‰€ๆœ‰ {{ nodeName }} ้ƒฝๆœ‰ๅ…ณ่”ๆ•ฐๆฎๆบ๏ผŒsourceIds ไธญ้ƒฝๆœ‰ๅ€ผใ€‚
25
+ 2. **ๆ— ๅ…ณ่Š‚็‚น็š„็จณๅฎšๆ€ง**๏ผšๆฒกๆœ‰ๅœจ็”จๆˆทๅ้ฆˆไธญ่ขซๆๅŠ็š„่Š‚็‚น ** pathใ€sourcesIds ๅฑžๆ€งไธ่ƒฝ่ขซไฟฎๆ”น **
26
+ - `path`ใ€`sourcesIds` ๆ˜ฏๅ…ณ่”็Žฐๆœ‰ๅ†…ๅฎน็š„ๅ…ณ้”ฎๆ ‡่ฏ†็ฌฆ๏ผŒๅ…ถ็จณๅฎšๆ€ง่‡ณๅ…ณ้‡่ฆใ€‚
27
+ - ๅฏนไบŽ็”จๆˆท่ฆๆฑ‚ๆ–ฐๅขž่Š‚็‚น็š„ๅœบๆ™ฏ๏ผŒๆ–ฐๅขž็š„่Š‚็‚นๅฏ่ƒฝไผšๅฝฑๅ“ๅŽŸๆฅ่Š‚็‚น็š„้กบๅบ๏ผŒ่ฟ™ๆ˜ฏๅ…่ฎธ็š„ใ€‚
28
+ 4. **ๆ•ฐๆฎๆœ‰ๆ•ˆๆ€ง**: ๆ‰€ๆœ‰ {{ nodeName }} ้ƒฝๆœ‰ๅ…ณ่”ๆ•ฐๆฎๆบ๏ผŒsourceIds ไธญ้ƒฝๆœ‰ๅ€ผใ€‚
27
29
  </goal>
28
30
 
29
31
  <rules>
@@ -0,0 +1,370 @@
1
+ import { existsSync } from "node:fs";
2
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { saveValueToConfig } from "../utils/utils.mjs";
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ // Test directory for isolated testing
11
+ const TEST_DIR = join(__dirname, "temp-config-test");
12
+ const TEST_CONFIG_DIR = join(TEST_DIR, ".aigne", "doc-smith");
13
+ const TEST_CONFIG_PATH = join(TEST_CONFIG_DIR, "config.yaml");
14
+
15
+ // Setup and teardown helpers
16
+ async function setupTestDir() {
17
+ if (existsSync(TEST_DIR)) {
18
+ await rm(TEST_DIR, { recursive: true, force: true });
19
+ }
20
+ await mkdir(TEST_DIR, { recursive: true });
21
+
22
+ // Change to test directory for the duration of tests
23
+ process.chdir(TEST_DIR);
24
+ }
25
+
26
+ async function teardownTestDir() {
27
+ // Change back to original directory
28
+ process.chdir(dirname(TEST_DIR));
29
+
30
+ if (existsSync(TEST_DIR)) {
31
+ await rm(TEST_DIR, { recursive: true, force: true });
32
+ }
33
+ }
34
+
35
+ async function readConfigFile() {
36
+ if (!existsSync(TEST_CONFIG_PATH)) {
37
+ return "";
38
+ }
39
+ return await readFile(TEST_CONFIG_PATH, "utf8");
40
+ }
41
+
42
+ async function createInitialConfig(content) {
43
+ await mkdir(TEST_CONFIG_DIR, { recursive: true });
44
+ await writeFile(TEST_CONFIG_PATH, content, "utf8");
45
+ }
46
+
47
+ // Test utilities
48
+ function assertContains(content, expected, message) {
49
+ if (!content.includes(expected)) {
50
+ throw new Error(
51
+ `${message}\nExpected content to contain: ${expected}\nActual content:\n${content}`,
52
+ );
53
+ }
54
+ }
55
+
56
+ function assertNotContains(content, unexpected, message) {
57
+ if (content.includes(unexpected)) {
58
+ throw new Error(
59
+ `${message}\nExpected content NOT to contain: ${unexpected}\nActual content:\n${content}`,
60
+ );
61
+ }
62
+ }
63
+
64
+ function assertEqual(actual, expected, message) {
65
+ if (actual !== expected) {
66
+ throw new Error(`${message}\nExpected: ${expected}\nActual: ${actual}`);
67
+ }
68
+ }
69
+
70
+ // Test cases
71
+ const tests = [
72
+ // Test 1: Save string value to empty file
73
+ {
74
+ name: "Save string value to empty file",
75
+ async run() {
76
+ await saveValueToConfig("projectName", "test-project");
77
+ const content = await readConfigFile();
78
+
79
+ assertContains(
80
+ content,
81
+ 'projectName: "test-project"',
82
+ "Should save string value with quotes",
83
+ );
84
+ },
85
+ },
86
+
87
+ // Test 2: Save string value with comment to empty file
88
+ {
89
+ name: "Save string value with comment to empty file",
90
+ async run() {
91
+ await saveValueToConfig("projectDesc", "A test project", "Project description");
92
+ const content = await readConfigFile();
93
+
94
+ assertContains(content, "# Project description", "Should include comment");
95
+ assertContains(content, 'projectDesc: "A test project"', "Should save string value");
96
+ },
97
+ },
98
+
99
+ // Test 3: Save array value to empty file
100
+ {
101
+ name: "Save array value to empty file",
102
+ async run() {
103
+ await saveValueToConfig("translateLanguages", ["zh", "ja", "ko"]);
104
+ const content = await readConfigFile();
105
+
106
+ assertContains(content, "translateLanguages:", "Should have array key");
107
+ assertContains(content, " - zh", "Should have first array item");
108
+ assertContains(content, " - ja", "Should have second array item");
109
+ assertContains(content, " - ko", "Should have third array item");
110
+ },
111
+ },
112
+
113
+ // Test 4: Save empty array
114
+ {
115
+ name: "Save empty array",
116
+ async run() {
117
+ await saveValueToConfig("emptyArray", []);
118
+ const content = await readConfigFile();
119
+
120
+ assertContains(content, "emptyArray: []", "Should save empty array as []");
121
+ },
122
+ },
123
+
124
+ // Test 5: Save array with comment
125
+ {
126
+ name: "Save array with comment",
127
+ async run() {
128
+ await saveValueToConfig("sourcePaths", ["./src", "./lib"], "Source code paths");
129
+ const content = await readConfigFile();
130
+
131
+ assertContains(content, "# Source code paths", "Should include comment");
132
+ assertContains(content, "sourcePaths:", "Should have array key");
133
+ assertContains(content, " - ./src", "Should have first path");
134
+ assertContains(content, " - ./lib", "Should have second path");
135
+ },
136
+ },
137
+
138
+ // Test 6: Update existing string value
139
+ {
140
+ name: "Update existing string value",
141
+ async run() {
142
+ await createInitialConfig('projectName: "old-project"\nversion: "1.0.0"');
143
+
144
+ await saveValueToConfig("projectName", "new-project");
145
+ const content = await readConfigFile();
146
+
147
+ assertContains(content, 'projectName: "new-project"', "Should update string value");
148
+ assertContains(content, 'version: "1.0.0"', "Should preserve other values");
149
+ assertNotContains(content, "old-project", "Should not contain old value");
150
+ },
151
+ },
152
+
153
+ // Test 7: Update existing array value
154
+ {
155
+ name: "Update existing array value",
156
+ async run() {
157
+ await createInitialConfig(`translateLanguages:
158
+ - en
159
+ - fr
160
+ version: "1.0.0"`);
161
+
162
+ await saveValueToConfig("translateLanguages", ["zh", "ja"]);
163
+ const content = await readConfigFile();
164
+
165
+ assertContains(content, "translateLanguages:", "Should have array key");
166
+ assertContains(content, " - zh", "Should have new first item");
167
+ assertContains(content, " - ja", "Should have new second item");
168
+ assertNotContains(content, " - en", "Should not contain old first item");
169
+ assertNotContains(content, " - fr", "Should not contain old second item");
170
+ assertContains(content, 'version: "1.0.0"', "Should preserve other values");
171
+ },
172
+ },
173
+
174
+ // Test 8: Update array to empty array
175
+ {
176
+ name: "Update array to empty array",
177
+ async run() {
178
+ await createInitialConfig(`translateLanguages:
179
+ - en
180
+ - fr
181
+ version: "1.0.0"`);
182
+
183
+ await saveValueToConfig("translateLanguages", []);
184
+ const content = await readConfigFile();
185
+
186
+ assertContains(content, "translateLanguages: []", "Should update to empty array");
187
+ assertNotContains(content, " - en", "Should remove old items");
188
+ assertContains(content, 'version: "1.0.0"', "Should preserve other values");
189
+ },
190
+ },
191
+
192
+ // Test 9: Update empty array to populated array
193
+ {
194
+ name: "Update empty array to populated array",
195
+ async run() {
196
+ await createInitialConfig(`translateLanguages: []
197
+ version: "1.0.0"`);
198
+
199
+ await saveValueToConfig("translateLanguages", ["zh", "ja"]);
200
+ const content = await readConfigFile();
201
+
202
+ assertContains(content, "translateLanguages:", "Should have array key");
203
+ assertContains(content, " - zh", "Should have first item");
204
+ assertContains(content, " - ja", "Should have second item");
205
+ assertNotContains(content, "translateLanguages: []", "Should not contain empty array format");
206
+ assertContains(content, 'version: "1.0.0"', "Should preserve other values");
207
+ },
208
+ },
209
+
210
+ // Test 10: Add comment to existing value without comment
211
+ {
212
+ name: "Add comment to existing value without comment",
213
+ async run() {
214
+ await createInitialConfig('projectName: "test-project"\nversion: "1.0.0"');
215
+
216
+ await saveValueToConfig("projectName", "updated-project", "Updated project name");
217
+ const content = await readConfigFile();
218
+
219
+ assertContains(content, "# Updated project name", "Should add comment");
220
+ assertContains(content, 'projectName: "updated-project"', "Should update value");
221
+ },
222
+ },
223
+
224
+ // Test 11: Update value that already has comment
225
+ {
226
+ name: "Update value that already has comment",
227
+ async run() {
228
+ await createInitialConfig(`# Project information
229
+ projectName: "old-project"
230
+ version: "1.0.0"`);
231
+
232
+ await saveValueToConfig("projectName", "new-project", "Updated project info");
233
+ const content = await readConfigFile();
234
+
235
+ assertContains(content, "# Project information", "Should preserve existing comment");
236
+ assertContains(content, 'projectName: "new-project"', "Should update value");
237
+ assertNotContains(content, "# Updated project info", "Should not add duplicate comment");
238
+ },
239
+ },
240
+
241
+ // Test 12: Complex array with various items
242
+ {
243
+ name: "Complex array with various items",
244
+ async run() {
245
+ const complexArray = ["./src/components", "./lib/utils", "./modules/auth"];
246
+ await saveValueToConfig("sourcePaths", complexArray, "All source paths");
247
+ const content = await readConfigFile();
248
+
249
+ assertContains(content, "# All source paths", "Should include comment");
250
+ assertContains(content, "sourcePaths:", "Should have array key");
251
+ assertContains(content, " - ./src/components", "Should have first complex path");
252
+ assertContains(content, " - ./lib/utils", "Should have second complex path");
253
+ assertContains(content, " - ./modules/auth", "Should have third complex path");
254
+ },
255
+ },
256
+
257
+ // Test 13: Mixed content preservation
258
+ {
259
+ name: "Mixed content preservation",
260
+ async run() {
261
+ await createInitialConfig(`# Project configuration
262
+ projectName: "original-project"
263
+ translateLanguages:
264
+ - en
265
+ - fr
266
+ # Other settings
267
+ version: "1.0.0"
268
+ locale: en`);
269
+
270
+ await saveValueToConfig("translateLanguages", ["zh", "ja", "ko"], "Updated languages");
271
+ const content = await readConfigFile();
272
+
273
+ assertContains(content, "# Project configuration", "Should preserve file header comment");
274
+ assertContains(content, 'projectName: "original-project"', "Should preserve string value");
275
+ assertContains(content, "# Updated languages", "Should add new comment");
276
+ assertContains(content, "translateLanguages:", "Should have updated array key");
277
+ assertContains(content, " - zh", "Should have new array items");
278
+ assertContains(content, " - ja", "Should have new array items");
279
+ assertContains(content, " - ko", "Should have new array items");
280
+ assertContains(content, "# Other settings", "Should preserve other comments");
281
+ assertContains(content, 'version: "1.0.0"', "Should preserve other values");
282
+ assertContains(content, "locale: en", "Should preserve other values");
283
+ assertNotContains(content, " - en", "Should remove old array items");
284
+ assertNotContains(content, " - fr", "Should remove old array items");
285
+ },
286
+ },
287
+
288
+ // Test 14: Array in middle of file
289
+ {
290
+ name: "Array in middle of file",
291
+ async run() {
292
+ await createInitialConfig(`projectName: "test-project"
293
+ translateLanguages:
294
+ - en
295
+ - fr
296
+ locale: en
297
+ version: "1.0.0"`);
298
+
299
+ await saveValueToConfig("translateLanguages", ["zh"]);
300
+ const content = await readConfigFile();
301
+
302
+ assertContains(content, 'projectName: "test-project"', "Should preserve content before");
303
+ assertContains(content, "translateLanguages:", "Should have array key");
304
+ assertContains(content, " - zh", "Should have new array item");
305
+ assertContains(content, "locale: en", "Should preserve content after");
306
+ assertContains(content, 'version: "1.0.0"', "Should preserve content after");
307
+ assertNotContains(content, " - en", "Should remove old items");
308
+ assertNotContains(content, " - fr", "Should remove old items");
309
+ },
310
+ },
311
+
312
+ // Test 15: Handle undefined values
313
+ {
314
+ name: "Handle undefined values",
315
+ async run() {
316
+ const initialContent = 'projectName: "test-project"';
317
+ await createInitialConfig(initialContent);
318
+
319
+ await saveValueToConfig("undefinedKey", undefined);
320
+ const content = await readConfigFile();
321
+
322
+ assertEqual(content, initialContent, "Should not modify file when value is undefined");
323
+ },
324
+ },
325
+ ];
326
+
327
+ // Run all tests
328
+ async function runTests() {
329
+ console.log("๐Ÿงช Running saveValueToConfig tests...\n");
330
+
331
+ let passed = 0;
332
+ let failed = 0;
333
+
334
+ for (const test of tests) {
335
+ try {
336
+ await setupTestDir();
337
+ await test.run();
338
+ console.log(`โœ… ${test.name}`);
339
+ passed++;
340
+ } catch (error) {
341
+ console.log(`โŒ ${test.name}`);
342
+ console.log(` Error: ${error.message}\n`);
343
+ failed++;
344
+ } finally {
345
+ await teardownTestDir();
346
+ }
347
+ }
348
+
349
+ console.log(`\n๐Ÿ“Š Test Results:`);
350
+ console.log(` Passed: ${passed}`);
351
+ console.log(` Failed: ${failed}`);
352
+ console.log(` Total: ${tests.length}`);
353
+
354
+ if (failed > 0) {
355
+ console.log(`\nโŒ ${failed} test(s) failed`);
356
+ process.exit(1);
357
+ } else {
358
+ console.log(`\n๐ŸŽ‰ All tests passed!`);
359
+ }
360
+ }
361
+
362
+ // Run tests if this file is executed directly
363
+ if (import.meta.url === `file://${process.argv[1]}`) {
364
+ runTests().catch((error) => {
365
+ console.error("Test runner failed:", error);
366
+ process.exit(1);
367
+ });
368
+ }
369
+
370
+ export { runTests, tests };
@@ -8,14 +8,14 @@ import open from "open";
8
8
  import { joinURL } from "ufo";
9
9
  import { parse, stringify } from "yaml";
10
10
  import {
11
+ ComponentNotFoundError,
11
12
  getComponentMountPoint,
12
13
  InvalidBlockletError,
13
- ComponentNotFoundError,
14
14
  } from "./blocklet.mjs";
15
15
  import {
16
+ BLOCKLET_ADD_COMPONENT_DOCS,
16
17
  DISCUSS_KIT_DID,
17
18
  DISCUSS_KIT_STORE_URL,
18
- BLOCKLET_ADD_COMPONENT_DOCS,
19
19
  } from "./constants.mjs";
20
20
 
21
21
  const WELLKNOWN_SERVICE_PATH_PREFIX = "/.well-known/service";
@@ -324,6 +324,9 @@ export const DISCUSS_KIT_STORE_URL =
324
324
  export const BLOCKLET_ADD_COMPONENT_DOCS =
325
325
  "https://www.arcblock.io/docs/blocklet-developer/en/7zbw0GQXgcD6sCcjVfwqqT2s";
326
326
 
327
+ // Supported file extensions for content reading
328
+ export const SUPPORTED_FILE_EXTENSIONS = [".txt", ".md", ".json", ".yaml", ".yml"];
329
+
327
330
  // Conflict rules configuration for documentation generation
328
331
  export const CONFLICT_RULES = {
329
332
  // Internal conflicts within the same question (multi-select conflicts)