✨ feat(vscode): 注释卡片可按规范重写注释
This commit is contained in:
1 parent
724c81188c
commit
299acb979f
11 files changed
+717
-5
No files matched your search
@@ -0,0 +1,169 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { commentProse, commentRewritePrompt, commentSource, isModuleComment, loadCommentSkill, modelCommentBody, refillComment, skillBody } from './commentRewrite'
|
||||
import { commonIndent, replaceLines } from './editText'
|
||||
|
||||
/** 和预览写回同一条路:正文套回壳,再按原来的缩进替换这几行。 */
|
||||
function rewrite(file: string, start: number, end: number, body: string): string {
|
||||
const lines = file.split('\n').slice(start, end + 1)
|
||||
const filled = refillComment(commentSource(lines), body)
|
||||
expect(filled, '认得出定界符').toBeTruthy()
|
||||
return replaceLines(file, start, end, filled ?? '')
|
||||
}
|
||||
|
||||
describe('重写注释后套回原来的壳', () => {
|
||||
it('三引号模块说明:定界符还在,正文换了,文件别的部分不动', () => {
|
||||
const file = [
|
||||
'"""旧的模块说明。',
|
||||
'',
|
||||
'只做一件事。',
|
||||
'"""',
|
||||
'',
|
||||
'def keep():',
|
||||
' return 1',
|
||||
'',
|
||||
].join('\n')
|
||||
expect(rewrite(file, 0, 3, '新的模块说明。\n\n换成了。')).toBe([
|
||||
'"""新的模块说明。',
|
||||
'',
|
||||
'换成了。',
|
||||
'"""',
|
||||
'',
|
||||
'def keep():',
|
||||
' return 1',
|
||||
'',
|
||||
].join('\n'))
|
||||
})
|
||||
|
||||
it('行注释 #:缩进和井号留着,只换这几行', () => {
|
||||
const file = [
|
||||
'def keep():',
|
||||
' return 0',
|
||||
'',
|
||||
' # 旧说明',
|
||||
' # 第二行',
|
||||
' return 1',
|
||||
'',
|
||||
].join('\n')
|
||||
const next = rewrite(file, 3, 4, '新说明')
|
||||
expect(next).toBe([
|
||||
'def keep():',
|
||||
' return 0',
|
||||
'',
|
||||
' # 新说明',
|
||||
' return 1',
|
||||
'',
|
||||
].join('\n'))
|
||||
expect(commonIndent([' # 新说明'])).toBe(' ')
|
||||
})
|
||||
|
||||
it('块注释 /** */:星号和收尾留着,前后的代码不动', () => {
|
||||
const file = [
|
||||
'export const KEEP = 1',
|
||||
'',
|
||||
'/**',
|
||||
' * 旧说明',
|
||||
' * 还有一行',
|
||||
' */',
|
||||
'export function stay(): number {',
|
||||
' return KEEP',
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
expect(rewrite(file, 2, 5, '新说明')).toBe([
|
||||
'export const KEEP = 1',
|
||||
'',
|
||||
'/**',
|
||||
' * 新说明',
|
||||
' */',
|
||||
'export function stay(): number {',
|
||||
' return KEEP',
|
||||
'}',
|
||||
'',
|
||||
].join('\n'))
|
||||
})
|
||||
|
||||
it('双斜杠行注释同样只换正文', () => {
|
||||
const file = [
|
||||
'function keep() {',
|
||||
' // 旧说明',
|
||||
' return 1',
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
expect(rewrite(file, 1, 1, '新说明')).toBe([
|
||||
'function keep() {',
|
||||
' // 新说明',
|
||||
' return 1',
|
||||
'}',
|
||||
'',
|
||||
].join('\n'))
|
||||
})
|
||||
|
||||
it('认不出定界符、正文是空的,都不给出替换', () => {
|
||||
expect(refillComment('const x = 1', '新')).toBeUndefined()
|
||||
expect(refillComment('# 旧', ' ')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('给模型的正文不带定界符', () => {
|
||||
expect(commentProse('"""旧说明"""')).toBe('旧说明')
|
||||
expect(commentProse('# 旧说明\n# 第二行')).toBe('旧说明\n第二行')
|
||||
expect(commentProse('/**\n * 旧说明\n */')).toBe('旧说明')
|
||||
expect(commentProse('// 旧说明')).toBe('旧说明')
|
||||
})
|
||||
})
|
||||
|
||||
describe('重写注释的提示', () => {
|
||||
it('文件顶上的三引号:上下文是去掉这段之后的文件,太长会截掉并说明', () => {
|
||||
const rest = Array.from({ length: 130 }, (_, index) => `line ${index}`).join('\n')
|
||||
const prompt = commentRewritePrompt({
|
||||
skill: '技能正文',
|
||||
comment: '"""旧"""',
|
||||
source: `"""旧"""\n${rest}`,
|
||||
startLine: 0,
|
||||
endLine: 0,
|
||||
earlierKinds: [],
|
||||
})
|
||||
expect(prompt).toContain('技能正文')
|
||||
expect(prompt).toContain('只按上面的技能重写这一段注释')
|
||||
expect(prompt).toContain('这段注释现在的正文:\n旧')
|
||||
expect(prompt).not.toContain('"""')
|
||||
expect(prompt).toContain('截断了')
|
||||
expect(prompt).toContain('line 0')
|
||||
expect(prompt).not.toContain('line 129')
|
||||
})
|
||||
|
||||
it('普通注释只带后面紧挨着的那一块,不带整份文件', () => {
|
||||
const prompt = commentRewritePrompt({
|
||||
skill: '技能正文',
|
||||
comment: '# 旧',
|
||||
source: '整份文件不该出现',
|
||||
startLine: 4,
|
||||
endLine: 4,
|
||||
earlierKinds: ['function'],
|
||||
following: 'def stay():\n return 1',
|
||||
})
|
||||
expect(prompt).toContain('def stay():')
|
||||
expect(prompt).not.toContain('整份文件不该出现')
|
||||
expect(isModuleComment('# 旧', [])).toBe(false)
|
||||
expect(isModuleComment('"""旧"""', [])).toBe(true)
|
||||
expect(isModuleComment('"""旧"""', ['function'])).toBe(false)
|
||||
})
|
||||
|
||||
it('技能按给出的顺序找,用到第一份;都没有就是没有', async () => {
|
||||
const read = async (path: string): Promise<string> => {
|
||||
if (path.includes('/marketplaces/ecc/'))
|
||||
throw Object.assign(new Error('no'), { code: 'ENOENT' })
|
||||
return '---\nname: writing-code-comments\n---\n规范正文\n'
|
||||
}
|
||||
expect(await loadCommentSkill(read)).toBe('规范正文')
|
||||
expect(await loadCommentSkill(async () => {
|
||||
throw Object.assign(new Error('no'), { code: 'ENOENT' })
|
||||
})).toBeUndefined()
|
||||
expect(skillBody('没有头的正文')).toBe('没有头的正文')
|
||||
})
|
||||
|
||||
it('模型套了代码围栏时只留里面的正文', () => {
|
||||
expect(modelCommentBody('```\n新说明\n```')).toBe('新说明')
|
||||
expect(modelCommentBody(' ')).toBeUndefined()
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user