import type { Inline, KindBadge, LibraryRule, Node, PropertyRow, RuleCard, ThemeColor } from '../contract' import { macroInvocation, named, oneLine, stringContent } from './rustTree' /** 查询卡用字符串那种橙。 */ const COLOR: ThemeColor = { dark: '#ce9178', light: '#a31515' } const BADGE: KindBadge = { label: '查询', color: COLOR, icon: 'database' } const MACROS = new Set(['query', 'query_as', 'query_scalar']) /** * sqlx::query! / query_as! 这类宏。等宽 SQL、参数、返回类型;前面的注释同别的块,是卡片的「注释」一行。 * 文件里导入了 sqlx 才启用。 */ export const sqlxRule: LibraryRule = { id: 'sqlx', label: 'sqlx 查询', languageIds: ['rust'], libraries: ['sqlx'], claim: (block) => { const macro = block.kind === 'statement' ? findQuery(block.node) : undefined return macro ? card(macro) : undefined }, attributeNames: () => ({ attributes: {}, values: { kind: { 'sqlx.query': '查询' } } }), } function card(macro: Node): RuleCard { const call = macroInvocation(macro) const args = call?.args ?? [] const typed = call?.name.split('::').pop() !== 'query' const sqlNode = args[typed ? 1 : 0] const sql = stringContent(sqlNode) ?? '' const params = args.slice(typed ? 2 : 1) const returned = typed ? args[0] : undefined const rows: PropertyRow[] = [ { label: 'SQL', value: [{ text: sql, role: 'string', ...(sqlNode && { offset: sqlNode.startIndex }) }] }, ...(params.length > 0 ? [{ label: '参数', value: [{ text: params.map((param, index) => `$${index + 1} = ${oneLine(param.text)}`).join('、'), role: 'plain' as const }] }] : []), { label: '返回类型', value: returned ? [{ text: oneLine(returned.text), role: 'type', offset: returned.startIndex }] : [hint('—')] }, ] return { kind: 'sqlx.query', badge: BADGE, rows, absorbs: [] } } function findQuery(node: Node): Node | undefined { if (node.type === 'macro_invocation') { const last = node.childForFieldName('macro')?.text.split('::').pop() if (last && MACROS.has(last)) return node } for (const child of named(node)) { const found = findQuery(child) if (found) return found } return undefined } function hint(text: string): Inline { return { text, role: 'hint' } }