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` 里的 Base(一个表达式)和跟在它后面的泛型实参 ``(语法里是两个节点); * 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`)。 */ typeParameters: Node[] /** 按源码顺序。 */ bases: BaseFacts[] /** 实现的接口(TypeScript 的 `implements A, B`),每个接口一项。 */ 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 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 /** 预览成一行译文的块。 */ 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 /** 属性 id → 值 id → 值名,例如 access → public → 公共、async → true → 是、kind → function → 函数。 */ values: Record> } /** 翻译插件:代码块 → 一行译文或属性表。 */ 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 }