✨ feat(vscode): 代码阅读把说明里的 @param / @return / @throws 拆到参数表、输出、异常表
This commit is contained in:
1 parent
c2982537d7
commit
0958506681
43 files changed
+1300
-323
No files matched your search
@@ -5,7 +5,7 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { toBlockViews } from '../blockView'
|
||||
import { createPythonAdapter } from '../languages/python'
|
||||
import { DocumentLookups } from '../ruleLookups'
|
||||
import { flatSegments, MemoryIndexHost, propertyLines, readFixture, WASM_DIR, withBlocks } from '../testSupport'
|
||||
import { flatSegments, inlineOf, MemoryIndexHost, propertyLines, readFixture, WASM_DIR, withBlocks } from '../testSupport'
|
||||
import { pythonZhTranslator } from '../translators/pythonZh'
|
||||
import { WorkspaceIndexes } from '../workspaceIndex'
|
||||
import { fastapiRule } from './fastapi'
|
||||
@@ -47,7 +47,7 @@ async function route(source: string, fn: string, lookup?: RuleContext['lookup'])
|
||||
function segmentsOf(row: PropertyRow | undefined): Segment[] {
|
||||
const pieces: Inline[] = [
|
||||
...(!row || 'markdown' in row.value ? [] : row.value),
|
||||
...(row?.items ?? []).flatMap(item => item.cells.flat()),
|
||||
...(row?.items ?? []).flatMap(item => item.cells.flatMap(inlineOf)),
|
||||
]
|
||||
return flatSegments(pieces)
|
||||
}
|
||||
@@ -97,20 +97,20 @@ describe('fastapi 库规则:接口卡片', () => {
|
||||
const rows = properties(await route(ROUTES, 'update_user', known({ Forbidden: '403' })))
|
||||
const request = rows.find(row => row.label === '请求')
|
||||
const [url, method] = request?.items ?? []
|
||||
expect(flatSegments(url.cells[1]).map(piece => [piece.text, piece.role])).toEqual([['/users', 'string'], ['/', 'string'], ['{', 'variable'], ['user_id', 'variable'], ['}', 'variable']])
|
||||
for (const piece of flatSegments(url.cells[1]))
|
||||
expect(flatSegments(inlineOf(url.cells[1])).map(piece => [piece.text, piece.role])).toEqual([['/users', 'string'], ['/', 'string'], ['{', 'variable'], ['user_id', 'variable'], ['}', 'variable']])
|
||||
for (const piece of flatSegments(inlineOf(url.cells[1])))
|
||||
expect(ROUTES.slice(piece.offset, (piece.offset ?? 0) + piece.text.length)).toBe(piece.text)
|
||||
// 路径里的 user_id 讲的是 update_user 的参数 user_id:高亮参数的各处出现时跟着亮,⌘ + 点击跳到参数
|
||||
const param = ROUTES.indexOf('user_id: Int4Path', ROUTES.indexOf('def update_user'))
|
||||
expect(flatSegments(url.cells[1]).find(piece => piece.text === 'user_id')?.refers).toEqual({ startIndex: param, endIndex: param + 'user_id'.length })
|
||||
expect(flatSegments(inlineOf(url.cells[1])).find(piece => piece.text === 'user_id')?.refers).toEqual({ startIndex: param, endIndex: param + 'user_id'.length })
|
||||
expect(method.cells[1]).toEqual([{ text: 'PUT', role: 'keyword', color: { dark: '#fca130', light: '#b35f00' } }])
|
||||
const [ok, forbidden, validation] = rows.find(row => row.label === '响应')?.items ?? []
|
||||
expect(ok.cells[0]).toEqual([{ text: '200', role: 'number', color: { dark: '#2ea043', light: '#1a7f37' } }])
|
||||
const model = ROUTES.indexOf('response_model=UserDetailResponse', ROUTES.indexOf('@router.put')) + 'response_model='.length
|
||||
expect(ok.cells[1]).toEqual([{ text: 'UserDetailResponse', role: 'type', offset: model }])
|
||||
expect(forbidden.cells[0]).toEqual([{ text: '403', role: 'string' }])
|
||||
expect(flatSegments(forbidden.cells[1])).toEqual([{ text: 'Forbidden', role: 'type', offset: ROUTES.indexOf('Forbidden("无权更新') }])
|
||||
expect(flatSegments([...validation.cells[1], ...validation.cells[2]]).map(piece => piece.role)).toEqual(['hint', 'hint'])
|
||||
expect(flatSegments(inlineOf(forbidden.cells[1]))).toEqual([{ text: 'Forbidden', role: 'type', offset: ROUTES.indexOf('Forbidden("无权更新') }])
|
||||
expect(flatSegments([...inlineOf(validation.cells[1]), ...inlineOf(validation.cells[2])]).map(piece => piece.role)).toEqual(['hint', 'hint'])
|
||||
// 名字都带下标、指回源码原文
|
||||
for (const piece of rows.flatMap(segmentsOf).filter(piece => piece.offset !== undefined && piece.role !== 'string' && piece.role !== 'variable'))
|
||||
expect(ROUTES.slice(piece.offset, (piece.offset ?? 0) + piece.text.length)).toBe(piece.text)
|
||||
@@ -316,6 +316,49 @@ async function routerCard(source: string, name: string): Promise<BlockView> {
|
||||
return found
|
||||
}
|
||||
|
||||
describe('fastapi 库规则:说明里的块标签', () => {
|
||||
const SOURCE = [
|
||||
'from fastapi import APIRouter, Depends, Query',
|
||||
'',
|
||||
'router = APIRouter(prefix="/apps")',
|
||||
'',
|
||||
'@router.get("/{app_id}")',
|
||||
'async def get_app(app_id: int, q: str | None = Query(None), db = Depends(get_db)) -> AppOut:',
|
||||
' """取一个应用。',
|
||||
'',
|
||||
' @param app_id 应用 id',
|
||||
' @param q 按名字搜',
|
||||
' @param db 数据库会话',
|
||||
' @param qq 写错的名字',
|
||||
' @return 应用详情',
|
||||
' @throws [AppNotFound] 没有这个应用',
|
||||
' """',
|
||||
].join('\n')
|
||||
|
||||
it('@param 对到请求表(一个参数一行,多一列说明),依赖参数不算对不上;@return 跟在响应后面;@throws 成异常表', async () => {
|
||||
const lines = propertyLines(properties(await route(SOURCE, 'get_app')))
|
||||
expect(lines).toEqual([
|
||||
'名称: get_app',
|
||||
'说明: 取一个应用。',
|
||||
'对不上的参数: 1 个',
|
||||
' qq | 写错的名字',
|
||||
'路由器: router',
|
||||
'异步: 是',
|
||||
'依赖: get_db(db)',
|
||||
'请求: GET /apps/{app_id}',
|
||||
' URL | /apps/{app_id} | ',
|
||||
' 方法 | GET | ',
|
||||
' 路径参数 | app_id: 整数 | 应用 id',
|
||||
' 查询参数 | q: 字符串 | 空 | 按名字搜',
|
||||
'响应: 200 / 422 — 应用详情',
|
||||
' 200 | AppOut | 成功',
|
||||
' 422 | 参数校验失败 | FastAPI 自动返回',
|
||||
'异常: 1 个',
|
||||
' [AppNotFound] | 没有这个应用',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('fastapi 库规则:路由器卡片', () => {
|
||||
it('luffy 的 router:名称 / 前缀 / 标签,接口表列这份文件里挂在它上面的接口(方法 / 完整路径 / 函数 / docstring 第一行)', async () => {
|
||||
const card = await routerCard(ROUTES, 'router')
|
||||
@@ -339,7 +382,7 @@ describe('fastapi 库规则:路由器卡片', () => {
|
||||
expect(getUser.cells[2]).toEqual([{ text: 'get_user', role: 'function', offset: ROUTES.indexOf('get_user(') }])
|
||||
const paramOf = (fn: string): number => ROUTES.indexOf('user_id: Int4Path', ROUTES.indexOf(`def ${fn}`))
|
||||
for (const [row, fn] of [[getUser, 'get_user'], [updateUser, 'update_user']] as const)
|
||||
expect(flatSegments(row.cells[1]).find(piece => piece.text === 'user_id')?.refers).toEqual({ startIndex: paramOf(fn), endIndex: paramOf(fn) + 'user_id'.length })
|
||||
expect(flatSegments(inlineOf(row.cells[1])).find(piece => piece.text === 'user_id')?.refers).toEqual({ startIndex: paramOf(fn), endIndex: paramOf(fn) + 'user_id'.length })
|
||||
expect(updateUser.cells[0]).toEqual([{ text: 'PUT', role: 'keyword', color: { dark: '#fca130', light: '#b35f00' } }])
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user