✨ feat(vscode): 代码阅读的 FastAPI 接口多一个筛选属性「请求方法」(GET / POST …);库规则自己报的筛选属性由规则起名(LibraryRule.attributeNames)

This commit is contained in:
cruldra committed 2026-09-27 21:21:48 +08:00
1 parent ec34ace7cf
commit b4e4879570
9 files changed
+107 -11

No files matched your search

@@ -4,6 +4,7 @@ import { describe, expect, it } from 'vitest'
import { createPythonAdapter } from '../languages/python'
import { createTypeScriptAdapter } from '../languages/typescript'
import { CodeReaderRegistry } from '../registry'
import { fastapiRule } from '../rules/fastapi'
import { sqlalchemyRule } from '../rules/sqlalchemy'
import { runtime, WASM_DIR } from '../testSupport'
import { pythonZhTranslator } from '../translators/pythonZh'
@@ -82,6 +83,41 @@ describe('预览的 document 消息', () => {
])
})
it('库规则自己的筛选属性:名字取规则给的(FastAPI 接口的「请求方法」),值照写;规则起名时抛错记下来、照写 id', async () => {
const routes = [
'from fastapi import APIRouter',
'',
'router = APIRouter(prefix="/users")',
'',
'@router.get("/{user_id}")',
'def get_user(user_id: int):',
' pass',
'',
'@router.put("/{user_id}")',
'def update_user(user_id: int):',
' pass',
'',
'@router.get("")',
'def list_users():',
' pass',
'',
].join('\n')
const { message } = await documentMessage(doc('python', routes), registryWithPython(fastapiRule), runtime, ignore)
expect(message.attributes.find(attribute => attribute.id === 'httpMethod')).toEqual({
id: 'httpMethod',
name: '请求方法',
values: [{ id: 'GET', name: 'GET', count: 2 }, { id: 'PUT', name: 'PUT', count: 1 }],
})
const reports: string[] = []
const broken: LibraryRule = { ...fastapiRule, attributeNames: () => {
throw new Error('词表坏了')
} }
const again = await documentMessage(doc('python', routes), registryWithPython(broken), runtime, text => reports.push(text))
expect(again.message.attributes.find(attribute => attribute.id === 'httpMethod')?.name).toBe('httpMethod')
expect(reports).toEqual(['库规则 fastapi 给筛选属性起名时出错,筛选栏照写 id:词表坏了'])
})
it('库规则抛错:不算解析失败,交给 report 记下,这块照常显示', async () => {
const broken: LibraryRule = {
id: 'broken',
@@ -2,8 +2,9 @@ import type { DisplayName, RuleContext } from '../contract'
import type { CodeReaderRegistry } from '../registry'
import type { TreeSitterRuntime } from '../runtime'
import type { DocumentMessage } from './messages'
import { fileAttributes } from '../attributes'
import { fileAttributes, mergeAttributeNames } from '../attributes'
import { readBlockViews } from '../blockView'
import { ruleAttributeNames } from '../libraryRules'
/** 生成预览数据要读的那点文档信息(TextDocument 的子集)。 */
export interface DocumentSnapshot {
@@ -20,7 +21,7 @@ export interface DocumentRead {
/**
* 当前文档 → 发给预览的 document 消息;语言不支持或解析失败时带 error,blocks 为空。库规则出错不算失败,交给 report 记下;
* 规则查名字的定义时问 lookup(RuleContext.lookup)。
* 规则查名字的定义时问 lookup(RuleContext.lookup)。筛选属性和值的名字先取翻译插件的,没给的再取库规则的(LibraryRule.attributeNames)。
*/
export async function documentMessage(
document: DocumentSnapshot,
@@ -46,8 +47,10 @@ export async function documentMessage(
if (!adapter)
return { message: { ...message, error: `代码阅读还不支持「${languageId}」这种语言` }, displayNames: [] }
try {
const { blocks, displayNames } = await readBlockViews(runtime, adapter, translator, languageId, source, { rules: registry.rulesFor(languageId), report, lookup })
return { message: { ...message, blocks, attributes: fileAttributes(blocks, translator?.attributeNames) }, displayNames }
const rules = registry.rulesFor(languageId)
const { blocks, displayNames } = await readBlockViews(runtime, adapter, translator, languageId, source, { rules, report, lookup })
const names = mergeAttributeNames([translator?.attributeNames, ...ruleAttributeNames(rules, translator?.displayLanguage, report)])
return { message: { ...message, blocks, attributes: fileAttributes(blocks, names) }, displayNames }
}
catch (err) {
return { message: { ...message, error: err instanceof Error ? err.message : String(err) }, displayNames: [] }