✨ feat(vscode): 代码阅读把说明里的 @param / @return / @throws 拆到参数表、输出、异常表

This commit is contained in:
cruldra committed 2026-10-08 07:17:26 +08:00
1 parent c2982537d7
commit 0958506681
43 files changed
+1300 -323

No files matched your search

+24 -12
View File
@@ -1,5 +1,6 @@
import type { FunctionBlock, Inline, KindBadge, LibraryRule, Node, PropertyItem, PropertyRow, RuleCard, ThemeColor } from '../contract'
import { attributeName, docSentence, named, oneLine, returnText, stringContent } from './rustTree'
import type { FunctionBlock, Inline, KindBadge, LibraryRule, Node, PropertyItem, PropertyRow, RuleCard, RuleContext, ThemeColor } from '../contract'
import { returnNote, throwsRows, writtenParamRows } from './docRows'
import { attributeName, docSummary, named, oneLine, returnText, stringContent } from './rustTree'
/** 和 FastAPI 接口同一个蓝。 */
const COLOR: ThemeColor = { dark: '#61afef', light: '#1a6fb5' }
@@ -16,14 +17,14 @@ export const axumRule: LibraryRule = {
label: 'axum 接口',
languageIds: ['rust'],
libraries: ['axum'],
claim: (block) => {
claim: (block, context) => {
if (block.kind === 'function') {
const route = attributeRoute(block)
return route ? card(block, route) : undefined
return route ? card(block, route, context) : undefined
}
if (block.kind === 'statement') {
const [route] = routesOn(block.node).filter(item => !handled(block.node, item.handler))
return route ? routerCard(block.node, route) : undefined
return route ? routerCard(block.node, route, context) : undefined
}
return undefined
},
@@ -48,15 +49,18 @@ function attributeRoute(block: FunctionBlock): Route | undefined {
return undefined
}
function card(block: FunctionBlock, route: Route): RuleCard {
const doc = docSentence(block.facts.doc)
function card(block: FunctionBlock, route: Route, context: RuleContext): RuleCard {
const doc = block.facts.doc && context.doc(block.facts.doc)
const summary = docSummary(doc)
const params = pathParams(route.path, block.node)
const rows: PropertyRow[] = [
nameRow(block.facts.name),
...(doc ? [{ label: '说明', value: { markdown: doc } }] : []),
...(summary ? [{ label: '说明', value: { markdown: summary } }] : []),
...(block.facts.async ? [{ label: '异步', value: [keyword('是')] }] : []),
requestRow(route, params),
{ label: '返回', value: [plain(returnText(block.node))] },
...writtenParamRows(doc?.params ?? [], '参数'),
{ label: '返回', value: [plain(returnText(block.node))], ...returnNote(doc) },
...throwsRows(doc),
]
return {
kind: 'axum.route',
@@ -80,10 +84,11 @@ function handled(node: Node, handler: string | undefined): boolean {
return false
}
function routerCard(node: Node, route: Route & { handlerNode?: Node }): RuleCard {
function routerCard(node: Node, route: Route & { handlerNode?: Node }, context: RuleContext): RuleCard {
const fn = route.handler ? functionNamed(node, route.handler) : undefined
const params = fn ? pathParams(route.path, fn) : []
const doc = fn ? docSentence(leadingDoc(fn)) : undefined
const comment = fn && leadingDoc(fn)
const doc = docSummary(comment && context.doc(comment))
return {
kind: 'axum.route',
badge: BADGE,
@@ -184,11 +189,18 @@ function functionNamed(node: Node, name: string): Node | undefined {
return named(node.tree.rootNode).find(item => item.type === 'function_item' && item.childForFieldName('name')?.text === name)
}
/** 函数上面的文档注释(中间可以隔着属性):连着几行的 `///` 取第一条,读说明时从它往下连。 */
function leadingDoc(fn: Node): Node | undefined {
let prev = fn.previousNamedSibling
while (prev?.type === 'attribute_item')
prev = prev.previousNamedSibling
return prev && (prev.type === 'line_comment' || prev.type === 'block_comment') ? prev : undefined
if (!prev || (prev.type !== 'line_comment' && prev.type !== 'block_comment'))
return undefined
let first = prev
for (let before = first.previousNamedSibling; first.type === 'line_comment' && before?.type === 'line_comment' && before.startPosition.row === first.startPosition.row - 1; before = before.previousNamedSibling)
first = before
return first
}
function attributeString(attributeItem: Node): string | undefined {