0.0.2 • Published 10 years ago

managejs v0.0.2

Weekly downloads
1
License
MIT
Repository
-
Last release
10 years ago

managejs Build Status

managejs是使用nodejs编写的基于语法树的js源码分析操作工具。通过managejs,可以使用类似jQuery的操作方式来操作你的javascript源代码。

Installation

npm install managejs

Test

npm test

example

var managejs = require('managejs');

var testStr = 'var a = function (m,n){}';

var rootNode = managejs.transfer(testStr);//return root node

var fnNodes = rootNode.find('FunctionExpression','a');

console.log(fnNodes.stringify());
//function (m,n){}

fnNodes.append('var test = "xxx"');
console.log(fnNodes.stringify());
//function (m,n){var test = "xxx"}
  • transfer用于返回javascript源码的根节点
  • find使用语法树节点类型,还有对应的标识来查找节点
  • append用于往function里面注入一段代码

Introduction

语法树节点类型(ast node type)

javascript源码被词法语法分析后,会变成语法树。每个树节点对应一段源码。可以点此通过mozilla的文档了解。

如果不是很清楚一段源码的语法树结构,可以通过Esprima的在线解析器查看。

比如上面那段代码var a = function (m,n){}解析成语法树为:

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "a"
                    },
                    "init": {
                        "type": "FunctionExpression",
                        "id": null,
                        "params": [
                            {
                                "type": "Identifier",
                                "name": "m"
                            },
                            {
                                "type": "Identifier",
                                "name": "n"
                            }
                        ],
                        "defaults": [],
                        "body": {
                            "type": "BlockStatement",
                            "body": []
                        },
                        "rest": null,
                        "generator": false,
                        "expression": false
                    }
                }
            ],
            "kind": "var"
        }
    ]
}

选择器

managejs使用节点类型+标识符的方式来查找定位节点。之后这些节点会具有一系列的方法用于处理当前节点。并且支持链式操作可以继续在此节点的基础上往下查找。

选择器有四个查找函数:

1.findById

查找函数,通过(id)来查找。什么是当前节点的标识(id)呢?

  • 对于ObjectExpression,FunctionExpression,ArrayExpression,Literal等表达式来说:
var t = 表达式;  
var a = {
 t:表达式
};
t = 表达式;

//t就是当前表达式的标识(id)
  • 对于FunctionDeclaration来说:
function fnName(){};
//fnName就是当前表达式的标识
  • 对于IfStatement,ForStatement,WhileStatement来说:
if(exp){}
while(exp){}
for(exp){}
//exp就是当前表达式的标识

example:

root = require('managejs').transfer("var test222 = 'xxxx'");
root.findById('Literal','test');

2.findByString

  • param {string} type 语法树节点类型(ast type)
  • param {string} reg 匹配的字符串,支持正则写法。

  • return {JsNodeList} 返回找到的节点集合对象

使用字符串匹配,会将当前节点解析成字符串进行查找

example:

root = require('managejs').transfer("var test222 = 'xxxx'");
root.findByString('Literal','xx');

3. find

  • param {string} type 语法树节点类型(ast type)
  • param {string} reg 匹配的字符串,支持正则写法。

  • return {JsNodeList} 返回找到的节点集合对象

查找函数,是findById与findByString的结合体,会先尝试使用findById查找,如果找不到,就使用字符串匹配查找。

example:

root = require('managejs').transfer("var test222 = 'xxxx'");
root.find('Literal','xx');
//sam as 
root.find('Literal','test');

4. findByFn

  • param {string} type 语法树节点类型(ast type)
  • param {function} fn 匹配的函数,函数返回值为true代表匹配成功,否则匹配失败。

  • return {JsNodeList} 返回找到的节点集合对象

自定义函数匹配,会将当前jsNode作为参数注入。

example

root = require('managejs').transfer("var test222 = 'xxxx'");
root.findById('Literal',function(jsNode){
 console.log(jsNode.astObj)  //抽象语法树节点
 console.log(jsNode.stringify()) //将当前节点解析为字符串
 console.log(jsNode.parentJsNode()) //父节点
 return /xx/.test(jsNode.stringify()); //为true代表匹配成功
});

function (m,n){}是一个FunctionExpression节点。我们通过标识a来最终找到这个节点。 查到到的对象都是JsNodeList的节点集合对象。可以通过一些函数来操作这些节点。

