Skip to content

Commit 72b6d5b

Browse files
committed
fix:TCVB解析规范化
1 parent 948bf5a commit 72b6d5b

File tree

2 files changed

+97
-67
lines changed

2 files changed

+97
-67
lines changed

src/cvbManager.ts

Lines changed: 94 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -237,88 +237,110 @@ export class TCVB
237237

238238
private parse(tcStrContent: string) : void
239239
{
240-
// 匹配文件块,每个文件块以 "## FILE:" 开头
241-
const regFileBlock: RegExp = /^## FILE:(.*?)\n([\s\S]*?)(?=^## FILE:|^## END_TCVB)/gm;
242-
let arrFileMatch: RegExpExecArray | null;
243-
while ((arrFileMatch = regFileBlock.exec(tcStrContent)) !== null)
244-
{
245-
const strFilePath: string = filePathNormalize(arrFileMatch[1]);
246-
const strOperationsBlock: string = arrFileMatch[2];
247-
// 支持操作类型中含有 "-" 符号(如 exact-replace 等)
248-
const regOperation: RegExp = /^## OPERATION:([\w-]+)\n([\s\S]*?)(?=^## OPERATION:|(?![\s\S]))/gm;
249-
let arrOpMatch: RegExpExecArray | null;
250-
while ((arrOpMatch = regOperation.exec(strOperationsBlock)) !== null)
240+
// 从文件内容中提取 "## BEGIN_TCVB" 和 "## END_TCVB" 之间的部分
241+
const regTCVB: RegExp = /##\s*BEGIN_TCVB\s*([\s\S]*?)\s*##\s*END_TCVB/;
242+
const arrTCVBMatch: RegExpExecArray | null = regTCVB.exec( tcStrContent );
243+
if ( !arrTCVBMatch )
251244
{
252-
const strType: string = arrOpMatch[1].toLowerCase();
253-
const strOpContent: string = arrOpMatch[2].trim();
254-
this.parseOperation(strFilePath, strType, strOpContent);
245+
throw new Error( "文件内容必须包含 '## BEGIN_TCVB' 和 '## END_TCVB' 之间的内容,文件不完整" );
246+
}
247+
// 重新赋值 tcStrContent 为 BEGIN_TCVB 与 END_TCVB 之间的内容
248+
tcStrContent = arrTCVBMatch[1];
249+
250+
// 匹配文件块,每个文件块以 "## FILE:" 开头
251+
const regFileBlock: RegExp = /^## FILE:(.*?)\n([\s\S]*?)(?=^## FILE:|^## END_TCVB)/gm;
252+
let arrFileMatch: RegExpExecArray | null;
253+
while ((arrFileMatch = regFileBlock.exec(tcStrContent)) !== null)
254+
{
255+
const strFilePath: string = filePathNormalize(arrFileMatch[1]);
256+
const strOperationsBlock: string = arrFileMatch[2];
257+
// 支持操作类型中含有 "-" 符号(如 exact-replace 等)
258+
const regOperation: RegExp = /^## OPERATION:([\w-]+)\n([\s\S]*?)(?=^## OPERATION:|(?![\s\S]))/gm;
259+
let arrOpMatch: RegExpExecArray | null;
260+
while ((arrOpMatch = regOperation.exec(strOperationsBlock)) !== null)
261+
{
262+
const strType: string = arrOpMatch[1].toLowerCase();
263+
const strOpContent: string = arrOpMatch[2].trim();
264+
this.parseOperation(strFilePath, strType, strOpContent);
265+
}
255266
}
256-
}
257267
}
258268

259269
private parseOperation(strFilePath: string, strType: string, strContent: string) : void
260270
{
261-
try
262-
{
263271
switch (strType)
264272
{
265-
case 'global-replace':
266-
this.parseGlobalReplace(strFilePath, strContent);
267-
break;
268-
case 'exact-replace':
269-
this.parseExactReplace(strFilePath, strContent);
270-
break;
271-
case 'create':
272-
this.parseCreate(strFilePath, strContent);
273-
break;
274-
default:
275-
throw new Error(`未知的操作类型: ${strType}`);
273+
case 'global-replace':
274+
this.parseGlobalReplace(strFilePath, strContent);
275+
break;
276+
case 'exact-replace':
277+
this.parseExactReplace(strFilePath, strContent);
278+
break;
279+
case 'create':
280+
this.parseCreate(strFilePath, strContent);
281+
break;
282+
default:
283+
throw new Error(`未知的操作类型: ${strType},文件: ${strFilePath}`);
276284
}
277-
}
278-
catch (err)
279-
{
280-
console.error(`解析 ${strType} 操作时出错, 文件: ${strFilePath}, 错误: ${err}`);
281-
}
282285
}
283286

