- 普通注释不再单独成卡片:同一层挂到后面最近的块(隔空行也算),后面没有挂到前面那块,整层没代码挂到父块;只有文件开头隔着空行的注释、模块 docstring、//!、@file 单独成「文件开头的说明」 - 各语言(Python、TypeScript、Rust、Shell、Dockerfile)建好树后统一调 attachComments;块的编辑范围连着挂上的注释,差异、跳转、钉住卡片都按它 - 宿主统一给每张卡片(语言卡片、翻译插件的属性表、库规则卡片、一行译文的语句卡片)插「注释」一行,排在名称、说明后面 - TypeScript 的 JSDoc 也能当常量、变量的说明;sqlx、React 不再单独处理前面的注释 - 「重写注释」每块都有:提示只发 /ecc:writing-code-comments 路径:起-止,模型只读、按 --json-schema 交 body,没交结构化正文就失败不写;扩展换掉块前面的注释或在块上面新写一段
60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
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' }
|
|
}
|