Tern
Tern 是一个javascript代码分析引擎,其目标是被代码编辑插件使用以增强编辑器的javascript代码智能编辑能力。其提供的主要特征如下:
- 变量和属性的自动完成
- 函数参数提示
- 查询一个表达式的类型
- 查找定义
- 重构
Tern是开源项目(MIT),使用javascript编写,能运行于node.js和浏览器中。
Editor plugins
Tern当前支持的编辑器如下:
- Emacs
- Vim
- Sublime Text
- Brackets
- Light Table
- Eclipse(提供了一般性通用api)
- TextMate
社区支持
有一个论坛用于讨论和问有关Tern的论坛,并会有一些最新消息的通告,比如新版本的发行。可以通过github issue tracker来报告缺陷。
欢迎通过pull requests来进行代码分发。
如果你正从中获取收益,特别是用于盈利目的,考虑为更多的开发提供资金,Marijn Haverbeke将会为你提供咨询。
文档
了解如何安装Tern,阅读参考手册是你需要进行的第一步。
如果你对这个系统的内容工作比较感兴趣,可以查看下blog和一些会议上的视频
Tern 使用手册##
Tern又几个组件组成,依赖你利用它来做什么,你将关注Tern的不同层次。Editor Plugins,它位于最高的层次。Tern server,它是在Server模块(提供编程接口)的基础上实现,利用推断引擎inference engine来做真正的类型推断。
Tern server
bin/tern用来启动Tern server,你会经常使用一个Editor plugin来启动它,但是也可以手动启动它,这样比较方便调试。(注意server的基础是通过编程接口提供出来的,对于使用在浏览器中的场景,将直接使用编程接口而不是这里描述的http方式)。
Server启动时将在当前文件夹或者其子文件夹下寻找.tern-project文件,读取里面的内容作为配置。如果没有project文件,默认配置将创建失败。你可以通过放置一个.tern-config文件来改变默认配置,该文件的配置格式和.tern-project文件一致,并将该文件放在你的HOME目录下。
Server在启动时将其监听的端口(默认随机)写入标准输出,Server通过http方式和json格式数据进行交互,客户端可以通过http上传代码并询问一些关于代码的问题。
以下命令行标识将得到支持:
--port <number>
指定监听端口,通过这种方式可以取代默认的随机端口方式
--host <host>
指定监听的host,默认127.0.0.1
--persistent
默认情况下,Server将在五分钟没有交互的情况下自动关闭,通过该选项可以禁用自动关闭
--ignore-stdin
默认情况下,在标准输入流关闭时Server将自动关闭,通过该选项可以禁用该行为
--verbose
Server将输出请求和返回的信息,以及错误信息,这有助于调试
--no-port-file
Server将不会输出.tern-port文件
JSON格式协议
向Tern发送查询请求要通过POST方式发送,请求体以json格式传送。请求提有三个可选字段:query,files,timeout。
query描述了你所请求的信息类型,如果请求只是为了推送新的代码,那该字段可以忽略。files用于指定一组文件,如果请求所操作的代码Server上已经存在,并没有添加新的文件,那么该字段将被忽略。timeout用于指定该请求的最大工作时长(cpu时间),毫秒。
query是一个对象,至少有一个type属性,用以标识请求类型,其他属性依赖于不同的类型而不同。
以下是Tern server所能理解的请求。(插件可能添加自定义的类型)
-
completions
在给定的位置,询问代码完成
字段:
-
file,end(required)
指定代码完成的位置
-
types(optional,默认false)
是否在结果数据中包含代码完成的类型
depths(optional,默认false)
docs,urls,origins(optional,默认false)
-
filter(optional,默认true)
是否只返回符合当前位置的词语的完成列表,否则返回全部
-
caseInsensitive(optional,默认false)
当前位置的词语和潜在完成列表是否采用大小写敏感性比较
-
guess(optional,默认true)
当找不到匹配的完成结果时,是否返回启发式的建议
-
sort(optional,默认true)
结果是否排序
-
expandWordForward(optional,默认true)
true,鼠标所在的整个变量名将被包含,false,只有指定位置前的文本内容会被考虑
-
omitObjectPrototype(optional,默认true)
是否忽略Object.prototype的属性
-
includeKeywords(optional,默认false)
当代码完成发生在一个属性上,是否包含javascript的关键字
-
inLiteral(optional,默认true)
字面量上是否返回完成内容
返回结果包含两个属性,start和end,表示完成的词语的偏移量,isProperty是布尔类型,表示完成的是否为一个属性或者一个变量,completions包含一组完成
-
-
define
询问表达式的定义。
略。
-
documentation
略
-
refs
获取一个变量或属性的所有引用。
file,end(required)
start(optional)
返回:一个对象,包含name属性,变量或属性的名字,refs是一个数组,包含{file,start,end},如果是变量,将包含type:"global"或"local"
-
rename
重命名一个变量
file,end(required)
start(optional)
返回:一个对象,changes属性是一个数组,该数组包含{file,start,end,text},客户端需要根据这个结果做真正的修改。
-
properties
获取一个对象的所有属性名
略 -
files
获取server当前持有的文件
编程接口
基础Server是没有http交互也没有配置文件的,其实现在lib/tern.js中。
该包提供了一个Server构造器,通过它我们可以创建一个server对象。它使用一个对象作为配置,该配置包含的选项如下(都有默认值):
-
defs(array of strings)
类型定义对象,加入到sever
-
plugins(object)
指定server需要加载的插件
-
ecmaVersion(number)
按ECMAScript哪个版本进行解析。应该选择5或6,默认6.
-
getFile(function)
为server提供一个获取文件内容的方式。如果async选项为false,该函数接收filename作为参数,并返回一个字符串,或者接收一个filename参数和一个callback参数,callback接收error信息作为第一个参数,第二个参数为字符串类型的文件内容。
-
async(bool)
指定getFile是否为异步,默认为false.
fetchTimeout(number)
指定异步getFile最大等待时间,单位为毫秒。默认1000。
Server对象拥有以下方法:
-
addFile(name:string,text?:string,parent?:string)
向server注册一个文件。注意文件也可包含在请求中,如果需要通过这个方法加载一个依赖,就在第三个参数中指定文件名称(如果Tern理解这个文件)。该文件将计入依赖预算。
-
delFile(name:string)
注销一个文件。
-
request(doc:object,callback:fn(error,response))
执行一个请求。doc是一个json文档,其格式在JSON格式协议中有所描述。请求执行完毕后,callback将得到执行,如果有错误发生将在第一个参数中传入,返回内容将以第二个参数传入。
当server并没有配置为异步方式,callcack
-
flush(callback:fn())
强行读取并解析所有文件,然后调用callback。
-
on(eventType:string,handler:fn())
注册事件处理器
-
off(eventType:string,handler:fn())
注销事件处理器
-
addDefs(defs:object,atFront?:bool)
添加类型定义,atFront表示是否添加在已有定义之前
-
deleteDefs(name:string)
删除类型定义
-
loadPlugin(name:string,options?:object)
加载一个server plugin
Server会触发以下类型的事件:
-
reset
当server抛弃已有的分析并开始新的运行状态时
-
beforeLoad(file)
分析一个文件前,file是个对象包含{name,text,scope}属性
-
afterLoad(file)
分析一个文件后
-
preParse(text,options)
在一个文件解析之前,将传入给定的text和options
-
postParse(ast,text)
在一个文件解析之后,传入ast树和被解析的文件
-
preInfer(ast,scope)
在类型推断之前,传入ast树和scope对象
-
postInfer(ast,scope)
在类型推断之后
-
typeAt(file,end,expr,type)
在查找文件的指定点end处的类型后触发
-
completion(file,query)
代码完成开始时执行,可以返回一个代码完成结果来替换默认算法