API

有些api是部分节点类型才支持的,有些是所有都支持的。

源码解析


transfer(jsString, options)

  • @param {string} jsString 需要解析的字符串
  • @param {object} options 配置项
  • @param {boolean} options.remainSpace 是否保留各种空格,为true的话会保留以前的格式。会消耗性能,并且容易出错
  • @param {boolean} options.remainComment 是否保留注释
  • @return {JsNodeList} 根节点,JsNodeList对象,可以使用提供的一系列方法

用于将一段javascript字符串 解析成一个JsNodeList对象

example

root = require('managejs').transfer("code");
root.stringify();

选择器


findById,findByString,find,findByFn,详见介绍章节选择器部分

通用api

stringify()

解析当前节点生成源代码

example:

root = require('managejs').transfer("var test222 = 'xxxx'");
root.stringify(); //var test222 = 'xxxx'

getCurrentStatement()

获取当前节点所在的语句(statement)节点

example

root = require('managejs').transfer("var test222 = 'xxxx'");
root.findById('Literal','test*')    // 'xx'
root.findById('Literal','test*').getCurrentStatement() //var test222 = 'xxxx'

replaceWith(nodelist)

  • @param {string|nodelist} nodelist 需要替换的类容,可以是字符串,或者JsNodeList对象。
  • @return {JsNodeList} 返回替换后的新节点 替换当前节点集合

example

root = require('managejs').transfer("var test222 = 'xxxx'");
root.findById('Literal','xx').replaceWith("'hahaha'"); //var test222 = 'hahaha'

item()

  • @param {JsNodelist} index 节点的位置
  • @return void 类似jQuery里面的item。选择器获取到的都是节点集合JsNodeList可以使用这个item返回里面的某一个节点生成的新的JsNodeList。

语句类型通用api


下面的函数是只有语句类型的节点才能使用,包括函数声明等等。如果当前的节点不是语句类型的可以使用上面的getCurrentStatement获得父级语句节点。

insertBefore(nodelist)

  • @param {JsNodelist} nodelist 指定节点
  • @return void 用于将当前的节点插入到指定节点的前面

example:

root = require('managejs').transfer("var a = 'xxxx';var b = 'xx'");
test = root.findById('Literal','a').getCurrentStatement()
root.findByString('VariableDeclaration','b').insertBefore(test) 

insertAfter(nodelist)

  • @param {JsNodelist} nodelist指定节点
  • @return void 用于将当前的节点插入到指定节点的后面

example:

root = require('managejs').transfer("var a = 'xxxx';var b = 'xx'");
test = root.findById('Literal','a').getCurrentStatement()
root.findByString('VariableDeclaration','b').insertAfter(test) 

Function


Function包括 FunctionDeclaration,FunctionExpression。

getParam(index)

  • @param {int} index 索引,可以为负数
  • @return {JsNodeList} 返回获取到的节点 用于通过index获取参数节点。

example:

root = require('managejs').transfer("var a = function(m,n){}");
root.find('FunctionDeclaration','a').getParam(0).stringify();
//m

addParam(identifyName)

  • @param {string} 需要添加的参数名
  • @return {JsNodeList} 返回新增的节点 增加新的参数

example:

root = require('managejs').transfer("var a = function(m,n){}");
root.find('FunctionDeclaration','a').addParam('x').stringify();
//x

allParam()

  • @return {JsNodeList} 返回所有参数节点 获取所有的参数节点 example:
root = require('managejs').transfer("var a = function(m,n){}");
root.find('FunctionDeclaration','a').allParam().stringify();
//mn

spliceParam()

  • @param {int} index,整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
  • @param {int} howmany 要删除的项目数量。如果设置为 0,则不会删除项目。
  • @param {string|JsNodeList} item1, ..., itemX 可选。向数组添加的新项目。
  • @return {JsNodeList} 返回删除的数组节点 使用类似数组的splice方法。来操作参数 example:
root = require('managejs').transfer("function test(a,b,c){}");
root.find('CallExpression','test').splice(1,1,'m').stringify();//m

append(nodelist)

  • @param {string|JsNodeList} 需要append的类容,可以是字符串也可以是JsNodeList对象
  • @return {JsNodeList} 返回当前节点 在{}最后面添加新的语句节点