284287
// Exact-REPLACE 操作解析:要求 BEFORE_ANCHOR、AFTER_ANCHOR、OLD_CONTENT、NEW_CONTENT 四个段落
285288
private parseExactReplace(strFilePath: string, strContent: string) : void
286289
{
287-
const recSections = this.parseSections(strContent, ['BEFORE_ANCHOR', 'AFTER_ANCHOR', 'OLD_CONTENT', 'NEW_CONTENT']);
288-
this.m_arrOperations.push(new ExactReplaceOperation(
289-
strFilePath,
290-
recSections['BEFORE_ANCHOR'],
291-
recSections['AFTER_ANCHOR'],
292-
recSections['OLD_CONTENT'],
293-
recSections['NEW_CONTENT']
294-
));
290+
let recSections: { [key: string]: string } = { };
291+
try
292+
{
293+
recSections = this.parseSections(strContent, ['BEFORE_ANCHOR', 'AFTER_ANCHOR', 'OLD_CONTENT', 'NEW_CONTENT']);
294+
}
295+
catch (err : any)
296+
{
297+
throw new Error(`解析 exact-replace 操作时,文件 "${strFilePath}" 的内容解析失败,原因: ${err.message}`);
298+
}
299+
300+
this.m_arrOperations.push(new ExactReplaceOperation(
301+
strFilePath,
302+
recSections['BEFORE_ANCHOR'],
303+
recSections['AFTER_ANCHOR'],
304+
recSections['OLD_CONTENT'],
305+
recSections['NEW_CONTENT']
306+
));
295307
}
296308

297309
// GLOBAL-REPLACE 操作解析:仅要求 OLD_CONTENT 与 NEW_CONTENT
298310
private parseGlobalReplace(strFilePath: string, strContent: string) : void
299311
{
300-
const recSections = this.parseSections(strContent, ['OLD_CONTENT', 'NEW_CONTENT']);
301-
this.m_arrOperations.push(new GlobalReplaceOperation(
302-
strFilePath,
303-
recSections['OLD_CONTENT'],
304-
recSections['NEW_CONTENT']
305-
));
312+
let recSections: { [key: string]: string } = { };
313+
try
314+
{
315+
recSections = this.parseSections(strContent, ['OLD_CONTENT', 'NEW_CONTENT']);
316+
}
317+
catch (err : any)
318+
{
319+
throw new Error(`解析 global-replace 操作时,文件 "${strFilePath}" 的内容解析失败,原因: ${err.message}`);
320+
}
321+
322+
this.m_arrOperations.push(new GlobalReplaceOperation(
323+
strFilePath,
324+
recSections['OLD_CONTENT'],
325+
recSections['NEW_CONTENT']
326+
));
306327
}
307328

308329
// CREATE 操作解析:直接将正文内容作为新文件内容,可选地去除 Markdown 代码块
309330
private parseCreate(strFilePath: string, strContent: string) : void
310331
{
311-
let strNewContent: string = strContent;
312-
const regCodeBlock: RegExp = /^```.*\n([\s\S]*?)\n```$/m;
313-
const arrMatch = regCodeBlock.exec(strNewContent);
314-
if (arrMatch)
315-
{
316-
strNewContent = arrMatch[1];
317-
}
318-
this.m_arrOperations.push(new CreateOperation(
319-
strFilePath,
320-
strNewContent
321-
));
332+
let strNewContent: string = strContent;
333+
const regCodeBlock: RegExp = /^```.*\n([\s\S]*?)\n```$/m;
334+
const arrMatch: RegExpExecArray | null = regCodeBlock.exec(strNewContent);
335+
if (arrMatch)
336+
{
337+
strNewContent = arrMatch[1];
338+
}
339+
340+
this.m_arrOperations.push(new CreateOperation(
341+
strFilePath,
342+
strNewContent
343+
));
322344
}
323345

