cloving 0.3.17 → 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/cloving_gpt/adapters/openai.js +2 -0
- package/dist/commands/generate/context.js +1 -1
- package/dist/commands/tokens.js +1 -1
- package/dist/managers/CommitManager.js +8 -2
- package/dist/managers/ProxyManager.js +9 -2
- package/dist/managers/StreamManager.js +1 -1
- package/dist/package.json +26 -26
- package/dist/utils/config_utils.js +21 -4
- package/dist/utils/git_utils.js +109 -7
- package/dist/utils/prompt_utils.js +3 -3
- package/jest.config.js +11 -0
- package/package.json +23 -23
- 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,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module tokens
|
|
3
|
+
* This module provides functionality to estimate the number of tokens in the context files
|
|
4
|
+
* and project description for GPT processing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs'
|
|
8
|
+
import path from 'path'
|
|
9
|
+
import { getNearestClovingConfig } from '../utils/config_utils'
|
|
10
|
+
import { getAllFilesInDirectory } from '../utils/prompt_utils'
|
|
11
|
+
import type { ClovingGPTOptions } from '../utils/types'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Calculates the estimated number of tokens for the given context files and project description.
|
|
15
|
+
* @param {ClovingGPTOptions} options - The options for token calculation, including file paths.
|
|
16
|
+
* @returns {Promise<void>} A promise that resolves when the token estimation is complete.
|
|
17
|
+
*/
|
|
18
|
+
const tokens = async (options: ClovingGPTOptions): Promise<void> => {
|
|
19
|
+
let contextFiles: Record<string, string> = {}
|
|
20
|
+
let files = options.files || '.'
|
|
21
|
+
|
|
22
|
+
let prompt = ''
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Expands the given file paths to include all files in directories.
|
|
26
|
+
* @type {string[]}
|
|
27
|
+
*/
|
|
28
|
+
let expandedFiles: string[] = []
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
const filePath = path.resolve(file)
|
|
31
|
+
if (
|
|
32
|
+
await fs.promises
|
|
33
|
+
.stat(filePath)
|
|
34
|
+
.then((stat) => stat.isDirectory())
|
|
35
|
+
.catch(() => false)
|
|
36
|
+
) {
|
|
37
|
+
const dirFiles = await getAllFilesInDirectory(filePath)
|
|
38
|
+
expandedFiles = expandedFiles.concat(dirFiles.map((f) => path.relative(process.cwd(), f)))
|
|
39
|
+
} else {
|
|
40
|
+
expandedFiles.push(path.relative(process.cwd(), filePath))
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
files = expandedFiles
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Reads the content of each file and stores it in the contextFiles object.
|
|
47
|
+
*/
|
|
48
|
+
for (const file of files) {
|
|
49
|
+
const filePath = path.resolve(file)
|
|
50
|
+
if (
|
|
51
|
+
await fs.promises
|
|
52
|
+
.stat(filePath)
|
|
53
|
+
.then((stat) => stat.isFile())
|
|
54
|
+
.catch(() => false)
|
|
55
|
+
) {
|
|
56
|
+
const content = await fs.promises.readFile(filePath, 'utf-8')
|
|
57
|
+
contextFiles[file] = content
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Generates the prompt content by combining the app description and context file contents.
|
|
63
|
+
*/
|
|
64
|
+
const contextFileContents = Object.keys(contextFiles)
|
|
65
|
+
.map((file) => `### Contents of ${file}\n\n${contextFiles[file]}\n\n`)
|
|
66
|
+
.join('\n')
|
|
67
|
+
prompt += `
|
|
68
|
+
### Description of App
|
|
69
|
+
|
|
70
|
+
${JSON.stringify(getNearestClovingConfig().config, null, 2)}
|
|
71
|
+
|
|
72
|
+
${contextFileContents}`
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Estimates the number of tokens based on the prompt length.
|
|
76
|
+
* This is a rough estimation and may not be exact.
|
|
77
|
+
*/
|
|
78
|
+
const tokens = Math.ceil(prompt.length / 4).toLocaleString()
|
|
79
|
+
console.log(`Estimated tokens: ${tokens}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default tokens
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import config from './commands/config'
|
|
5
|
+
import init from './commands/init'
|
|
6
|
+
import proxy from './commands/proxy'
|
|
7
|
+
import tokens from './commands/tokens'
|
|
8
|
+
import models from './commands/models'
|
|
9
|
+
import chat from './commands/chat'
|
|
10
|
+
import shell from './commands/generate/shell'
|
|
11
|
+
import code from './commands/generate/code'
|
|
12
|
+
import commit from './commands/generate/commit'
|
|
13
|
+
import context from './commands/generate/context'
|
|
14
|
+
import unitTests from './commands/generate/unit_tests'
|
|
15
|
+
import analyze from './commands/generate/review'
|
|
16
|
+
import docs from './commands/generate/docs'
|
|
17
|
+
import { getPackageVersion } from './utils/prompt_utils'
|
|
18
|
+
|
|
19
|
+
const program = new Command()
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name('cloving')
|
|
23
|
+
.description(
|
|
24
|
+
'Integrate AI into your development workflow for generating commit messages, code reviews, and unit tests.',
|
|
25
|
+
)
|
|
26
|
+
.version(getPackageVersion())
|
|
27
|
+
|
|
28
|
+
program
|
|
29
|
+
.command('config')
|
|
30
|
+
.description('Configure cloving with your API key and models to use')
|
|
31
|
+
.action(config)
|
|
32
|
+
|
|
33
|
+
program
|
|
34
|
+
.command('init')
|
|
35
|
+
.description('Setup cloving in the current directory')
|
|
36
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
37
|
+
.option(
|
|
38
|
+
'-m, --model <model>',
|
|
39
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)',
|
|
40
|
+
)
|
|
41
|
+
.action(init)
|
|
42
|
+
|
|
43
|
+
program
|
|
44
|
+
.command('chat')
|
|
45
|
+
.option(
|
|
46
|
+
'-f, --files <filenames...>',
|
|
47
|
+
'Specify filenames of files with context to use for generating code',
|
|
48
|
+
)
|
|
49
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
50
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
51
|
+
.option(
|
|
52
|
+
'-m, --model <model>',
|
|
53
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5:sonnet-20240620)',
|
|
54
|
+
)
|
|
55
|
+
.description('Start an interactive chat with cloving')
|
|
56
|
+
.action(chat)
|
|
57
|
+
|
|
58
|
+
program
|
|
59
|
+
.command('proxy')
|
|
60
|
+
.option(
|
|
61
|
+
'-f, --files <filenames...>',
|
|
62
|
+
'Specify filenames of files with context to use for generating code',
|
|
63
|
+
)
|
|
64
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
65
|
+
.option(
|
|
66
|
+
'-m, --model <model>',
|
|
67
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5:sonnet-20240620)',
|
|
68
|
+
)
|
|
69
|
+
.description('Start a proxy server to use with cloving')
|
|
70
|
+
.action(proxy)
|
|
71
|
+
|
|
72
|
+
program.command('models').alias('m').description('List available models').action(models)
|
|
73
|
+
|
|
74
|
+
program
|
|
75
|
+
.command('tokens')
|
|
76
|
+
.alias('t')
|
|
77
|
+
.option(
|
|
78
|
+
'-f, --files <filenames...>',
|
|
79
|
+
'Specify filenames of files with context to use for generating code',
|
|
80
|
+
)
|
|
81
|
+
.description('Estimate the number of tokens in the current working directory or specified files')
|
|
82
|
+
.action(tokens)
|
|
83
|
+
|
|
84
|
+
program
|
|
85
|
+
.command('commit')
|
|
86
|
+
.alias('c')
|
|
87
|
+
.description('Alias for cloving generate commit')
|
|
88
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
89
|
+
.option(
|
|
90
|
+
'-m, --model <model>',
|
|
91
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)',
|
|
92
|
+
)
|
|
93
|
+
.action(commit)
|
|
94
|
+
|
|
95
|
+
// Generate commands
|
|
96
|
+
const generate = program
|
|
97
|
+
.command('generate')
|
|
98
|
+
.alias('g')
|
|
99
|
+
.description('Generate various items like unit-tests and code reviews')
|
|
100
|
+
|
|
101
|
+
generate
|
|
102
|
+
.command('shell')
|
|
103
|
+
.alias('sh')
|
|
104
|
+
.description('Generate a shell command based on a prompt')
|
|
105
|
+
.option('-e, --exec', 'Automatically execute the generated shell command')
|
|
106
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
107
|
+
.option(
|
|
108
|
+
'-m, --model <model>',
|
|
109
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)',
|
|
110
|
+
)
|
|
111
|
+
.option('-p, --prompt <prompt>', 'Specify the prompt to use')
|
|
112
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
113
|
+
.action(shell)
|
|
114
|
+
|
|
115
|
+
generate
|
|
116
|
+
.command('code')
|
|
117
|
+
.alias('c')
|
|
118
|
+
.description('Generate code based on a prompt')
|
|
119
|
+
.option('--save', 'Automatically save all files after generating the code')
|
|
120
|
+
.option(
|
|
121
|
+
'-i, --interactive',
|
|
122
|
+
'Auto-save generated code and then show a new prompt with existing context to revise the code further',
|
|
123
|
+
)
|
|
124
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
125
|
+
.option(
|
|
126
|
+
'-m, --model <model>',
|
|
127
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5:sonnet-20240620)',
|
|
128
|
+
)
|
|
129
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
130
|
+
.option('-p, --prompt <prompt>', 'Specify the prompt to use')
|
|
131
|
+
.option(
|
|
132
|
+
'-f, --files <filenames...>',
|
|
133
|
+
'Specify filenames of files with context to use for generating code',
|
|
134
|
+
)
|
|
135
|
+
.action(code)
|
|
136
|
+
|
|
137
|
+
generate
|
|
138
|
+
.command('commit')
|
|
139
|
+
.description('Generate a commit message and commit the changes')
|
|
140
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
141
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
142
|
+
.option(
|
|
143
|
+
'-m, --model <model>',
|
|
144
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)',
|
|
145
|
+
)
|
|
146
|
+
.action(commit)
|
|
147
|
+
|
|
148
|
+
generate
|
|
149
|
+
.command('context')
|
|
150
|
+
.description('Create a context string for generating code')
|
|
151
|
+
.option('-f, --files <filenames...>', 'Specify filenames of files with context')
|
|
152
|
+
.action(context)
|
|
153
|
+
|
|
154
|
+
generate
|
|
155
|
+
.command('unit-tests')
|
|
156
|
+
.alias('u')
|
|
157
|
+
.description(
|
|
158
|
+
"Generate unit tests (if you don't specify filenames, it will generate tests for commited changes that differ from the main/master branch)",
|
|
159
|
+
)
|
|
160
|
+
.option('--save', 'Automatically save all files after generating the unit tests')
|
|
161
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
162
|
+
.option('-f, --files <filenames...>', 'Specify filenames for the unit tests')
|
|
163
|
+
.option(
|
|
164
|
+
'-m, --model <model>',
|
|
165
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)',
|
|
166
|
+
)
|
|
167
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
168
|
+
.action(unitTests)
|
|
169
|
+
|
|
170
|
+
generate
|
|
171
|
+
.command('review')
|
|
172
|
+
.alias('r')
|
|
173
|
+
.description('Review the code for commited changes that differ from the main/master branch')
|
|
174
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
175
|
+
.option('-f, --files <filenames...>', 'Specify filenames for files you want to review')
|
|
176
|
+
.option('-p, --prompt <prompt>', 'Add a prompt to the review')
|
|
177
|
+
.option(
|
|
178
|
+
'-m, --model <model>',
|
|
179
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)',
|
|
180
|
+
)
|
|
181
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
182
|
+
.action(analyze)
|
|
183
|
+
|
|
184
|
+
generate
|
|
185
|
+
.command('docs')
|
|
186
|
+
.alias('d')
|
|
187
|
+
.description('Generate documentation for the project')
|
|
188
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
189
|
+
.option('-f, --files <filenames...>', 'Specify filenames for files you want to document')
|
|
190
|
+
.option(
|
|
191
|
+
'-m, --model <model>',
|
|
192
|
+
'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)',
|
|
193
|
+
)
|
|
194
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
195
|
+
.action(docs)
|
|
196
|
+
|
|
197
|
+
program.parse(process.argv)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { EventEmitter } from 'events'
|
|
2
|
+
import { extractCurrentNewBlocks } from '../utils/string_utils'
|
|
3
|
+
import type { CurrentNewBlock } from '../utils/types'
|
|
4
|
+
|
|
5
|
+
// Passes through string chunks, looking for code blocks, when it finds one, it starts buffering until it finds the end of the block
|
|
6
|
+
// Then it emits the code block and clears the buffer and continues
|
|
7
|
+
class BlockManager extends EventEmitter {
|
|
8
|
+
private buffer: string = ''
|
|
9
|
+
private codeBuffer: string = ''
|
|
10
|
+
private isBufferingCode: boolean = false
|
|
11
|
+
private isWaitingForContent: boolean = false
|
|
12
|
+
|
|
13
|
+
// add content to the buffer, watching for code blocks along the way
|
|
14
|
+
addContent(content: string) {
|
|
15
|
+
if (content.includes('`') || content.includes('\n')) {
|
|
16
|
+
this.isWaitingForContent = true
|
|
17
|
+
this.buffer += content
|
|
18
|
+
return
|
|
19
|
+
} else if (this.isWaitingForContent) {
|
|
20
|
+
content = this.buffer + content
|
|
21
|
+
this.buffer = ''
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// if content has multiple \n``` in the string, then we need to split it up
|
|
25
|
+
const codeBlockRegex = /\n```[\s\S]*?\n```/g
|
|
26
|
+
const codeBlocks = content.match(codeBlockRegex)
|
|
27
|
+
|
|
28
|
+
if (codeBlocks) {
|
|
29
|
+
let lastIndex = 0
|
|
30
|
+
for (const block of codeBlocks) {
|
|
31
|
+
const index = content.indexOf(block, lastIndex)
|
|
32
|
+
this.processCodeBlocks(content.slice(lastIndex, index))
|
|
33
|
+
this.processCodeBlocks(block)
|
|
34
|
+
lastIndex = index + block.length
|
|
35
|
+
}
|
|
36
|
+
this.processCodeBlocks(content.slice(lastIndex))
|
|
37
|
+
} else {
|
|
38
|
+
this.processCodeBlocks(content)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private processCodeBlocks(content: string) {
|
|
43
|
+
const codeBlockMarker = '\n```'
|
|
44
|
+
let markerIndex = content.indexOf(codeBlockMarker)
|
|
45
|
+
|
|
46
|
+
if (markerIndex !== -1) {
|
|
47
|
+
if (this.isBufferingCode) {
|
|
48
|
+
this.codeBuffer += content.slice(0, markerIndex + codeBlockMarker.length)
|
|
49
|
+
const rest = content.slice(markerIndex + codeBlockMarker.length)
|
|
50
|
+
this.emit('endGeneratingCode')
|
|
51
|
+
this.emitCodeBlock()
|
|
52
|
+
this.emit('content', rest)
|
|
53
|
+
} else {
|
|
54
|
+
this.emitBuffer(content.slice(0, markerIndex))
|
|
55
|
+
this.codeBuffer = content.slice(markerIndex)
|
|
56
|
+
this.emit('startGeneratingCode')
|
|
57
|
+
this.isBufferingCode = true
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
if (this.isBufferingCode) {
|
|
61
|
+
this.codeBuffer += content
|
|
62
|
+
} else {
|
|
63
|
+
this.buffer += content
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!this.isBufferingCode && this.buffer) {
|
|
68
|
+
this.emitBuffer()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private emitBuffer(additionalContent: string = '') {
|
|
73
|
+
const contentToEmit = this.buffer + additionalContent
|
|
74
|
+
if (contentToEmit) {
|
|
75
|
+
this.emit('content', contentToEmit)
|
|
76
|
+
this.clearBuffer()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private emitCodeBlock() {
|
|
81
|
+
if (this.codeBuffer.length > 0) {
|
|
82
|
+
const currentNewBlock = this.parseCodeBuffer()
|
|
83
|
+
this.emit('codeBlock', {
|
|
84
|
+
currentNewBlock,
|
|
85
|
+
raw: this.codeBuffer,
|
|
86
|
+
})
|
|
87
|
+
this.emit('content', this.buffer)
|
|
88
|
+
this.clearBuffer()
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Parses a code buffer into its constituent parts.
|
|
94
|
+
*
|
|
95
|
+
* This function takes a code buffer as a string, splits it into lines, and identifies the language,
|
|
96
|
+
* current start index, divider index, and new end index. It then extracts the current code and new code
|
|
97
|
+
* from the buffer based on these indices.
|
|
98
|
+
*
|
|
99
|
+
* @return {CurrentNewBlock | null}
|
|
100
|
+
* An object containing the language, current start, new end, current code, and new code.
|
|
101
|
+
*/
|
|
102
|
+
private parseCodeBuffer(): CurrentNewBlock | null {
|
|
103
|
+
const results = extractCurrentNewBlocks(this.codeBuffer)
|
|
104
|
+
|
|
105
|
+
if (results.length === 0) {
|
|
106
|
+
return null
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const block = results[0]
|
|
110
|
+
if (!block.currentContent || !block.newContent) {
|
|
111
|
+
console.warn('Incomplete code block detected. Skipping.')
|
|
112
|
+
return null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return block
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
clearBuffer() {
|
|
119
|
+
this.buffer = ''
|
|
120
|
+
this.codeBuffer = ''
|
|
121
|
+
this.isBufferingCode = false
|
|
122
|
+
this.isWaitingForContent = false
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default BlockManager
|