✨ 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
@@ -1,5 +1,8 @@
|
||||
import type { Access, AttributeNames, BaseFacts, BlockKind, CallArgument, CallFacts, ClassFacts, CommandContext, CommandFacts, CommandForm, CommandReading, CommandRule, CommandWord, CommonAttribute, DeclaratorFacts, Defines, DirectiveFacts, EmbeddedReading, EntryFacts, EnumFacts, ExceptionFacts, FactBlock, FunctionFacts, HealthFacts, ImportFacts, ImportItem, Inline, InstructionFlag, InterpreterFacts, IterationClause, IterationFacts, IterationResult, LanguageAdapter, Markdown, Node, OptionsFacts, ParameterFacts, PositionalParameter, PreviewTable, PropertyItem, PropertyRow, Redirect, Segment, SegmentGroup, SourceDocument, SourceRange, SourceSpan, StageFacts, StartFacts, TextBlock, TextTranslation, TokenRole, Translator, VariableBlock } from '../contract'
|
||||
import type { Access, AttributeNames, BaseFacts, BlockKind, CallArgument, CallFacts, ClassFacts, CommandContext, CommandFacts, CommandForm, CommandReading, CommandRule, CommandWord, CommonAttribute, DeclaratorFacts, Defines, DirectiveFacts, Doc, EmbeddedReading, EntryFacts, EnumFacts, ExceptionFacts, FactBlock, FunctionFacts, HealthFacts, ImportFacts, ImportItem, Inline, InstructionFlag, InterpreterFacts, IterationClause, IterationFacts, IterationResult, LanguageAdapter, Markdown, Node, OptionsFacts, ParameterFacts, PositionalParameter, PreviewTable, PropertyItem, PropertyRow, Redirect, Segment, SegmentGroup, SourceDocument, SourceRange, SourceSpan, StageFacts, StartFacts, TextBlock, TextTranslation, TokenRole, Translator, VariableBlock } from '../contract'
|
||||
import type { ParamDocs } from '../rules/docRows'
|
||||
import { readDoc } from '../docTags'
|
||||
import { commonIndent, splitLines } from '../editText'
|
||||
import { docBodyRows, paramDocCell, paramDocs, returnNote, throwsRows, unmatchedParamRows, writtenParamRows } from '../rules/docRows'
|
||||
|
||||
/** 按所在语法节点区分译法的关键字,例如 Python 的 else:if 后「否则」,for / while 后「未中断时」。 */
|
||||
export interface ContextualWord {
|
||||
@@ -46,6 +49,11 @@ export interface ZhTable {
|
||||
stringNodes: string[]
|
||||
/** 注释(或 docstring)节点去掉注释符号后的原文,可以多行;text 是节点的源码去掉代码阅读的记号(SourceDocument.markers)以后剩下的。 */
|
||||
commentText: (node: Node, text: string) => string
|
||||
/**
|
||||
* 说明是连着几条行注释写的(Rust 的 `///`)时,从第一条(facts.doc)起这一段的各条注释节点,照源码顺序;
|
||||
* 不填就是那一个节点(JSDoc、docstring 本来就是一个节点)。
|
||||
*/
|
||||
docNodes?: (first: Node) => Node[]
|
||||
/**
|
||||
* 节点模板:节点类型 → 按中文语序重排的译文。命中的节点只输出模板里的译词和槽位,节点自己的关键字、标点不再输出;
|
||||
* 槽位里的子节点照常递归翻译。模板引用的子节点缺了,或节点没整个落在要翻的这一段里,就不重排、照常翻。
|
||||
@@ -661,9 +669,9 @@ export function createZhTemplateTranslator(table: ZhTable): Translator {
|
||||
return joinTokens(tokensIn(node, nodeSpan(node), document))
|
||||
}
|
||||
|
||||
function doc(node: Node, document: SourceDocument): Markdown | undefined {
|
||||
const markdown = docText([commentOf(node, document)])
|
||||
return markdown ? { markdown } : undefined
|
||||
function doc(node: Node, document: SourceDocument): Doc | undefined {
|
||||
const markdown = docText((table.docNodes?.(node) ?? [node]).map(part => commentOf(part, document)))
|
||||
return markdown ? readDoc(markdown) : undefined
|
||||
}
|
||||
|
||||
function describe(block: FactBlock, document: SourceDocument): PropertyRow[] {
|
||||
@@ -817,8 +825,8 @@ interface Phrases {
|
||||
module: (node: Node) => Segment[]
|
||||
/** 源码里的一个名字原样照抄、按 role 着色(函数、类的名称)。 */
|
||||
name: (node: Node, role: TokenRole) => Segment[]
|
||||
/** 函数、类的说明(JSDoc、docstring):去掉注释符号、引号和共同缩进的 Markdown 原文;没有文字时没有。 */
|
||||
doc: (node: Node) => Markdown | undefined
|
||||
/** 函数、类的说明(JSDoc、docstring):去掉注释符号、引号和共同缩进的 Markdown 原文拆成正文和块标签;没有文字时没有。 */
|
||||
doc: (node: Node) => Doc | undefined
|
||||
/** 一条要执行的命令:数组写法交给命令规则读,shell 写法是宿主读好的嵌着的代码(SourceDocument.embedded),可以带一张选项表。 */
|
||||
command: (form: CommandForm) => { text: Inline[], table?: PreviewTable }
|
||||
}
|
||||
@@ -907,38 +915,50 @@ function aliased(item: Inline[], alias: Node | undefined, say: Phrases): Inline[
|
||||
}
|
||||
|
||||
/**
|
||||
* 函数:名称 / 说明 / 访问级别 / 异步(只有分这个的语言才有)/ 装饰器 / 输入参数 / 输出参数。
|
||||
* 输入参数是一张表,列名是名称 / 类型 / 默认值,每个参数一行;没有默认值的格子留空。
|
||||
* 函数:名称 / 说明 / 对不上的参数 / 访问级别 / 异步(只有分这个的语言才有)/ 装饰器 / 输入参数 / 输出参数 / 异常。
|
||||
* 输入参数是一张表,列名是名称 / 类型 / 默认值,每个参数一行;没有默认值的格子留空。说明里的块标签拆开放:
|
||||
* `@param` 进输入参数表多出的「说明」列(有参数对上才有这一列),名字对不上的排在说明下面;`@return` 跟在输出参数的类型后面;
|
||||
* `@throws` 是「异常」一行。
|
||||
*/
|
||||
function functionRows(facts: FunctionFacts, say: Phrases): PropertyRow[] {
|
||||
const doc = facts.doc && say.doc(facts.doc)
|
||||
const names = facts.positional ? facts.positional.flatMap(param => param.name ? [param.name.text] : []) : facts.parameters.map(param => param.name.text)
|
||||
const docs = paramDocs(doc, names)
|
||||
return [
|
||||
{ label: '名称', value: facts.name ? say.name(facts.name, 'function') : [hint('匿名')] },
|
||||
...docRows(facts.doc, say),
|
||||
...docBodyRows(doc),
|
||||
...unmatchedParamRows(docs.unmatched),
|
||||
...accessRows(facts.access),
|
||||
...flagRows('async', facts.async),
|
||||
...decoratorRows(facts.decorators, say),
|
||||
...(facts.positional
|
||||
? positionalRows(facts, facts.positional, say)
|
||||
? positionalRows(facts, facts.positional, say, docs, doc)
|
||||
: [
|
||||
parameterRow('输入参数', facts.parameters, say),
|
||||
{ label: '输出参数', value: facts.returnType ? say.translated(facts.returnType) : [hint('未标注')] },
|
||||
parameterRow('输入参数', facts.parameters, say, docs),
|
||||
{ label: '输出参数', value: facts.returnType ? say.translated(facts.returnType) : [hint('未标注')], ...returnNote(doc) },
|
||||
]),
|
||||
...throwsRows(doc),
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* 按位置取参数的函数(shell):输入参数写「N 个,按位置」,下面一张表「位置 | 函数里叫」(没起名的写 $N);
|
||||
* 按位置取参数的函数(shell):输入参数写「N 个,按位置」,下面一张表「位置 | 函数里叫」(没起名的写 $N;`@param` 按起的名字对上时多一列说明);
|
||||
* 输出是它打印的那几句(调用处用 $(函数 …) 拿去用时注明);返回是写了的 return 值,没写 return、也不打印时是最后一句成不成功。
|
||||
*/
|
||||
function positionalRows(facts: FunctionFacts, positional: PositionalParameter[], say: Phrases): PropertyRow[] {
|
||||
function positionalRows(facts: FunctionFacts, positional: PositionalParameter[], say: Phrases, docs: ParamDocs, doc: Doc | undefined): PropertyRow[] {
|
||||
const described = positional.some(param => param.name && docs.of(param.name.text))
|
||||
const inputs: PropertyRow = positional.length === 0
|
||||
? { label: '输入参数', value: [hint('无')] }
|
||||
: {
|
||||
label: '输入参数',
|
||||
value: [hint(`${positional.length} 个,按位置`)],
|
||||
columns: ['位置', '函数里叫'],
|
||||
columns: described ? ['位置', '函数里叫', '说明'] : ['位置', '函数里叫'],
|
||||
items: positional.map(param => ({
|
||||
cells: [[hint(`第 ${param.position} 个`)], param.name ? say.name(param.name, 'variable') : [segment(`$${param.position}`, 'variable', undefined)]],
|
||||
cells: [
|
||||
[hint(`第 ${param.position} 个`)],
|
||||
param.name ? say.name(param.name, 'variable') : [segment(`$${param.position}`, 'variable', undefined)],
|
||||
...(described ? [param.name ? paramDocCell(docs, param.name.text) : []] : []),
|
||||
],
|
||||
...defining(param.name),
|
||||
})),
|
||||
}
|
||||
@@ -950,7 +970,9 @@ function positionalRows(facts: FunctionFacts, positional: PositionalParameter[],
|
||||
const result: PropertyRow[] = values.length > 0
|
||||
? [{ label: '返回', value: joined(values, '、') }]
|
||||
: prints.length === 0 ? [{ label: '返回', value: [hint('最后一句成不成功')] }] : []
|
||||
return [inputs, ...output, ...result]
|
||||
// `@return` 跟在返回那一行后面;只有打印、没写 return 时跟在输出那一行后面
|
||||
const [noted] = [...result, ...output]
|
||||
return [inputs, ...[...output, ...result].map(row => row === noted ? { ...row, ...returnNote(doc) } : row)]
|
||||
}
|
||||
|
||||
/** 解释器:叫什么,怎么找到它(按 PATH 找,或写死的路径)。 */
|
||||
@@ -991,7 +1013,7 @@ function flagValue(flag: InstructionFlag): Inline[] {
|
||||
* 接着前面某个阶段建的写「阶段 X」)/ 平台(写了 --platform 才有)。
|
||||
*/
|
||||
function stageRows(facts: StageFacts, say: Phrases): PropertyRow[] {
|
||||
const doc = (facts.doc ?? []).map(node => say.doc(node)?.markdown).filter(Boolean).join('\n')
|
||||
const doc = (facts.doc ?? []).map(node => say.doc(node)?.body?.markdown).filter(Boolean).join('\n')
|
||||
const platform = facts.flags.find(flag => flag.name === 'platform')
|
||||
const image: Inline[] = facts.stage
|
||||
? [segment('阶段', 'keyword', undefined), segment(' ', 'plain', undefined), ...say.name(facts.image, 'variable')]
|
||||
@@ -1078,17 +1100,22 @@ function scopedVariableRows(declarators: DeclaratorFacts[], scope: 'build' | 'en
|
||||
}]
|
||||
}
|
||||
|
||||
/** 参数表:列名是名称 / 类型 / 默认值,每个参数一行,讲的定义是参数名;没有默认值的格子留空。 */
|
||||
function parameterRow(label: string, parameters: ParameterFacts[], say: Phrases): PropertyRow {
|
||||
/**
|
||||
* 参数表:列名是名称 / 类型 / 默认值,每个参数一行,讲的定义是参数名;没有默认值的格子留空。
|
||||
* 说明里有参数对上了(docs)时多一列「说明」,没对上的格子留空。
|
||||
*/
|
||||
function parameterRow(label: string, parameters: ParameterFacts[], say: Phrases, docs: ParamDocs): PropertyRow {
|
||||
const described = parameters.some(param => docs.of(param.name.text))
|
||||
return {
|
||||
label,
|
||||
value: count(parameters.length),
|
||||
columns: ['名称', '类型', '默认值'],
|
||||
columns: described ? ['名称', '类型', '默认值', '说明'] : ['名称', '类型', '默认值'],
|
||||
items: parameters.map(param => ({
|
||||
cells: [
|
||||
param.optional ? [...say.translated(param.name), { text: '?', role: 'plain' }] : say.translated(param.name),
|
||||
param.type ? say.translated(param.type) : [hint('未标注')],
|
||||
param.default ? say.translated(param.default) : [],
|
||||
...(described ? [paramDocCell(docs, param.name.text)] : []),
|
||||
],
|
||||
...defining(param.name),
|
||||
})),
|
||||
@@ -1098,19 +1125,23 @@ function parameterRow(label: string, parameters: ParameterFacts[], say: Phrases)
|
||||
/**
|
||||
* 类:名称 / 说明 / 访问级别 / 抽象(只有分这个的语言才有)/ 装饰器 / 类型参数 / 父类 / 实现的接口,
|
||||
* 说明及以后各行有才显示;类型参数、父类、实现的接口各是一行,多项用逗号隔开。类型参数那一行讲的是这几个泛型参数的定义。
|
||||
* 类没有构造参数表可对,说明里的 `@param` 照写成「构造参数」一张「名称 | 说明」表;`@throws` 是「异常」一行。
|
||||
*/
|
||||
function classRows(facts: ClassFacts, say: Phrases): PropertyRow[] {
|
||||
const listRow = (label: string, parts: Inline[][], defines: Defines = {}): PropertyRow[] =>
|
||||
parts.length > 0 ? [{ label, value: joined(parts, ', '), ...defines }] : []
|
||||
const doc = facts.doc && say.doc(facts.doc)
|
||||
return [
|
||||
{ label: '名称', value: facts.name ? say.name(facts.name, 'type') : [hint('匿名')] },
|
||||
...docRows(facts.doc, say),
|
||||
...docBodyRows(doc),
|
||||
...accessRows(facts.access),
|
||||
...flagRows('abstract', facts.abstract),
|
||||
...decoratorRows(facts.decorators, say),
|
||||
...listRow('类型参数', facts.typeParameters.map(say.translated), defining(...facts.typeParameters)),
|
||||
...listRow('父类', facts.bases.map(base => baseText(base, say))),
|
||||
...listRow('实现的接口', facts.implements.map(say.translated)),
|
||||
...writtenParamRows(doc?.params ?? [], '构造参数'),
|
||||
...throwsRows(doc),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1129,7 +1160,7 @@ function enumRows(facts: EnumFacts, say: Phrases): PropertyRow[] {
|
||||
const described = docs.some(Boolean)
|
||||
return [
|
||||
{ label: '名称', value: say.name(facts.name, 'type') },
|
||||
...docRows(facts.doc, say),
|
||||
...docBodyRows(facts.doc && say.doc(facts.doc)),
|
||||
...accessRows(facts.access),
|
||||
...decoratorRows(facts.decorators, say),
|
||||
...baseRows(facts.bases, say),
|
||||
@@ -1153,6 +1184,7 @@ function enumRows(facts: EnumFacts, say: Phrases): PropertyRow[] {
|
||||
* 异常(Python、TypeScript 同一张表):名称 / 说明 / 访问级别 / 装饰器 / 继承(照写的父类),说明及以后有才显示;
|
||||
* 类属性收成一张表:属性 | 类型 | 值 | 说明,一个属性都没写类型时没有「类型」列、都没有说明时没有「说明」列,没写的格子留空;
|
||||
* 构造参数同函数的输入参数表。没有类属性、没写构造函数时没有这两行。
|
||||
* 说明里的 `@param` 对到构造参数表(同函数的输入参数,对不上的排在说明下面;没写构造函数时同类,照写成一张表),`@throws` 是「异常」一行。
|
||||
*/
|
||||
function exceptionRows(facts: ExceptionFacts, say: Phrases): PropertyRow[] {
|
||||
const docs = facts.fields.map(field => docsText(field.docs, say))
|
||||
@@ -1172,14 +1204,18 @@ function exceptionRows(facts: ExceptionFacts, say: Phrases): PropertyRow[] {
|
||||
...defining(field.name),
|
||||
})),
|
||||
}
|
||||
const doc = facts.doc && say.doc(facts.doc)
|
||||
const params = facts.parameters && paramDocs(doc, facts.parameters.map(param => param.name.text))
|
||||
return [
|
||||
{ label: '名称', value: facts.name ? say.name(facts.name, 'type') : [hint('匿名')] },
|
||||
...docRows(facts.doc, say),
|
||||
...docBodyRows(doc),
|
||||
...unmatchedParamRows(params?.unmatched ?? []),
|
||||
...accessRows(facts.access),
|
||||
...decoratorRows(facts.decorators, say),
|
||||
...baseRows(facts.bases, say),
|
||||
...(facts.fields.length > 0 ? [fields] : []),
|
||||
...(facts.parameters ? [parameterRow('构造参数', facts.parameters, say)] : []),
|
||||
...(facts.parameters && params ? [parameterRow('构造参数', facts.parameters, say, params)] : writtenParamRows(doc?.params ?? [], '构造参数')),
|
||||
...throwsRows(doc),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1188,21 +1224,15 @@ function baseRows(bases: BaseFacts[], say: Phrases): PropertyRow[] {
|
||||
return bases.length > 0 ? [{ label: '继承', value: joined(bases.map(base => baseText(base, say)), ', ') }] : []
|
||||
}
|
||||
|
||||
/** 表格里一格说明:几段说明文字的原文用空格连起来。 */
|
||||
/** 表格里一格说明:几段说明文字的正文用空格连起来。 */
|
||||
function docsText(nodes: Node[], say: Phrases): string {
|
||||
return nodes.map(node => say.doc(node)?.markdown).filter(Boolean).join(' ')
|
||||
return nodes.map(node => say.doc(node)?.body?.markdown).filter(Boolean).join(' ')
|
||||
}
|
||||
|
||||
function docCell(text: string): Inline[] {
|
||||
return text ? [segment(text, 'comment', undefined)] : []
|
||||
}
|
||||
|
||||
/** 函数、类、常量、变量的说明:有文字才有这一行。 */
|
||||
function docRows(doc: Node | undefined, say: Phrases): PropertyRow[] {
|
||||
const markdown = doc && say.doc(doc)
|
||||
return markdown ? [{ label: '说明', value: markdown }] : []
|
||||
}
|
||||
|
||||
/** 装饰器:源码原样照抄,多个换行。 */
|
||||
function decoratorRows(decorators: Node[], say: Phrases): PropertyRow[] {
|
||||
return decorators.length > 0 ? [{ label: '装饰器', value: joined(decorators.map(say.verbatim), '\n') }] : []
|
||||
@@ -1238,7 +1268,7 @@ function variableRows(block: VariableBlock, say: Phrases): PropertyRow[] {
|
||||
const valueLabel = block.kind === 'const' ? '值' : '初始值'
|
||||
return block.facts.declarators.flatMap((declarator, i) => [
|
||||
{ label: '名称', value: say.translated(declarator.name), ...defining(declarator.name) },
|
||||
...(i === 0 ? docRows(block.facts.doc, say) : []),
|
||||
...(i === 0 ? docBodyRows(block.facts.doc && say.doc(block.facts.doc)) : []),
|
||||
...accessRows(block.facts.access),
|
||||
...(declarator.type ? [{ label: '类型', value: say.translated(declarator.type) }] : []),
|
||||
{ label: valueLabel, ...(declarator.value ? declaredValue(declarator.value, declarator.entries, say) : { value: [hint('无')] }) },
|
||||
|
||||
Reference in new issue
Block a user