288 lines
14 KiB
TypeScript
288 lines
14 KiB
TypeScript
import type { Node } from '@vscode/tree-sitter-wasm'
|
||
import type { Disposable } from 'vscode'
|
||
|
||
export type { Node }
|
||
|
||
export type BlockKind
|
||
= | 'import' | 'function' | 'class' | 'type' | 'field' | 'const' | 'variable'
|
||
| 'if' | 'else' | 'loop' | 'try' | 'catch' | 'finally' | 'return' | 'statement' | 'comment'
|
||
|
||
/** 源码里一段的下标:源码字符串下标(web-tree-sitter 的 startIndex / endIndex),end 为开区间。 */
|
||
export interface SourceRange { startIndex: number, endIndex: number }
|
||
|
||
/** 源码里的一段,带起止行号(从 0 开始)。 */
|
||
export interface SourceSpan extends SourceRange { startRow: number, endRow: number }
|
||
|
||
/** 访问级别。 */
|
||
export type Access = 'public' | 'private' | 'protected'
|
||
|
||
/** 函数的一个参数;节点都指向源码。 */
|
||
export interface ParameterFacts {
|
||
/** 参数名;解构参数是整个模式,`...rest`、`*args`、`**kwargs` 带着前缀。 */
|
||
name: Node
|
||
/** TypeScript 的可省略参数 `x?`。 */
|
||
optional: boolean
|
||
type?: Node
|
||
default?: Node
|
||
}
|
||
|
||
export interface FunctionFacts {
|
||
/** 匿名函数(`export default function () {}`)没有。 */
|
||
name?: Node
|
||
/**
|
||
* 函数自己的说明:TypeScript 是紧贴在声明前面的 JSDoc 注释(以 `/**` 开头),Python 是主体开头的 docstring(字符串节点)。
|
||
* 它算在块的头部里,不再单独成一块注释。
|
||
*/
|
||
doc?: Node
|
||
/** 嵌套在函数体、条件等语句块里的函数没有。 */
|
||
access?: Access
|
||
/** 异步函数;没有这个概念的语言不填。 */
|
||
async?: boolean
|
||
decorators: Node[]
|
||
parameters: ParameterFacts[]
|
||
returnType?: Node
|
||
}
|
||
|
||
/**
|
||
* 父类的一项:TypeScript `extends Base<T>` 里的 Base(一个表达式)和跟在它后面的泛型实参 `<T>`(语法里是两个节点);
|
||
* Python 类参数列表里的一项,`metaclass=ABCMeta` 这类关键字参数、`*bases` 也算。
|
||
*/
|
||
export interface BaseFacts {
|
||
value: Node
|
||
typeArguments?: Node
|
||
}
|
||
|
||
export interface ClassFacts {
|
||
/** 匿名类(`export default class {}`)没有;赋给变量、类字段的类表达式取变量名、字段名。 */
|
||
name?: Node
|
||
/** 类自己的说明,同 FunctionFacts.doc:TypeScript 是紧贴在前面的 JSDoc,Python 是主体开头的 docstring。 */
|
||
doc?: Node
|
||
/** 同函数:嵌套在函数体、条件等语句块里的类没有。 */
|
||
access?: Access
|
||
/** 抽象类(TypeScript 的 `abstract class`);没有这个概念的语言不填。 */
|
||
abstract?: boolean
|
||
decorators: Node[]
|
||
/** 泛型参数,每个参数一项(TypeScript `<T extends X = Y>` 里的 `T extends X = Y`)。 */
|
||
typeParameters: Node[]
|
||
/** 按源码顺序。 */
|
||
bases: BaseFacts[]
|
||
/** 实现的接口(TypeScript 的 `implements A, B<T>`),每个接口一项。 */
|
||
implements: Node[]
|
||
}
|
||
|
||
/** 导入的一项。 */
|
||
export type ImportItem
|
||
= | { kind: 'named', name: Node, alias?: Node } // import { a as b }、from m import a as b
|
||
| { kind: 'default', alias: Node } // import x from 'm'
|
||
| { kind: 'namespace', alias?: Node } // import * as x、from m import *
|
||
| { kind: 'module', module: Node, alias?: Node } // import a.b as c、import x = require('m')
|
||
|
||
export interface ImportFacts {
|
||
/** 来源模块,节点就是源码里的写法:TypeScript 是字符串字面量,Python 是点分模块名;Python 的 `import a, b` 有多个。 */
|
||
sources: Node[]
|
||
/** 只导入类型(TypeScript 的 `import type`);没有这个概念的语言不填。 */
|
||
typeOnly?: boolean
|
||
/** 副作用导入(`import './x'`)没有。 */
|
||
items: ImportItem[]
|
||
}
|
||
|
||
/** 字典 / 对象字面量里的一项,照源码顺序;注释不算。 */
|
||
export type EntryFacts
|
||
= | { kind: 'pair', key: Node, value: Node, entries?: EntryFacts[] } // 'a': 1、a: 1、[k]: v;TypeScript 的简写 { a } 键和值是同一个节点;entries 同 DeclaratorFacts.entries
|
||
| { kind: 'spread', value: Node } // **other、...other:value 是展开的那个表达式
|
||
| { kind: 'method', name: Node, node: Node, header: SourceSpan } // 对象字面量里的方法、getter、setter:node 是整个方法,header 同 BlockShape.header,只到主体开始之前
|
||
|
||
/** 写在表达式里的遍历得到什么:逐个产出的生成器,或一次建好的列表、集合、字典。 */
|
||
export type IterationResult = 'generator' | 'list' | 'set' | 'dict'
|
||
|
||
/** 遍历的一节,照源码顺序:从来源里逐个取出变量(async:异步地取),或只留下满足条件的。 */
|
||
export type IterationClause
|
||
= | { kind: 'for', variables: Node, source: Node, async: boolean }
|
||
| { kind: 'if', condition: Node }
|
||
|
||
/**
|
||
* 写在表达式里的遍历(Python 的列表 / 集合 / 字典推导式、生成器表达式):语言插件从语法树读出结构,翻译插件按自己的语序重排。
|
||
* 节点都指向源码;各节、每一项取的值里还能再套遍历。
|
||
*/
|
||
export interface IterationFacts {
|
||
result: IterationResult
|
||
/** 至少一节,第一节是 for。 */
|
||
clauses: IterationClause[]
|
||
/** 每一项取的值。 */
|
||
value: Node
|
||
/** 结果是字典时每一项的键。 */
|
||
key?: Node
|
||
/**
|
||
* 遍历自己的一对括号同时是外面调用的括号时(Python `f(x for x in y)` 只写一对括号)是这对括号:
|
||
* 它们属于外面的调用,照常写在遍历外面;别的写法里遍历自己的括号、方括号、花括号不写出来。
|
||
*/
|
||
sharedParentheses?: { open: Node, close: Node }
|
||
}
|
||
|
||
export interface DeclaratorFacts {
|
||
/** 变量名;解构声明是整个模式。 */
|
||
name: Node
|
||
type?: Node
|
||
value?: Node
|
||
/** 值是字典 / 对象字面量(Python 的 dictionary、TypeScript 的 object)时是它的各项,空字面量是空数组;别的值没有。 */
|
||
entries?: EntryFacts[]
|
||
}
|
||
|
||
export interface VariableFacts {
|
||
/** 只有模块顶层(Python 还有类主体)的声明有。 */
|
||
access?: Access
|
||
/** 一条语句声明几个变量(`let a = 1, b = 2`)就有几项。 */
|
||
declarators: DeclaratorFacts[]
|
||
}
|
||
|
||
/**
|
||
* 筛选属性的通用词表,筛选栏按这个顺序排,语言自己的属性排在后面:
|
||
* - kind:块的种类(BlockKind);
|
||
* - access:访问级别,'public' | 'private' | 'protected',语言可以加自己的值(Kotlin 的 'internal',见 BlockShape.attributes);
|
||
* - async、abstract、typeOnly:异步、抽象、仅类型,值是 'true' | 'false'。
|
||
* 宿主从块的 kind 和 facts 推出它们(FunctionFacts.access / async、ClassFacts.access / abstract、ImportFacts.typeOnly、VariableFacts.access),
|
||
* 语言插件不用另报;facts 里没填的(语言没有这个概念、块没有这一项),块就没有这个属性,也不受这个属性的筛选影响。
|
||
*/
|
||
export const COMMON_ATTRIBUTES = ['kind', 'access', 'async', 'abstract', 'typeOnly'] as const
|
||
|
||
export type CommonAttribute = (typeof COMMON_ATTRIBUTES)[number]
|
||
|
||
/** 块的筛选属性:属性 id → 值 id,都是稳定的英文 id,不放显示文字(显示名由翻译插件给,见 AttributeNames)。 */
|
||
export type BlockAttributes = Record<string, string>
|
||
|
||
export interface BlockShape {
|
||
/** 这一块对应的语法树节点(整条语句)。 */
|
||
node: Node
|
||
/**
|
||
* 块自己显示 / 编辑的那一段:复合语句只到主体开始之前,其余是整条语句。
|
||
* 函数、类的说明(facts.doc)也算在里面:JSDoc 往上延到注释开头,docstring 往下延到字符串结尾。
|
||
*/
|
||
header: SourceSpan
|
||
children: CodeBlock[]
|
||
/**
|
||
* 语言自己报的筛选属性,和宿主推出的通用属性(见 COMMON_ATTRIBUTES)合在一起:通用词表以外的属性(Rust 的 unsafe: 'true'),
|
||
* 或 facts 表达不了的通用属性值(Kotlin 的 access: 'internal',盖过从 facts 推出的)。kind 总是块的种类,这里填了不算。
|
||
*/
|
||
attributes?: BlockAttributes
|
||
}
|
||
|
||
/** 预览成属性表的块:语言插件从语法树读出结构化信息(facts),翻译插件把它排成属性表。 */
|
||
export interface FunctionBlock extends BlockShape { kind: 'function', facts: FunctionFacts }
|
||
export interface ClassBlock extends BlockShape { kind: 'class', facts: ClassFacts }
|
||
export interface ImportBlock extends BlockShape { kind: 'import', facts: ImportFacts }
|
||
export interface VariableBlock extends BlockShape { kind: 'const' | 'variable', facts: VariableFacts }
|
||
export type FactBlock = FunctionBlock | ClassBlock | ImportBlock | VariableBlock
|
||
|
||
/** 带说明(facts.doc)的块。 */
|
||
export type DocumentedBlock = FunctionBlock | ClassBlock
|
||
|
||
export type TextKind = Exclude<BlockKind, FactBlock['kind']>
|
||
|
||
/** 预览成一行译文的块。 */
|
||
export interface TextBlock extends BlockShape { kind: TextKind }
|
||
|
||
export type CodeBlock = TextBlock | FactBlock
|
||
|
||
/** 着色用的词性,源码着色和译文着色共用。 */
|
||
export type TokenRole
|
||
= | 'keyword' // 流程关键字:import from export if else for return try catch await …
|
||
| 'storage' // 声明关键字与字面量关键字:const function async class interface new true false null …
|
||
| 'operator' // 被翻成文字的运算符:全等 并且 或者 非
|
||
| 'hint' // 属性表里的说明词:未标注 无 N 个 默认导出 …
|
||
| 'variable' | 'function' | 'type' | 'string' | 'number' | 'literal' | 'comment' | 'plain'
|
||
|
||
/**
|
||
* 一段着色的文字。offset:这段照抄自源码里的名字(标识符、属性名、类型名、点分模块名的一节)或字符串时,
|
||
* 它在源码里的起始下标(同 SourceSpan 的下标),预览拿它向 VS Code 查定义、跳过去;译词、提示词没有。
|
||
*/
|
||
export interface Segment { text: string, role: TokenRole, offset?: number }
|
||
|
||
/** 框的样式,决定框头的图标和框的颜色:'iteration' 是写在表达式里的遍历,图标、颜色同「循环」块。 */
|
||
export type GroupStyle = 'iteration'
|
||
|
||
/**
|
||
* 框起来的一组词:译文里自成一体的一段(写在表达式里的遍历),预览把它画成嵌在前后文字里的一个小框,框头是图标和 label。
|
||
* 框里的词照样带源码下标,还能再套框。
|
||
*/
|
||
export interface SegmentGroup {
|
||
style: GroupStyle
|
||
/** 框头的文字(遍历的结果:生成器 / 列表 …),翻译插件给。 */
|
||
label: string
|
||
segments: Inline[]
|
||
}
|
||
|
||
/** 译文里的一段:着色的词,或框起来的一组词。 */
|
||
export type Inline = Segment | SegmentGroup
|
||
|
||
/**
|
||
* 一段 Markdown 说明文字:注释、JSDoc、docstring 去掉注释符号、引号和共同缩进后的原文,不做别的转换
|
||
* (reStructuredText 的 `:func:`、JSDoc 的 `@param` 都照抄)。预览按 Markdown 渲染成注释色的段落、列表、代码块,源码里的 HTML 当文字显示。
|
||
*/
|
||
export interface Markdown { markdown: string }
|
||
|
||
/** 预览里显示的一段文字:着色的词(一行译文、属性值),或整段 Markdown 说明(注释块、函数和类的说明)。 */
|
||
export type PreviewText = Inline[] | Markdown
|
||
|
||
/**
|
||
* 属性表里的一行或一个子行讲的是哪个定义:定义出来的那个名字的节点(取自 facts,例如参数名、导入项的名称和别名、
|
||
* 声明的变量名、类的泛型参数、字典 / 对象字面量一项的键)在源码里的范围。跳到定义时,定义处落在这个范围里就只闪这一行;不填(第三方翻译插件可以不填)就闪整块。
|
||
*/
|
||
export interface Defines { defines?: SourceRange }
|
||
|
||
/** 属性表里展开的一个子行:几列对齐的格子,例如参数的名称 / 类型 / 默认值、字典一项的键 / 值。 */
|
||
export interface PropertyItem extends Defines {
|
||
cells: Inline[][]
|
||
/** 展开在这个子行下面的下一层子行(字典 / 对象的值又是字典 / 对象时,它的各项);一层层可以一直往下套。 */
|
||
items?: PropertyItem[]
|
||
}
|
||
|
||
/**
|
||
* 属性表的一行:左列属性名,右列着色的值或 Markdown 说明;items 是展开在这一行下面的子行(输入参数、导入项、字典 / 对象的各项)。
|
||
* columns 是子行各列的列名(输入参数的名称 / 类型 / 默认值):给了列名的子行排成带表头和边框的表格,没给的排成列表;表格只有一层,子行不再往下套。
|
||
*/
|
||
export interface PropertyRow extends Defines {
|
||
label: string
|
||
value: PreviewText
|
||
items?: PropertyItem[]
|
||
columns?: string[]
|
||
}
|
||
|
||
/** 语言插件:语法树 → 代码块树。 */
|
||
export interface LanguageAdapter {
|
||
id: string
|
||
/** 覆盖的 VS Code languageId,例如 ['typescript', 'typescriptreact', 'javascript', 'javascriptreact']。 */
|
||
languageIds: string[]
|
||
/** 该 languageId 用的语法包 .wasm 的绝对路径(宿主负责加载,保证和解析器运行时是同一份)。 */
|
||
grammarPath: (languageId: string) => string
|
||
/** languageId 是这份源码的 languageId:一个插件覆盖几种方言时按它区分(JavaScript 没有 TypeScript 的抽象类、仅类型导入)。 */
|
||
toBlocks: (root: Node, source: string, languageId: string) => CodeBlock[]
|
||
/** 源码着色:给语法树叶子节点定词性。 */
|
||
tokenRole: (leaf: Node) => TokenRole
|
||
}
|
||
|
||
/** 筛选属性和值的显示名,筛选栏、种类标签用它;没给名字的显示 id。 */
|
||
export interface AttributeNames {
|
||
/** 属性 id → 属性名,例如 access → 访问级别。 */
|
||
attributes: Record<string, string>
|
||
/** 属性 id → 值 id → 值名,例如 access → public → 公共、async → true → 是、kind → function → 函数。 */
|
||
values: Record<string, Record<string, string>>
|
||
}
|
||
|
||
/** 翻译插件:代码块 → 一行译文或属性表。 */
|
||
export interface Translator {
|
||
id: string // 'typescript.zh-template'
|
||
label: string // '中文直译'
|
||
languageIds: string[]
|
||
/** 只翻 header 那一段;注释块给去掉注释符号的 Markdown 原文。 */
|
||
translate: (block: TextBlock, source: string) => PreviewText
|
||
/** 函数、类、导入、常量、变量块 → 属性表。 */
|
||
describe: (block: FactBlock, source: string) => PropertyRow[]
|
||
/** 筛选属性和值叫什么,和属性表里的属性名、值用同一套叫法;不给就都显示 id。 */
|
||
attributeNames?: AttributeNames
|
||
}
|
||
|
||
export interface CodeReaderApi {
|
||
registerLanguage: (adapter: LanguageAdapter) => Disposable
|
||
registerTranslator: (translator: Translator) => Disposable
|
||
}
|