324346
// 辅助方法:剥离 Markdown 代码块外部包裹的 ``` 标记
@@ -345,8 +367,8 @@ export class TCVB
345367
return strTrimmedContent;
346368
}
347369

348-
// 辅助方法:解析操作正文中的各个段落(段落标记格式为 "## 段落名称")
349-
private parseSections(strContent: string, arrExpectedSections: string[]) : Record<string, string>
370+
// 辅助方法:解析操作正文中的各个段落(段落标记格式为 "## 段落名称")
371+
private parseSections( strContent: string , arrExpectedSections: string[] ) : Record<string, string>
350372
{
351373
const recResult: Record<string, string> = { };
352374
let strCurrentSection: string | null = null;
@@ -370,7 +392,11 @@ export class TCVB
370392

371393
if (arrExpectedSections.indexOf(strCurrentSection) === -1)
372394
{
373-
throw new Error(`意外的段落: ${strCurrentSection}`);
395+
const cMaxLen: number = 50;
396+
const strSnippet: string = strContent.length <= cMaxLen
397+
? strContent
398+
: strContent.substring( 0 , cMaxLen ) + '...';
399+
throw new Error(`意外的段落: ${strCurrentSection},操作原始内容部分为: ${strSnippet}`);
374400
}
375401
}
376402
else if (strCurrentSection)
@@ -388,9 +414,13 @@ export class TCVB
388414
// 检查是否缺少必需的段落
389415
for (const strSection of arrExpectedSections)
390416
{
391-
if (!(strSection in recResult))
417+
if (!( strSection in recResult))
392418
{
393-
throw new Error(`缺失必需的段落: ${strSection}`);
419+
const cMaxLen: number = 50;
420+
const strSnippet: string = strContent.length <= cMaxLen
421+
? strContent
422+
: strContent.substring( 0 , cMaxLen ) + '...';
423+
throw new Error( `缺失必需的段落: ${strSection},操作原始内容部分为: ${strSnippet}` );
394424
}
395425
}
396426

@@ -493,7 +523,7 @@ export function mergeCvb(baseCvb: Cvb, tcvb: TCVB) : Cvb
493523
else if (op instanceof CreateOperation)
494524
{
495525
if (mapMergedFiles.has(strFilePath)){
496-
throw new Error(`${strFilePath} 已经存在,不可以使用 ## OPERATION:CREATE`)
526+
throw new Error(`${strFilePath} 已经存在,不可以使用 ## OPERATION:CREATE`);
497527
}
498528
// CREATE 操作:直接以新内容覆盖原有内容
499529
strContent = op.m_strContent;

src/deepseekApi.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ async function callDeepSeekApi(
137137
finishReason === 'length' ||
138138
(endstring && !fullResponse.includes(endstring));
139139

140-
if (!shouldContinue) {break};
140+
if (!shouldContinue) {break;};
141141

142142
if (abortSignal?.aborted) {
143143
throw new Error(userStopException);
@@ -203,7 +203,7 @@ export async function callDeepSeekFixApi(
203203
let messages_body = lastMessageBody;
204204

205205
messages_body.push(
206-
{ role: 'user', content:`接收的数据格式有错误: ${errorInfo}, 仔细检查,分析输出错误的原因。然后重新完整输出:`}
206+
{ role: 'user', content:`接收的数据格式有错误: ${errorInfo}, 仔细检查,分析输出错误的原因。然后根据分析重新完整输出, 注意不能有省略:`}
207207
);
208208

209209
let fullResponse = '';
@@ -362,7 +362,7 @@ export async function generateFilenameFromRequest(userRequest: string): Promise<
362362

363363
// 清理文件名
364364
summary = cleanFilename(summary);
365-
summary = summary.replace(/\s+/g, '') // 去除所有空格
365+
summary = summary.replace(/\s+/g, ''); // 去除所有空格
366366
summary = summary.replace(/^\.+|\.+$/g, ''); // 移除开头和结尾的点
367367
summary = summary.replace(/^ +| +$/g, ''); // 移除开头和结尾的空格
368368
summary = summary.substring(0, 15); // 截取前15个字符

0 commit comments

Comments
 (0)