跳到主要内容

Typescript解析器之Midway配置项读取

· 10 分钟阅读
月子喵

最近在使用 Midway 框架写一个小项目, 虽然装饰器在很多时候提供了非常多辅助作用, 但是用多了会发现一件事情, 很多的装饰器参数都是字符串, 这就导致了编辑器完全没有办法做语法补全🤷‍♀️, 非常的蛋疼.

为了缓解这个问题我打算写一个关于 Midway 框架的 LSP

加载中.....

我这边使用的是 ts-node 调试的时候用是 `node --inspect -r ts-node/register <filename.ts>

目前在找工作, 如果这家公司用的是 midway 我就把这个插件补完, 发布出来并补上其他功能 😄

测试文件

首先为了编写的简单, 先约定在src/config/config.d.ts 里面一个 继承 EggAppConfig 结构的声明

加载中.....
加载中.....

效果

效果
Preview

初始化 Typescript 的 LanguageService

这个不多说, 不知道的看 ts 的文档, 那个文件的地址就是我们约定的 types 的存放位置, 可自己计算出来, 当然搜索也是没问题的

加载中.....

搜索继承自EggAppConfig的 interface

遍历整个文件的节点, 如果找到了 interface 类型的, 那么就看他有没有继承, 如果又继承就看他的继承里面有没有一个叫做 EggAppConfig

加载中.....

搜索到 Config 节点之后, 遍历节点

遍历节点的时候, 针对不同的类型做不同的处理是, 这里写的有点粗糙, 可能有点细节没有考虑到,比如带复杂类型的数组(没处理)

  • 如果是 Interface 类型的数据, 就先寻找他的父类, 然后再计算他的成员
  • 如果已经是 PropertySignature那么就记录他的 kind 和名字, 跳转
  • 如果是 TypeReference的类型, 就要去寻找他的真实的定义,和位置
  • 如果 kind 的是 TypeLiteralNode 说明是一个数组结构, 需要记录为数组 并且记录他的类型
加载中.....

寻找申明的真实位置

很多时候都会遇到这个蛋疼的问题, ts 的 getDefinitionAtPosition的这个函数并不准确, 比如搜索EggAppConfig的 ImportDeclaration, 会返回给你 3 个定义,分别是

  • egg
  • egg-view
  • egg-multipart

搜索EggAppConfig
Preview

实际上你阅读以下源码可以清楚的知道是egg包里面的定义, 但是这玩意就给你返回了 3 个, webStorm 是 0 个 (MDZZ)

这里只是测试代码, 所以选择三个都返回, 在mapConfig 里面也是 3 个都合并

加载中.....

getDefinitionAtPosition只会返回一个这样的数据结构

加载中.....

所以我们需要吧 文件名, 位置, 拿去再搜索一次, 由于 ts.forEachChild 只能遍历一层, 增加了辅助函数遍历深层的Node,即 如果还有子节点就递归调用 deepNodeMap 直到没有子节点为止, 对比的时候要注意

  • 如果是 Interface 类型的数据, 那么就去读取他的 name.pos
  • 如果是普通的直接对比 pos 数据即可
加载中.....

拿到了准确的位置信息和 Node 节点, 然后在 mapConfig 函数里面递归就行了

结束

如果拿到了这份配置表, 梳理一下结构, 非常容易的就可以根据输入的字符预测用户需要完成的配置项, 并且可以提前将 private | <Type> 这种结构帮他写好. 包括其他的 Service,Controller,Middleware都是同理, 搜索对应的就行

参考文档

[1]:microsoft/TypeScript - Using the Compiler API