cloving 0.3.18 → 0.3.19
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/.DS_Store +0 -0
- package/.aider.chat.history.md +16978 -0
- package/.aider.input.history +15 -0
- package/.aider.tags.cache.v3/cache.db +0 -0
- package/.aider.tags.cache.v3/cache.db-shm +0 -0
- package/.aider.tags.cache.v3/cache.db-wal +0 -0
- package/.cursorrules +77 -0
- package/.github/workflows/auto-release.yml +83 -0
- package/.github/workflows/ci.yml +32 -0
- package/.github/workflows/npm-publish.yml +34 -0
- package/.gitignore +67 -0
- package/.husky/_/.gitignore +1 -0
- package/.husky/_/applypatch-msg +2 -0
- package/.husky/_/commit-msg +2 -0
- package/.husky/_/h +22 -0
- package/.husky/_/husky.sh +9 -0
- package/.husky/_/post-applypatch +2 -0
- package/.husky/_/post-checkout +2 -0
- package/.husky/_/post-commit +2 -0
- package/.husky/_/post-merge +2 -0
- package/.husky/_/post-rewrite +2 -0
- package/.husky/_/pre-applypatch +2 -0
- package/.husky/_/pre-auto-gc +2 -0
- package/.husky/_/pre-commit +2 -0
- package/.husky/_/pre-merge-commit +2 -0
- package/.husky/_/pre-push +2 -0
- package/.husky/_/pre-rebase +2 -0
- package/.husky/_/prepare-commit-msg +2 -0
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +1 -0
- package/.prettierrc.json +7 -0
- package/.tool-versions +2 -0
- package/SECURITY.md +15 -0
- package/cloving.json +67 -0
- package/dist/managers/CommitManager.js +8 -2
- package/dist/package.json +1 -1
- package/jest.config.js +11 -0
- package/package.json +1 -1
- package/src/cloving_gpt/adapters/azureopenai.ts +83 -0
- package/src/cloving_gpt/adapters/claude.ts +140 -0
- package/src/cloving_gpt/adapters/gemini.ts +146 -0
- package/src/cloving_gpt/adapters/index.ts +43 -0
- package/src/cloving_gpt/adapters/mistral.ts +142 -0
- package/src/cloving_gpt/adapters/ollama.ts +136 -0
- package/src/cloving_gpt/adapters/openai.ts +113 -0
- package/src/cloving_gpt/index.ts +229 -0
- package/src/commands/chat.ts +12 -0
- package/src/commands/config.ts +192 -0
- package/src/commands/generate/code.ts +18 -0
- package/src/commands/generate/commit.ts +9 -0
- package/src/commands/generate/context.ts +93 -0
- package/src/commands/generate/docs.ts +9 -0
- package/src/commands/generate/review.ts +9 -0
- package/src/commands/generate/shell.ts +9 -0
- package/src/commands/generate/unit_tests.ts +9 -0
- package/src/commands/init.ts +9 -0
- package/src/commands/models.ts +21 -0
- package/src/commands/proxy.ts +9 -0
- package/src/commands/tokens.ts +82 -0
- package/src/index.ts +197 -0
- package/src/managers/BlockManager.ts +126 -0
- package/src/managers/ChatManager.ts +755 -0
- package/src/managers/ChunkManager.ts +31 -0
- package/src/managers/CodeManager.ts +226 -0
- package/src/managers/CommitManager.ts +71 -0
- package/src/managers/DocsManager.ts +101 -0
- package/src/managers/InitManager.ts +263 -0
- package/src/managers/ProxyManager.ts +240 -0
- package/src/managers/ReviewManager.ts +154 -0
- package/src/managers/ShellManager.ts +172 -0
- package/src/managers/StreamManager.ts +353 -0
- package/src/managers/UnitTestManager.ts +293 -0
- package/src/utils/config_utils.ts +271 -0
- package/src/utils/git_utils.ts +230 -0
- package/src/utils/model_utils.ts +3 -0
- package/src/utils/prompt_utils.ts +375 -0
- package/src/utils/prompts/CODEGEN_COULDNT_APPLY.md +5 -0
- package/src/utils/prompts/CODEGEN_EXAMPLES.md +82 -0
- package/src/utils/prompts/CODEGEN_INSTRUCTIONS.md +43 -0
- package/src/utils/prompts/DOCS_INSTRUCTIONS.md +9 -0
- package/src/utils/prompts/INIT_INSTRUCTIONS.md +132 -0
- package/src/utils/prompts/REVIEW_INSTRUCTIONS.md +49 -0
- package/src/utils/prompts/SHELL_INSTRUCTIONS.md +15 -0
- package/src/utils/prompts/SPECIAL_FILES.md +66 -0
- package/src/utils/prompts/index.ts +37 -0
- package/src/utils/string_utils.ts +552 -0
- package/src/utils/types.ts +127 -0
- package/tests/commands/generate/unit_tests.test.ts +27 -0
- package/tests/utils/git_utils.test.ts +116 -0
- package/tests/utils/model_utils.test.ts +27 -0
- package/tests/utils/prompt_utils.test.ts +33 -0
- package/tests/utils/string_utils.test.ts +560 -0
- package/tsconfig.json +14 -0
- package/yarn.lock +5823 -0
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extractCurrentNewBlocks,
|
|
3
|
+
extractMarkdown,
|
|
4
|
+
searchReplaceString,
|
|
5
|
+
extractJsonMetadata,
|
|
6
|
+
} from '../../src/utils/string_utils'
|
|
7
|
+
|
|
8
|
+
describe('stringUtils', () => {
|
|
9
|
+
describe('extractCurrentNewBlocks', () => {
|
|
10
|
+
test('should extract current and new blocks from input', () => {
|
|
11
|
+
const input = `
|
|
12
|
+
\`\`\`typescript
|
|
13
|
+
<<<<<<< CURRENT src/file1.ts
|
|
14
|
+
const oldVar = 1
|
|
15
|
+
=======
|
|
16
|
+
const newVar = 2
|
|
17
|
+
>>>>>>> NEW
|
|
18
|
+
\`\`\`
|
|
19
|
+
|
|
20
|
+
Some text in between
|
|
21
|
+
|
|
22
|
+
\`\`\`typescript
|
|
23
|
+
<<<<<<< CURRENT src/file2.ts
|
|
24
|
+
function oldFunction() {
|
|
25
|
+
return 'old'
|
|
26
|
+
}
|
|
27
|
+
=======
|
|
28
|
+
function newFunction() {
|
|
29
|
+
return 'new'
|
|
30
|
+
}
|
|
31
|
+
>>>>>>> NEW
|
|
32
|
+
\`\`\`
|
|
33
|
+
`
|
|
34
|
+
|
|
35
|
+
const result = extractCurrentNewBlocks(input)
|
|
36
|
+
|
|
37
|
+
expect(result).toEqual([
|
|
38
|
+
{
|
|
39
|
+
language: 'typescript',
|
|
40
|
+
filePath: 'src/file1.ts',
|
|
41
|
+
currentContent: 'const oldVar = 1',
|
|
42
|
+
newContent: 'const newVar = 2',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
language: 'typescript',
|
|
46
|
+
filePath: 'src/file2.ts',
|
|
47
|
+
currentContent: "function oldFunction() {\n return 'old'\n}",
|
|
48
|
+
newContent: "function newFunction() {\n return 'new'\n}",
|
|
49
|
+
},
|
|
50
|
+
])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('should handle empty current content', () => {
|
|
54
|
+
const input = `
|
|
55
|
+
\`\`\`typescript
|
|
56
|
+
<<<<<<< CURRENT src/newfile.ts
|
|
57
|
+
=======
|
|
58
|
+
const newContent = 'This is new'
|
|
59
|
+
>>>>>>> NEW
|
|
60
|
+
\`\`\``
|
|
61
|
+
|
|
62
|
+
const result = extractCurrentNewBlocks(input)
|
|
63
|
+
|
|
64
|
+
expect(result).toEqual([
|
|
65
|
+
{
|
|
66
|
+
language: 'typescript',
|
|
67
|
+
filePath: 'src/newfile.ts',
|
|
68
|
+
currentContent: '',
|
|
69
|
+
newContent: "const newContent = 'This is new'",
|
|
70
|
+
},
|
|
71
|
+
])
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('should return an empty array if no blocks are found', () => {
|
|
75
|
+
const input = 'No blocks here'
|
|
76
|
+
|
|
77
|
+
const result = extractCurrentNewBlocks(input)
|
|
78
|
+
|
|
79
|
+
expect(result).toEqual([])
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('should not change content if current content is not found', () => {
|
|
83
|
+
const currentContent = `
|
|
84
|
+
function example() {
|
|
85
|
+
console.log('Old content')
|
|
86
|
+
}
|
|
87
|
+
`
|
|
88
|
+
const block = {
|
|
89
|
+
language: 'typescript',
|
|
90
|
+
filePath: '/tmp/test',
|
|
91
|
+
currentContent: "console.log('Non-existent content')",
|
|
92
|
+
newContent: "console.log('New content')",
|
|
93
|
+
}
|
|
94
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
95
|
+
expect(updatedContent).toBe(currentContent)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('should replace entire content if current content is empty', () => {
|
|
99
|
+
const currentContent = ''
|
|
100
|
+
const block = {
|
|
101
|
+
language: 'typescript',
|
|
102
|
+
filePath: '/tmp/test',
|
|
103
|
+
currentContent: '',
|
|
104
|
+
newContent: "console.log('New content')",
|
|
105
|
+
}
|
|
106
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
107
|
+
expect(updatedContent).toBe("console.log('New content')")
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test('should preserve indentation of new content', () => {
|
|
111
|
+
const currentContent = `function example() {
|
|
112
|
+
console.log('Old content')
|
|
113
|
+
}`
|
|
114
|
+
const block = {
|
|
115
|
+
language: 'typescript',
|
|
116
|
+
filePath: '/tmp/test',
|
|
117
|
+
currentContent: "console.log('Old content')",
|
|
118
|
+
newContent: "console.log('New content with indentation')",
|
|
119
|
+
}
|
|
120
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
121
|
+
expect(updatedContent).toBe(`function example() {
|
|
122
|
+
console.log('New content with indentation')
|
|
123
|
+
}`)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
test('should handle new file creation', () => {
|
|
127
|
+
const input = `
|
|
128
|
+
\`\`\`typescript
|
|
129
|
+
<<<<<<< CURRENT foo/bar/baz.ts
|
|
130
|
+
=======
|
|
131
|
+
console.log('hello world')
|
|
132
|
+
>>>>>>> NEW
|
|
133
|
+
\`\`\``
|
|
134
|
+
|
|
135
|
+
const result = extractCurrentNewBlocks(input)
|
|
136
|
+
|
|
137
|
+
expect(result).toEqual([
|
|
138
|
+
{
|
|
139
|
+
language: 'typescript',
|
|
140
|
+
filePath: 'foo/bar/baz.ts',
|
|
141
|
+
currentContent: '',
|
|
142
|
+
newContent: "console.log('hello world')",
|
|
143
|
+
},
|
|
144
|
+
])
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test('should handle multiple new file creations', () => {
|
|
148
|
+
const input = `
|
|
149
|
+
\`\`\`typescript
|
|
150
|
+
<<<<<<< CURRENT foo/bar/file1.ts
|
|
151
|
+
=======
|
|
152
|
+
console.log('file 1')
|
|
153
|
+
>>>>>>> NEW
|
|
154
|
+
\`\`\`
|
|
155
|
+
|
|
156
|
+
Some text in between
|
|
157
|
+
|
|
158
|
+
\`\`\`javascript
|
|
159
|
+
<<<<<<< CURRENT foo/bar/file2.js
|
|
160
|
+
=======
|
|
161
|
+
console.log('file 2')
|
|
162
|
+
>>>>>>> NEW
|
|
163
|
+
\`\`\``
|
|
164
|
+
|
|
165
|
+
const result = extractCurrentNewBlocks(input)
|
|
166
|
+
|
|
167
|
+
expect(result).toEqual([
|
|
168
|
+
{
|
|
169
|
+
language: 'typescript',
|
|
170
|
+
filePath: 'foo/bar/file1.ts',
|
|
171
|
+
currentContent: '',
|
|
172
|
+
newContent: "console.log('file 1')",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
language: 'javascript',
|
|
176
|
+
filePath: 'foo/bar/file2.js',
|
|
177
|
+
currentContent: '',
|
|
178
|
+
newContent: "console.log('file 2')",
|
|
179
|
+
},
|
|
180
|
+
])
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
test('should handle new file creation when file already exists', () => {
|
|
184
|
+
const input = `
|
|
185
|
+
\`\`\`typescript
|
|
186
|
+
<<<<<<< CURRENT foo/bar/existing.ts
|
|
187
|
+
=======
|
|
188
|
+
// New content
|
|
189
|
+
const newVar = 'new';
|
|
190
|
+
>>>>>>> NEW
|
|
191
|
+
\`\`\``
|
|
192
|
+
|
|
193
|
+
const result = extractCurrentNewBlocks(input)
|
|
194
|
+
|
|
195
|
+
expect(result).toEqual([
|
|
196
|
+
{
|
|
197
|
+
language: 'typescript',
|
|
198
|
+
filePath: 'foo/bar/existing.ts',
|
|
199
|
+
currentContent: '',
|
|
200
|
+
newContent: `// New content
|
|
201
|
+
const newVar = 'new';`,
|
|
202
|
+
},
|
|
203
|
+
])
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
describe('extractMarkdown', () => {
|
|
208
|
+
test('should extract markdown content from response', () => {
|
|
209
|
+
const response = 'Here is some text\n```markdown\n# Title\nContent here.\n```\nMore text'
|
|
210
|
+
const result = extractMarkdown(response)
|
|
211
|
+
expect(result).toBe('# Title\nContent here.')
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
test('should return the entire response if no markdown block is found', () => {
|
|
215
|
+
const response = 'No markdown block here.'
|
|
216
|
+
const result = extractMarkdown(response)
|
|
217
|
+
expect(result).toBe('No markdown block here.')
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
describe('searchReplaceString', () => {
|
|
222
|
+
test('should replace current content with new content', () => {
|
|
223
|
+
const currentContent = `function example() {
|
|
224
|
+
console.log('Old content')
|
|
225
|
+
}`
|
|
226
|
+
const block = {
|
|
227
|
+
language: 'typescript',
|
|
228
|
+
filePath: '/tmp/test',
|
|
229
|
+
currentContent: "console.log('Old content')",
|
|
230
|
+
newContent: "console.log('New content')",
|
|
231
|
+
}
|
|
232
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
233
|
+
expect(updatedContent).toBe(`function example() {
|
|
234
|
+
console.log('New content')
|
|
235
|
+
}`)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
test('should replace current content with new content with matching indentation', () => {
|
|
239
|
+
const currentContent = `function example() {
|
|
240
|
+
console.log('Old content')
|
|
241
|
+
}`
|
|
242
|
+
const block = {
|
|
243
|
+
language: 'typescript',
|
|
244
|
+
filePath: '/tmp/test',
|
|
245
|
+
currentContent: " console.log('Old content')",
|
|
246
|
+
newContent: " console.log('New content')",
|
|
247
|
+
}
|
|
248
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
249
|
+
expect(updatedContent).toBe(`function example() {
|
|
250
|
+
console.log('New content')
|
|
251
|
+
}`)
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test('should do the correct indentation when there is indentation', () => {
|
|
255
|
+
const currentContent = ` function example() {
|
|
256
|
+
console.log('Old content')
|
|
257
|
+
}`
|
|
258
|
+
const block = {
|
|
259
|
+
language: 'typescript',
|
|
260
|
+
filePath: '/tmp/test',
|
|
261
|
+
currentContent: " console.log('Old content')",
|
|
262
|
+
newContent: " console.log('New content')",
|
|
263
|
+
}
|
|
264
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
265
|
+
expect(updatedContent).toBe(` function example() {
|
|
266
|
+
console.log('New content')
|
|
267
|
+
}`)
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
test("should do the correct indentation when there is indentation and the diff doesn't", () => {
|
|
271
|
+
const currentContent = ` function example() {
|
|
272
|
+
console.log('Old content')
|
|
273
|
+
}`
|
|
274
|
+
const block = {
|
|
275
|
+
language: 'typescript',
|
|
276
|
+
filePath: '/tmp/test',
|
|
277
|
+
currentContent: "console.log('Old content')",
|
|
278
|
+
newContent: "console.log('New content')",
|
|
279
|
+
}
|
|
280
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
281
|
+
expect(updatedContent).toBe(` function example() {
|
|
282
|
+
console.log('New content')
|
|
283
|
+
}`)
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
test('should do the correct indentation when replacing large chunks', () => {
|
|
287
|
+
const currentContent = ` function example() {
|
|
288
|
+
console.log('Old content')
|
|
289
|
+
}`
|
|
290
|
+
const block = {
|
|
291
|
+
language: 'typescript',
|
|
292
|
+
filePath: '/tmp/test',
|
|
293
|
+
currentContent: ` function example() {
|
|
294
|
+
console.log('Old content')
|
|
295
|
+
}`,
|
|
296
|
+
newContent: ` function example() {
|
|
297
|
+
console.log('New content')
|
|
298
|
+
}`,
|
|
299
|
+
}
|
|
300
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
301
|
+
expect(updatedContent).toBe(` function example() {
|
|
302
|
+
console.log('New content')
|
|
303
|
+
}`)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
test('should do the correct indentation when adding new lines of code', () => {
|
|
307
|
+
const currentContent = ` function example() {
|
|
308
|
+
console.log('Old content')
|
|
309
|
+
}`
|
|
310
|
+
const block = {
|
|
311
|
+
language: 'typescript',
|
|
312
|
+
filePath: '/tmp/test',
|
|
313
|
+
currentContent: ` function example() {
|
|
314
|
+
console.log('Old content')
|
|
315
|
+
}`,
|
|
316
|
+
newContent: ` # This is a comment
|
|
317
|
+
function example() {
|
|
318
|
+
# here is a new comment
|
|
319
|
+
console.log('Old content')
|
|
320
|
+
}`,
|
|
321
|
+
}
|
|
322
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
323
|
+
expect(updatedContent).toBe(` # This is a comment
|
|
324
|
+
function example() {
|
|
325
|
+
# here is a new comment
|
|
326
|
+
console.log('Old content')
|
|
327
|
+
}`)
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
test('should handle new file creation', () => {
|
|
331
|
+
const currentContent = ''
|
|
332
|
+
const block = {
|
|
333
|
+
language: 'typescript',
|
|
334
|
+
filePath: 'foo/bar/baz.ts',
|
|
335
|
+
currentContent: '',
|
|
336
|
+
newContent: "console.log('hello world')",
|
|
337
|
+
}
|
|
338
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
339
|
+
expect(updatedContent).toBe("console.log('hello world')")
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
test('should replace content when file already exists', () => {
|
|
343
|
+
const currentContent = `// Existing content
|
|
344
|
+
const existingVar = 'old';`
|
|
345
|
+
const block = {
|
|
346
|
+
language: 'typescript',
|
|
347
|
+
filePath: 'foo/bar/existing.ts',
|
|
348
|
+
currentContent: `// Existing content
|
|
349
|
+
const existingVar = 'old';`,
|
|
350
|
+
newContent: `// New content
|
|
351
|
+
const newVar = 'new';`,
|
|
352
|
+
}
|
|
353
|
+
const updatedContent = searchReplaceString(currentContent, block)
|
|
354
|
+
expect(updatedContent).toBe(`// New content
|
|
355
|
+
const newVar = 'new';`)
|
|
356
|
+
})
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
describe('extractCurrentNewBlocks and searchReplaceString integration', () => {
|
|
360
|
+
test('should extract blocks and replace content correctly funky indentation', () => {
|
|
361
|
+
const diffString = `Here is some code:\n\n\`\`\`javascript
|
|
362
|
+
<<<<<<< CURRENT src/api/auth.js
|
|
363
|
+
const token = response.data.token;
|
|
364
|
+
localStorage.setItem('token', token);
|
|
365
|
+
=======
|
|
366
|
+
const new_token = response.data.token;
|
|
367
|
+
localStorage.setItem('new_token', new_token);
|
|
368
|
+
>>>>>>> NEW
|
|
369
|
+
\`\`\``
|
|
370
|
+
|
|
371
|
+
const existingContent = `function authenticate(response) {
|
|
372
|
+
const token = response.data.token;
|
|
373
|
+
localStorage.setItem('token', token);
|
|
374
|
+
}`
|
|
375
|
+
|
|
376
|
+
// Extract blocks
|
|
377
|
+
const blocks = extractCurrentNewBlocks(diffString)
|
|
378
|
+
|
|
379
|
+
// Check if blocks are extracted correctly
|
|
380
|
+
expect(blocks).toHaveLength(1)
|
|
381
|
+
expect(blocks[0]).toEqual({
|
|
382
|
+
language: 'javascript',
|
|
383
|
+
filePath: 'src/api/auth.js',
|
|
384
|
+
currentContent: `const token = response.data.token;
|
|
385
|
+
localStorage.setItem('token', token);`,
|
|
386
|
+
newContent: `const new_token = response.data.token;
|
|
387
|
+
localStorage.setItem('new_token', new_token);`,
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
// Apply the change using searchReplaceString
|
|
391
|
+
const updatedContent = searchReplaceString(existingContent, blocks[0])
|
|
392
|
+
|
|
393
|
+
// Check if the content is updated correctly
|
|
394
|
+
const expectedContent = `function authenticate(response) {
|
|
395
|
+
const new_token = response.data.token;
|
|
396
|
+
localStorage.setItem('new_token', new_token);
|
|
397
|
+
}`
|
|
398
|
+
|
|
399
|
+
expect(updatedContent).toBe(expectedContent)
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
test('should extract blocks and replace content correctly', () => {
|
|
403
|
+
const diffString = `Here is some text\n\`\`\`typescript
|
|
404
|
+
<<<<<<< CURRENT src/managers/ShellManager.ts
|
|
405
|
+
constructor(private options: ClovingGPTOptions) {
|
|
406
|
+
options.silent = getConfig(options).globalSilent || false
|
|
407
|
+
this.gpt = new ClovingGPT(options)
|
|
408
|
+
}
|
|
409
|
+
=======
|
|
410
|
+
constructor(private options: ClovingGPTOptions) {
|
|
411
|
+
options.silent = getConfig(options).globalSilent || false
|
|
412
|
+
options.exec = options.exec || false
|
|
413
|
+
this.gpt = new ClovingGPT(options)
|
|
414
|
+
}
|
|
415
|
+
>>>>>>> NEW
|
|
416
|
+
\`\`\`\n\nThat is the current content of the file.`
|
|
417
|
+
|
|
418
|
+
const existingContent = `class ShellManager {
|
|
419
|
+
private gpt: ClovingGPT
|
|
420
|
+
private chatHistory: ChatMessage[] = []
|
|
421
|
+
|
|
422
|
+
constructor(private options: ClovingGPTOptions) {
|
|
423
|
+
options.silent = getConfig(options).globalSilent || false
|
|
424
|
+
this.gpt = new ClovingGPT(options)
|
|
425
|
+
}
|
|
426
|
+
}`
|
|
427
|
+
|
|
428
|
+
// Extract blocks
|
|
429
|
+
const blocks = extractCurrentNewBlocks(diffString)
|
|
430
|
+
|
|
431
|
+
// Check if blocks are extracted correctly
|
|
432
|
+
expect(blocks).toHaveLength(1)
|
|
433
|
+
expect(blocks[0]).toEqual({
|
|
434
|
+
language: 'typescript',
|
|
435
|
+
filePath: 'src/managers/ShellManager.ts',
|
|
436
|
+
currentContent: `constructor(private options: ClovingGPTOptions) {
|
|
437
|
+
options.silent = getConfig(options).globalSilent || false
|
|
438
|
+
this.gpt = new ClovingGPT(options)
|
|
439
|
+
}`,
|
|
440
|
+
newContent: `constructor(private options: ClovingGPTOptions) {
|
|
441
|
+
options.silent = getConfig(options).globalSilent || false
|
|
442
|
+
options.exec = options.exec || false
|
|
443
|
+
this.gpt = new ClovingGPT(options)
|
|
444
|
+
}`,
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
// Apply the change using searchReplaceString
|
|
448
|
+
const updatedContent = searchReplaceString(existingContent, blocks[0])
|
|
449
|
+
|
|
450
|
+
// Check if the content is updated correctly
|
|
451
|
+
const expectedContent = `class ShellManager {
|
|
452
|
+
private gpt: ClovingGPT
|
|
453
|
+
private chatHistory: ChatMessage[] = []
|
|
454
|
+
|
|
455
|
+
constructor(private options: ClovingGPTOptions) {
|
|
456
|
+
options.silent = getConfig(options).globalSilent || false
|
|
457
|
+
options.exec = options.exec || false
|
|
458
|
+
this.gpt = new ClovingGPT(options)
|
|
459
|
+
}
|
|
460
|
+
}`
|
|
461
|
+
|
|
462
|
+
expect(updatedContent).toBe(expectedContent)
|
|
463
|
+
})
|
|
464
|
+
|
|
465
|
+
test('should extract blocks and replace content correctly for new files', () => {
|
|
466
|
+
const diffString = `Here is a new file:\n\n\`\`\`typescript
|
|
467
|
+
<<<<<<< CURRENT src/newfile.ts
|
|
468
|
+
=======
|
|
469
|
+
export function newFunction() {
|
|
470
|
+
console.log('This is a new file')
|
|
471
|
+
}
|
|
472
|
+
>>>>>>> NEW
|
|
473
|
+
\`\`\``
|
|
474
|
+
|
|
475
|
+
const existingContent = ''
|
|
476
|
+
|
|
477
|
+
// Extract blocks
|
|
478
|
+
const blocks = extractCurrentNewBlocks(diffString)
|
|
479
|
+
|
|
480
|
+
// Check if blocks are extracted correctly
|
|
481
|
+
expect(blocks).toHaveLength(1)
|
|
482
|
+
expect(blocks[0]).toEqual({
|
|
483
|
+
language: 'typescript',
|
|
484
|
+
filePath: 'src/newfile.ts',
|
|
485
|
+
currentContent: '',
|
|
486
|
+
newContent: `export function newFunction() {
|
|
487
|
+
console.log('This is a new file')
|
|
488
|
+
}`,
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
// Apply the change using searchReplaceString
|
|
492
|
+
const updatedContent = searchReplaceString(existingContent, blocks[0])
|
|
493
|
+
|
|
494
|
+
// Check if the content is updated correctly
|
|
495
|
+
const expectedContent = `export function newFunction() {
|
|
496
|
+
console.log('This is a new file')
|
|
497
|
+
}`
|
|
498
|
+
|
|
499
|
+
expect(updatedContent).toBe(expectedContent)
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
test('should extract blocks and replace content correctly for existing files', () => {
|
|
503
|
+
const diffString = `Here's an update to an existing file:\n\n\`\`\`typescript
|
|
504
|
+
<<<<<<< CURRENT src/existingfile.ts
|
|
505
|
+
// Existing content
|
|
506
|
+
export function existingFunction() {
|
|
507
|
+
console.log('This is an existing file')
|
|
508
|
+
}
|
|
509
|
+
=======
|
|
510
|
+
// Updated content
|
|
511
|
+
export function updatedFunction() {
|
|
512
|
+
console.log('This file has been updated')
|
|
513
|
+
}
|
|
514
|
+
>>>>>>> NEW
|
|
515
|
+
\`\`\``
|
|
516
|
+
|
|
517
|
+
const existingContent = `// Existing content
|
|
518
|
+
export function existingFunction() {
|
|
519
|
+
console.log('This is an existing file')
|
|
520
|
+
}`
|
|
521
|
+
|
|
522
|
+
// Extract blocks
|
|
523
|
+
const blocks = extractCurrentNewBlocks(diffString)
|
|
524
|
+
|
|
525
|
+
// Check if blocks are extracted correctly
|
|
526
|
+
expect(blocks).toHaveLength(1)
|
|
527
|
+
expect(blocks[0]).toEqual({
|
|
528
|
+
language: 'typescript',
|
|
529
|
+
filePath: 'src/existingfile.ts',
|
|
530
|
+
currentContent: `// Existing content
|
|
531
|
+
export function existingFunction() {
|
|
532
|
+
console.log('This is an existing file')
|
|
533
|
+
}`,
|
|
534
|
+
newContent: `// Updated content
|
|
535
|
+
export function updatedFunction() {
|
|
536
|
+
console.log('This file has been updated')
|
|
537
|
+
}`,
|
|
538
|
+
})
|
|
539
|
+
|
|
540
|
+
// Apply the change using searchReplaceString
|
|
541
|
+
const updatedContent = searchReplaceString(existingContent, blocks[0])
|
|
542
|
+
|
|
543
|
+
// Check if the content is updated correctly
|
|
544
|
+
const expectedContent = `// Updated content
|
|
545
|
+
export function updatedFunction() {
|
|
546
|
+
console.log('This file has been updated')
|
|
547
|
+
}`
|
|
548
|
+
|
|
549
|
+
expect(updatedContent).toBe(expectedContent)
|
|
550
|
+
})
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
describe('extractJsonMetadata', () => {
|
|
554
|
+
test('should return empty string for invalid JSON', () => {
|
|
555
|
+
const invalidJsonResponse = 'Invalid JSON: {key: value}'
|
|
556
|
+
const result = extractJsonMetadata(invalidJsonResponse)
|
|
557
|
+
expect(result).toBe('')
|
|
558
|
+
})
|
|
559
|
+
})
|
|
560
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020", // Specify ECMAScript target version
|
|
4
|
+
"module": "CommonJS", // Specify module code generation
|
|
5
|
+
"outDir": "./dist", // Redirect output structure to the directory
|
|
6
|
+
"rootDir": "./src", // Specify the root directory of input files
|
|
7
|
+
"strict": true, // Enable all strict type-checking options
|
|
8
|
+
"esModuleInterop": true, // Enables emit interoperability for esModules
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"skipLibCheck": true // Skip type checking of all declaration files (*.d.ts)
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*.ts"], // Include all TypeScript files in the src directory
|
|
13
|
+
"exclude": ["node_modules", "dist"] // Exclude these directories
|
|
14
|
+
}
|