✨ feat(vscode): 代码阅读加异常卡片,Python、TypeScript 的异常类画成同一张表(属性、构造参数),方法照常是子块
This commit is contained in:
1 parent
d5a092dd6f
commit
0afd012c94
21 files changed
+1118
-66
No files matched your search
@@ -725,8 +725,8 @@ describe('属性表', () => {
|
||||
expect(tsRows[32]).toEqual(['名称: Plain', '访问级别: 私有', '抽象: 否', '装饰器: @sealed'])
|
||||
|
||||
const pyRows = rowTexts(await describeAll(py, 'python', pythonZhTranslator, readFixture('classes.py')))
|
||||
expect(pyRows[6]).toEqual(['名称: AppException', '说明: 应用异常的基类。\n\n带上 HTTP 状态码。', '访问级别: 公共', '父类: Exception'])
|
||||
expect(pyRows[18]).toEqual(['名称: NotFound', '说明: 找不到资源。', '访问级别: 公共', '父类: AppException'])
|
||||
expect(pyRows[6]).toEqual(['名称: AppResponse', '说明: 应用响应的基类。\n\n带上 HTTP 状态码。', '访问级别: 公共', '父类: BaseModel'])
|
||||
expect(pyRows[18]).toEqual(['名称: NotFound', '说明: 找不到资源。', '访问级别: 公共', '父类: AppResponse'])
|
||||
expect(pyRows[24]).toEqual(['名称: Meta', '访问级别: 公共', '装饰器: @dataclass(frozen=True)', '父类: Base, metaclass=ABCMeta'])
|
||||
expect(pyRows[29]).toEqual(['名称: _Hidden', '访问级别: 私有'])
|
||||
expect(pyRows[38]).toEqual(['名称: Local', '说明: 局部类。'])
|
||||
@@ -987,11 +987,11 @@ describe('源码下标(跳到定义用)', () => {
|
||||
expect(linked(valueOf(found, '实现的接口'))).toEqual([['Loader', at('Loader')], ['K', at('K>,')], ['Disposable', at('Disposable')]])
|
||||
expect(found.filter(row => row.defines).map(row => [row.label, source.slice(row.defines?.startIndex, row.defines?.endIndex)])).toEqual([['类型参数', 'K, T extends Entity']])
|
||||
|
||||
const pySource = 'class NotFound(errors.AppException, metaclass=ABCMeta):\n pass'
|
||||
const pySource = 'class NotFound(models.AppResponse, metaclass=ABCMeta):\n pass'
|
||||
const pyRows = await describeAll(py, 'python', pythonZhTranslator, pySource)
|
||||
expect(linked(valueOf(pyRows.get(1), '父类'))).toEqual([
|
||||
['errors', pySource.indexOf('errors')],
|
||||
['AppException', pySource.indexOf('AppException')],
|
||||
['models', pySource.indexOf('models')],
|
||||
['AppResponse', pySource.indexOf('AppResponse')],
|
||||
['metaclass', pySource.indexOf('metaclass')],
|
||||
['ABCMeta', pySource.indexOf('ABCMeta')],
|
||||
])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Access, AttributeNames, BaseFacts, BlockKind, ClassFacts, CommonAttribute, Defines, EntryFacts, EnumFacts, FactBlock, FunctionFacts, ImportFacts, ImportItem, Inline, IterationClause, IterationFacts, IterationResult, LanguageAdapter, Markdown, Node, PreviewText, PropertyItem, PropertyRow, Segment, SegmentGroup, SourceDocument, SourceRange, SourceSpan, TextBlock, TokenRole, Translator, VariableBlock } from '../contract'
|
||||
import type { Access, AttributeNames, BaseFacts, BlockKind, ClassFacts, CommonAttribute, Defines, EntryFacts, EnumFacts, ExceptionFacts, FactBlock, FunctionFacts, ImportFacts, ImportItem, Inline, IterationClause, IterationFacts, IterationResult, LanguageAdapter, Markdown, Node, ParameterFacts, PreviewText, PropertyItem, PropertyRow, Segment, SegmentGroup, SourceDocument, SourceRange, SourceSpan, TextBlock, TokenRole, Translator, VariableBlock } from '../contract'
|
||||
import { commonIndent, splitLines } from '../editText'
|
||||
|
||||
/** 按所在语法节点区分译法的关键字,例如 Python 的 else:if 后「否则」,for / while 后「未中断时」。 */
|
||||
@@ -148,6 +148,7 @@ const KIND_ZH: Record<BlockKind, string> = {
|
||||
function: '函数',
|
||||
class: '类',
|
||||
enum: '枚举',
|
||||
exception: '异常',
|
||||
type: '类型',
|
||||
field: '字段',
|
||||
const: '常量',
|
||||
@@ -451,6 +452,8 @@ export function createZhTemplateTranslator(table: ZhTable): Translator {
|
||||
return classRows(block.facts, phrases)
|
||||
case 'enum':
|
||||
return enumRows(block.facts, phrases)
|
||||
case 'exception':
|
||||
return exceptionRows(block.facts, phrases)
|
||||
case 'import':
|
||||
return importRows(block.facts, phrases)
|
||||
default:
|
||||
@@ -599,23 +602,28 @@ function functionRows(facts: FunctionFacts, say: Phrases): PropertyRow[] {
|
||||
...accessRows(facts.access),
|
||||
...flagRows('async', facts.async),
|
||||
...decoratorRows(facts.decorators, say),
|
||||
{
|
||||
label: '输入参数',
|
||||
value: count(facts.parameters.length),
|
||||
columns: ['名称', '类型', '默认值'],
|
||||
items: facts.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) : [],
|
||||
],
|
||||
...defining(param.name),
|
||||
})),
|
||||
},
|
||||
parameterRow('输入参数', facts.parameters, say),
|
||||
{ label: '输出参数', value: facts.returnType ? say.translated(facts.returnType) : [hint('未标注')] },
|
||||
]
|
||||
}
|
||||
|
||||
/** 参数表:列名是名称 / 类型 / 默认值,每个参数一行,讲的定义是参数名;没有默认值的格子留空。 */
|
||||
function parameterRow(label: string, parameters: ParameterFacts[], say: Phrases): PropertyRow {
|
||||
return {
|
||||
label,
|
||||
value: count(parameters.length),
|
||||
columns: ['名称', '类型', '默认值'],
|
||||
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) : [],
|
||||
],
|
||||
...defining(param.name),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 类:名称 / 说明 / 访问级别 / 抽象(只有分这个的语言才有)/ 装饰器 / 类型参数 / 父类 / 实现的接口,
|
||||
* 说明及以后各行有才显示;类型参数、父类、实现的接口各是一行,多项用逗号隔开。类型参数那一行讲的是这几个泛型参数的定义。
|
||||
@@ -646,14 +654,14 @@ function baseText(base: BaseFacts, say: Phrases): Inline[] {
|
||||
* 说明是成员的注释、JSDoc、属性 docstring 的原文用空格连起来,一个成员都没有说明时不给这一列。
|
||||
*/
|
||||
function enumRows(facts: EnumFacts, say: Phrases): PropertyRow[] {
|
||||
const docs = facts.members.map(member => member.docs.map(node => say.doc(node)?.markdown).filter(Boolean).join(' '))
|
||||
const docs = facts.members.map(member => docsText(member.docs, say))
|
||||
const described = docs.some(Boolean)
|
||||
return [
|
||||
{ label: '名称', value: say.name(facts.name, 'type') },
|
||||
...docRows(facts.doc, say),
|
||||
...accessRows(facts.access),
|
||||
...decoratorRows(facts.decorators, say),
|
||||
...(facts.bases.length > 0 ? [{ label: '继承', value: joined(facts.bases.map(base => baseText(base, say)), ', ') }] : []),
|
||||
...baseRows(facts.bases, say),
|
||||
{
|
||||
label: '成员',
|
||||
value: count(facts.members.length),
|
||||
@@ -662,7 +670,7 @@ function enumRows(facts: EnumFacts, say: Phrases): PropertyRow[] {
|
||||
cells: [
|
||||
say.name(member.name, 'variable'),
|
||||
member.value ? say.translated(member.value) : [hint(member.computed === undefined ? '自动' : String(member.computed))],
|
||||
...(described ? [docs[i] ? [segment(docs[i], 'comment', undefined)] : []] : []),
|
||||
...(described ? [docCell(docs[i])] : []),
|
||||
],
|
||||
...defining(member.name),
|
||||
})),
|
||||
@@ -670,6 +678,54 @@ function enumRows(facts: EnumFacts, say: Phrases): PropertyRow[] {
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常(Python、TypeScript 同一张表):名称 / 说明 / 访问级别 / 装饰器 / 继承(照写的父类),说明及以后有才显示;
|
||||
* 类属性收成一张表:属性 | 类型 | 值 | 说明,一个属性都没写类型时没有「类型」列、都没有说明时没有「说明」列,没写的格子留空;
|
||||
* 构造参数同函数的输入参数表。没有类属性、没写构造函数时没有这两行。
|
||||
*/
|
||||
function exceptionRows(facts: ExceptionFacts, say: Phrases): PropertyRow[] {
|
||||
const docs = facts.fields.map(field => docsText(field.docs, say))
|
||||
const described = docs.some(Boolean)
|
||||
const typed = facts.fields.some(field => field.type)
|
||||
const fields: PropertyRow = {
|
||||
label: '属性',
|
||||
value: count(facts.fields.length),
|
||||
columns: ['属性', ...(typed ? ['类型'] : []), '值', ...(described ? ['说明'] : [])],
|
||||
items: facts.fields.map((field, i) => ({
|
||||
cells: [
|
||||
say.name(field.name, 'variable'),
|
||||
...(typed ? [field.type ? say.translated(field.type) : []] : []),
|
||||
field.value ? say.translated(field.value) : [],
|
||||
...(described ? [docCell(docs[i])] : []),
|
||||
],
|
||||
...defining(field.name),
|
||||
})),
|
||||
}
|
||||
return [
|
||||
{ label: '名称', value: facts.name ? say.name(facts.name, 'type') : [hint('匿名')] },
|
||||
...docRows(facts.doc, say),
|
||||
...accessRows(facts.access),
|
||||
...decoratorRows(facts.decorators, say),
|
||||
...baseRows(facts.bases, say),
|
||||
...(facts.fields.length > 0 ? [fields] : []),
|
||||
...(facts.parameters ? [parameterRow('构造参数', facts.parameters, say)] : []),
|
||||
]
|
||||
}
|
||||
|
||||
/** 继承:照写的父类,逗号隔开;没有父类时没有这一行。 */
|
||||
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(' ')
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
Reference in new issue
Block a user