example:

root = require('managejs').transfer("var a = function(m,n){var t = 0;}");
root.find('FunctionDeclaration','a').append('var test =1;').stringify();

prepend(nodelist)

  • @param {string|JsNodeList} 需要append的类容,可以是字符串也可以是JsNodeList对象
  • @return {JsNodeList} 返回当前节点 在{}最前面添加语句节点 example:
root = require('managejs').transfer("var a = function(m,n){var t = 0;}");
root.find('FunctionDeclaration','a').prepend('var test =1;').stringify();

ObjectExpression


get(key)

  • @param {string} key,key的值
  • @return {JsNodeList} 返回获取到值的节点

通过key获取值节点 example:

root = require('managejs').transfer("var a = {m:1,n:2}");
root.find('ObjectExpression','a').get(0).stringify();
//1

add(key, nodelist)

  • @param {string|JsNodeList} 需要增加的key
  • @param {string|JsNodeList} 需要增加的value
  • @return {JsNodeList} 返回新增的节点 增加节点 example:
root = require('managejs').transfer("var a = {m:1,n:2}");
root.find('ObjectExpression','a').add('s','3');
root.find('ObjectExpression','a').get(-1).stringify();
//3

如果希望生成带引号的key或者value,可以add('"s"','3')。带引号的值会解析成Literal,否则会解析成Identifier。

remove(key)

  • @param {string} key,key的值
  • @return {void} 删除节点 example:
root = require('managejs').transfer("var a = {m:1,n:2}");
root.find('ObjectExpression','a').add('s','3');
root.find('ObjectExpression','a').get(-1).stringify();
//3

ArrayExpression


get(index)

  • @param {int} index,索引可以为负数,代表从后面开始
  • @return {JsNodeList} 返回获取到值的节点 获取数组节点 example:
root = require('managejs').transfer("var a = [1,2,3,4]");
root.find('ArrayExpression','a').get(-1).stringify();//4

splice()

  • @param {int} index,整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
  • @param {int} howmany 要删除的项目数量。如果设置为 0,则不会删除项目。
  • @param {string|JsNodeList} item1, ..., itemX 可选。向数组添加的新项目。
  • @return {JsNodeList} 返回删除的数组节点 类似数组的splice方法。 example:
root = require('managejs').transfer("var a = [1,2,3,4]");
root.find('ArrayExpression','a').splice(1,1,'4').stringify();//[1,4,3,4]

push(nodelist)

  • @param {string|JsNodelist} 需要添加的类容
  • @return {JsNodeList} 返回新增的节点 添加新的节点。 example:
root = require('managejs').transfer("var a = [1,2,3,4]");
root.find('ArrayExpression','a').push('5');
root.find('ArrayExpression','a').get(-1).stringify();//5;

IfStatement, ForStatement, WhileStatement


append(nodelist)

  • @param {string|JsNodeList} 需要append的类容,可以是字符串也可以是JsNodeList对象
  • @return {JsNodeList} 返回当前节点 在{}最后面添加新的语句节点

example:

root = require('managejs').transfer("if(a){}");
root.find('IfStatement','a').append('var test =1;').stringify();

prepend(nodelist)

  • @param {string|JsNodeList} 需要append的类容,可以是字符串也可以是JsNodeList对象
  • @return {JsNodeList} 返回当前节点 在{}最前面添加语句节点 example:
root = require('managejs').transfer("if(a){}");
root.find('IfStatement','a').append('var test =1;').stringify();

CallExpression


get(index)

  • @param {int} index,索引可以为负数,代表从后面开始
  • @return {JsNodeList} 返回获取到值的节点 用于通过index获取参数节点。

example:

root = require('managejs').transfer("var a = test(m,n)");
root.find('CallExpression','a').get(-1).stringify();
//n

spliceParam()

  • @param {int} index,整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
  • @param {int} howmany 要删除的项目数量。如果设置为 0,则不会删除项目。
  • @param {string|JsNodeList} item1, ..., itemX 可选。向数组添加的新项目。
  • @return {JsNodeList} 返回删除的数组节点 类似数组的splice方法。用来操作参数。 example:
root = require('managejs').transfer("test(a,b,c)");
root.find('CallExpression','test').splice(1,1,'m');
root.find('CallExpression','test').stringify();//test(a,m,c)

License

MIT