使用acorn對JavaScript程式碼進行解析。
使用acorn對JavaScript程式碼進行解析。
Acorn簡介
Acorn是一個小小的快速JavaScript解析器,完全用JavaScript編寫並且效能和效率比Esprima更勝一籌。解析思路是把程式碼解析成語法樹的形式。如下程式碼是一個簡單的例子。
c = 1 + 1;
通過Acorn解析結果如下:
AST樹簡介
在電腦科學中,抽象語法樹(abstract syntax tree或者縮寫為AST),或者語法樹(syntax
tree),是原始碼的抽象語法結構的樹狀表現形式,這裡特指程式語言的原始碼。樹上的每個節點都表示原始碼中的一種結構。之所以說語法是“抽象”的,是因為這裡的語法並不會表示出真實語法中出現的每個細節。比如,巢狀括號被隱含在樹的結構中,並沒有以節點的形式呈現;而類似於if-condition-then這樣的條件跳轉語句,可以使用帶有兩個分支的節點來表示。
AST樹作為程式的一種中間表示形式,在程式分析等諸多領域有廣泛的應用.利用抽象語法樹可以方便地實現多種源程式處理工具,比如源程式瀏覽器、智慧編輯器、語言翻譯器等.
var AST = "is Tree";
這裡的解析結果和Acorn的解析結果看起來很像,他們在形式上是相同的區別只是在於對不同資訊的儲存上或多或少,比如下程式碼
int a = 1;//給a賦值
int b = 2;
Acorn的處理邏輯會把註釋和第二句程式碼連結起來,而Esprima則是會註釋的資訊分別和兩句話都連結起來。那麼這也就在處理程式碼和註釋的對應上有一點誤差(後面會講到)。
解析過程和核心程式碼介紹
要使用Acorn進行解析那麼第一步就是安裝Acorn,通過npm install acorn
即可安裝。
我們的目的是提取JavaScript程式碼中的註釋和對應的程式碼,所以對應的操作就是
1. 如何解析出AST樹。
2. 如何遍歷AST樹拿出其中的註釋和找到註釋對應的程式碼。
3. 如何把註釋和註釋對應的程式碼存成對應的格式。
Acorn對程式碼的解析很簡單
var ast = acorn.parse(source, {
sourceType: "script",
locations: true,
onComment: comments,
onToken: tokens,
});
官方給出這樣的解釋“*parse(input, options) is used to parse a JavaScript
program. The input parameter is a string, options can be undefined or
an object setting some of the options listed below. The return value
will be an abstract syntax tree object as specified by the ESTree
spec.*”通過以上操作我們便可以得到解析完成AST,第一個引數是String型別的文字,第二個引數是一個物件,是對AST樹的一些設定。下邊對上面用到的引數做一個收集
locations :When true, each node has a loc object attached with start and end subobjects, each of which contains the one-based line and zero-based column numbers in {line, column} form. Default is false.
onComment: If a function is passed for this option, whenever a comment is encountered the function will be called with the following parameters:
block: true if the comment is a block comment, false if it is a line comment.
text: The content of the comment.
start: Character offset of the start of the comment.
end: Character offset of the end of the comment.
每個註釋都會被按照下面的形式儲存起來
當我們通過Acorn拿到了帶有完整註釋資訊的AST樹那麼就有對樹進行一個遍歷,取出對註釋和註釋對應的程式碼進行儲存。
//註釋說明1
int a = 2;
//註釋說明2
int b = 3;
//註釋說明3
經過對於AST樹中的節點來說 註釋一是程式碼一的leadingComments,註釋而是程式碼一的trailingComments,同樣程式碼二也有對應的leadingComments和trailingComments分別是註釋二和註釋三。但是也有一種特殊的情況如下
int a = 2; //註釋說明1
int b = 3;
//註釋說明2
註釋一和註釋二會被認為是程式碼二的leadingComments和trailingComments,而程式碼一沒有trailingComments。這樣的話就和我們的處理邏輯是不一樣的,我們需要然後上面例子中註釋一是程式碼一的trailingComments。所以就需要對整個樹進行一個遍歷,對節點資訊記性一個設定。
遍歷會用到estraverse
這個庫。處理邏輯如下程式碼所示
estraverse.traverse(ast, {
leave: function (node, parent) {
if (!node.hasOwnProperty('trailingComments')) {
var old_node = node;
var old_line = node.loc.end.line;
var old_column = node.loc.end.column;
estraverse.traverse(parent, {
leave: function (node, parent) {
if (node !== old_node &&
node.hasOwnProperty('leadingComments') &&
node.leadingComments[0].loc.start.line === old_line &&
node.leadingComments[0].loc.start.column >= old_column) {
old_node.trailingComments = [];
old_node.trailingComments[0] = node.leadingComments.shift();
if (node.leadingComments.length === 0) {
delete node.leadingComments;
}
estraverse.VisitorOption.Break;
}
}
});
node = old_node;
}
通過如上操作便可對上文提到的特殊情況進行更正。
現在最後一個問題就是如何把得到的註釋和程式碼對應起來,對AST樹來說這裡操作就很簡單了,我們需要對AST在遍歷時候對每個節點的狀態進行判別。
var t = node.hasOwnProperty('trailingComments');
var l = node.hasOwnProperty('leadingComments');
if (t && l) {
comment_code.comment = node.leadingComments.concat(node.trailingComments);
comment_code.code.push(escodegen.generate(node));//將註釋和程式碼對應起來
extract.push(comment_code);
}
else if (l) {
comment_code.comment = node.leadingComments;
comment_code.code.push(escodegen.generate(node));
extract.push(comment_code);
}
else if (t) {
comment_code.comment = node.trailingComments;
comment_code.code.push(escodegen.generate(node));
extract.push(comment_code);
}
comment_code = {comment: [], code: []};
把程式碼和註釋都存在陣列中之後,通過
var fs = require("fs");
fs.writeFileSync(filepaht, filecontent);
進行儲存。到此處理完畢。
相關文章
- 使用 Acorn 來解析 JavaScriptJavaScript
- javascript對空格和換行進行編碼程式碼例項JavaScript
- Docker中使用Xhprof 對程式碼進行效能分析Docker
- 用 Mocha 和 Chai 對 JavaScript 程式碼進行單元測試AIJavaScript
- 如何使用Python對引數進行解析Python
- 對.net 程式進行原始碼混淆原始碼
- 使用javascript如何給url進行編碼JavaScript
- 使用JAXP對xml文件進行DOM解析基礎XML
- 使用cJSON庫對JSON格式進行解析JSON
- 使用FakeAsync對Angular非同步程式碼進行單元測試Angular非同步
- 實際業務中使用策略模式對程式碼進行重構模式
- 使用springboot對各層的程式碼進行測試!Spring Boot
- 使用JAXP進行DOM解析_SAX解析
- javascript this 用法例項程式碼解析JavaScript
- 使用 Swift 進行 JSON 解析SwiftJSON
- 使用shell指令碼對Nginx日誌進行切分指令碼Nginx
- 使用jaxp解析器dom方式對xml節點進行操作XML
- 使用 JavaScript 進行函數語言程式設計 (一)JavaScript函數程式設計
- JavaScript 使用sort()方法從數值上對陣列進行排序JavaScript陣列排序
- 使用網頁前端JavaScript使用RSA對長字串進行加密及測試解密,1024位可對長字串進行網頁前端JavaScript字串加密解密
- 前端使用bcrypt對密碼加密,伺服器對密碼進行校驗前端密碼加密伺服器
- 使用Shell指令碼對Linux系統和程式資源進行監控指令碼Linux
- 使用Git進行小專案程式碼管理Git
- 使用CountDownLatch或迴圈屏障對多執行緒程式碼進行單元測試 -XebiaCountDownLatch執行緒
- 使用 JavaScript 進行單詞發音JavaScript
- 在JavaScript中對HTML進行反轉義JavaScriptHTML
- 一段對16進位制字串進行異或的程式碼字串
- 對比學習 ——simsiam 程式碼解析。
- 對iOS端支付寶和微信支付程式碼進行整合iOS
- 使用Faric+Git進行分散式程式碼管理Git分散式
- HP刀箱使用U盤對OA密碼進行重置密碼
- 使用node.js 進行伺服器端JavaScript程式設計Node.js伺服器JavaScript程式設計
- 使用JAXP進行DOM解析( DocumentBuilderFactory、DocumentBuilder、Document)UI
- javascript 絕對值程式碼例項JavaScript
- JavaScript程式碼檢查工具對比JavaScript
- SQL對資料進行按月統計或對資料進行按星期統計的例項程式碼SQL
- Collections工具類,可以使用collections工具類對程式碼中的list進行分組
- js裡對URL進行編碼、解碼JS