@sisyphus.js/compiler
TypeScript icon, indicating that this package has built-in type declarations

2.3.0 • Public • Published

@sisyphus.js/compiler

sisyphus.js 编辑器,包含了三个基础插件的实现,分别是用于生成核心模块的 core 插件,用于生成支持 protobuf 二进制格式代码的 proto 插件与用于支持 aip 标准的 aip 插件。

插件原理

插件采用消息与订阅者模型来实现编译插件,将状态(State)作为消息,发放给能够处理此状态的生成器(Generator)。

export interface GeneratingState<TKind extends string, TParent, TDesc, TTarget> {
    readonly parent: TParent

    readonly kind: TKind

    readonly descriptor: TDesc

    readonly target: TTarget

    generatedElements: number

    continue: boolean
}

每个状态包含一个用于匹配订阅者的 kind 字段,kind 字段一致状态和生成器会匹配,并执行生成器的生成过程。

parent 字段则表示状态的父状态,descriptor 表示当前状态的上下文,一般是 MessageDescriptor 之类的各种 Descriptor

target 字段表示这次状态生成的结果,一般为 CodeBuilder

generatedElements 是用于判断此次生成是否是空结果,当子状态进行了有效的生成时,将此字段递增 1。

continue 则表示这次生成后还需不需要继续传递到下一个同 kind 的生成器。

export type MessageGeneratingState = GeneratingState<'message', FileGeneratingState | MessageGeneratingState, MessageDescriptor, CodeBuilder>

export type FieldGeneratingState = GeneratingState<'field', MessageGeneratingState, FieldDescriptor, CodeBuilder>

使用 generate 函数用于注册一个生成器,只需要提供 kind 与生成过程就可以注册一个生成器。

generate<FieldGeneratingState>('field', it => {
    // 生成器过程
})

子状态

调用 advance 方法既可将子状态广播给其他的生成器。

for (let service of it.descriptor.services) {
    advance<ServiceGeneratingState>({
        kind: 'service', parent: it, descriptor: service, target: builder
    })
}

advance 方法会自动匹配 kind,将状态交付给对应的生成器,并在结束生成的时候,将子状态的 generatedElements 加到父状态中。

插件入口点

使用一个单 js 文件 import 所有的 生成器代码,就可以将这个 js 文件当作插件的入口点。

import './enum'
import './extension'
import './field'
import './file'
import './message'
import './service'
import '../wellknown/core'

将入口点文件注册在 package.jsonsisyphus.plugins 字段就可以被 sisygen 发现。

插件覆盖

使用 state.continue 字段可以控制是否将状态交由下一个生成器处理,将字段设置为 false 就可以就此中断此 state 的生成过程。

值得注意的的是生成器的优先顺序是倒序,即最后注册的生成器最先收到 state。

CodeBuilder 与 ImportManager

CodeBuilder 是一个用于生成 ts 代码的工具类,用于托管 CodeBlock 状态,代码缩进,换行等等。

builder.beginBlock(`export namespace ${it.descriptor.interfaceName()}`)
builder.normalize().appendLn(`export const name = '${it.descriptor.fullname()}'`)
builder.endBlock()

ImportManager 则可以管理 ts 代码的模块导入关系,并自动生成 import 语句,支持 import 冲突检测,自动别名等等。

const importedName = builder.importManager.import('@sisyphus.js/runtime', 'long')

Package Sidebar

Install

npm i @sisyphus.js/compiler

Weekly Downloads

1

Version

2.3.0

License

MIT

Unpacked Size

412 kB

Total Files

135

Last publish

Collaborators

  • jinchaoweb
  • butterbot
  • higan