成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

tsquery——一個(gè)方便的ast查詢工具

Neilyo / 1717人閱讀

摘要:結(jié)合上面三個(gè)函數(shù),我們可以得到的基本使用方法獲得語法樹獲得選擇器查找節(jié)點(diǎn)如果語法樹和選擇器可能被多次使用,則建議使用變量將它們分別保存下來,避免重復(fù)解析導(dǎo)致的資源浪費(fèi)和時(shí)間開銷的生成和遍歷還是比較花時(shí)間的。

前言

最近在給公司的 web 框架做一個(gè) vscode 的輔助插件,其中有個(gè)對(duì)需要路由一些文件進(jìn)行解析,實(shí)現(xiàn)配置文件和對(duì)應(yīng)文件的關(guān)聯(lián)信息顯示和跳轉(zhuǎn)的功能。既然是對(duì)文件進(jìn)行解析,很自然就會(huì)想到使用 ast 的方式來做,加上需要對(duì) TypeScript 也進(jìn)行支持,我便選擇了使用 TypeScript 自帶的 ast 工具來進(jìn)行解析。

在一開始我通過 ts 的forEachChild方法遍歷和對(duì)比節(jié)點(diǎn)的kind屬性來確定是否是我需要處理的節(jié)點(diǎn),但是之后發(fā)現(xiàn)這個(gè)方式有幾個(gè)缺點(diǎn):

當(dāng)需要查找滿足條件的子級(jí)的 ast 節(jié)點(diǎn)時(shí),需要做多次比較

對(duì)滿足某一條件的多個(gè)不同類型的節(jié)點(diǎn)需要比較多次,編寫滿足條件麻煩

對(duì)分布在同一文件中的多個(gè)同名標(biāo)識(shí)符,不能統(tǒng)一提取和處理

為了解決這些,我找到并引入了tsquery這個(gè)庫,它是 TypeScript 版的esquery,能夠讓我們使用 css 選擇器的方式來快速查詢滿足指定條件的 TypeScript ast 節(jié)點(diǎn)(也支持 JavaScript)。

比較 demo

在介紹tsquery的使用方式之前,我們先來看一個(gè)對(duì)比。

對(duì)下面這段簡(jiǎn)單的代碼:

class Animal {
  constructor(public name: string) { }
  move(distanceInMeters: number = 0) {
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}

若我們要查找到Animal這個(gè)類的構(gòu)造函數(shù)的所有參數(shù)并打印它們的名稱,在使用 tsquery 之前,我們會(huì)編寫這樣一段代碼:

import { ClassDeclaration, createSourceFile, Node, ScriptTarget, ConstructorDeclaration, SyntaxKind } from "TypeScript";
import { code } from "./code";

const sourceFile = createSourceFile("fileName", code, ScriptTarget.Latest, true);
sourceFile.forEachChild(findClass);

function findClass(node: Node): void {
  if (node.kind === SyntaxKind.ClassDeclaration) {
    const { name } = node as ClassDeclaration;
    if (name && name.text === "Animal") {
      node.forEachChild(findConstructor);
      return;
    }
  }
  node.forEachChild(findClass);
}

function findConstructor(node: Node): void {
  if (node.kind === SyntaxKind.Constructor) {
    printParameters(node as ConstructorDeclaration);
  }
}

function printParameters(node: ConstructorDeclaration) {
  node.parameters.forEach(parameter => {
    console.log(parameter.name.getText());
  })
}

而在我們引入了tsquery之后,只需要下面這么幾行簡(jiǎn)單的代碼:

import { tsquery } from "@phenomnomnominal/tsquery";
import * as ts from "TypeScript";
import { code } from "./code";

const parameters = tsquery.query(code, "ClassDeclaration[name.name="Animal"] > Constructor > Parameter");
parameters.forEach(param => console.log(param.name.getText()));

怎么樣,是不是對(duì)比強(qiáng)烈,讓你迫不及待得想把tsquery用到自己的項(xiàng)目中?

使用方式

那么接下來,我就來介紹一下如何去使用tsquery:

API

tsquery對(duì)象提供了下面幾個(gè)方法:

ast:

function ast(source: string, fileName?: string): SourceFile;

ast方法的功能如同其名,就是接收源代碼,返回一個(gè)解析后的ast語法樹,實(shí)際上就是調(diào)用了ts的createSourceFile方法。

parse:

function parse(selector: string, options?: TSQueryOptions): TSQuerySelectorNode;

parse方法接收一個(gè)規(guī)則字符串,這個(gè)字符串會(huì)被解析成tsquery的選擇器對(duì)象并返回,再被用于下面的match方法中。

match:

function match(ast: Node | TSQueryNode, selector: TSQuerySelectorNode, options?: TSQueryOptions): Array>;

match方法接收一個(gè)ast對(duì)象和一個(gè)parse解析后得到的選擇器對(duì)象,返回從ast中搜索得到的所有滿足選擇器條件的節(jié)點(diǎn)的數(shù)組。

結(jié)合上面三個(gè)函數(shù),我們可以得到tsquery的基本使用方法:

const ast = tsquery.ast(code);  // 獲得ast語法樹
const selector = tsquery.parse(selectorStr);  // 獲得選擇器
const result = tsquery.match(ast, selector);  // 查找節(jié)點(diǎn)

如果語法樹和選擇器可能被多次使用,則建議使用變量將它們分別保存下來,避免重復(fù)解析導(dǎo)致的資源浪費(fèi)和時(shí)間開銷(ast的生成和遍歷還是比較花時(shí)間的)。

如果語法樹和選擇器不會(huì)被重復(fù)使用,那么可以使用更簡(jiǎn)單的方法 query。

query:

function query(ast: string | Node | TSQueryNode, selector: string, options?: TSQueryOptions): Array>;

query封裝了ast、parse和match三個(gè)方法,可以更方便地完成一次查詢,同時(shí)tsquery自身也是一個(gè)query方法。

const result = tsquery.query(code, selectorStr);
// const result = tsquery(code, selectorStr);
選擇器規(guī)則

通用選擇器

和css中的一樣,*表示選擇所有的節(jié)點(diǎn)。

AST節(jié)點(diǎn)類型選擇器

你可以直接使用一個(gè)ast節(jié)點(diǎn)的類型來當(dāng)作查詢的選擇器,例如:類聲明: ClassDeclaration,變量聲明:VariableDeclaration等,就跟你使用css選擇器選擇某種HTML元素一樣。

屬性選擇器

tsquery支持使用css中屬性選擇器的方式來搜索滿足屬性條件的節(jié)點(diǎn),你可以僅僅只聲明一個(gè)屬性的名稱(例如:[text]),也可以指定屬性的值所滿足的條件(例如:[text="foo"]),其中操作符可以是=、"!="、">"、"<"、"<="、">=",值也可以是字符串、數(shù)字、正則表達(dá)式中的任意一種。
tsquery支持多級(jí)的屬性選擇,所以你也可以使用.來組合屬性(例如:[members.length<3])。

常見的后代、兄弟節(jié)點(diǎn)選擇器等

后代節(jié)點(diǎn)選擇器:node otherNode
子節(jié)點(diǎn)選擇器:node > otherNode
同級(jí)節(jié)點(diǎn)選擇器:node ~ otherNode
相鄰節(jié)點(diǎn)選擇器:node + otherNode
群組選擇器:node, otherNode

各種特殊的選擇器

not選擇器::not(ClassDeclaration) 用來選擇所有不是類聲明的節(jié)點(diǎn)
has選擇器:IfStatement:has([left.text="foo"]) 用來選擇含有符合[left.text="foo"]屬性選擇器的子節(jié)點(diǎn)的if語句
第n個(gè)節(jié)點(diǎn)的選擇器:包含 :first-child:last-child、:nth-child(n):nth-last-child(n) 這幾種選擇器,其中需要注意的是,tsquery并不支持an+b這種類型的序號(hào)匹配
類型選擇器:區(qū)分于AST節(jié)點(diǎn)類型選擇器,這個(gè)選擇器是用來選擇某種共通類型的(比如所有聲明、所有表達(dá)式等),目前支持的有:statement, :expression, :declaration, :function, 和 :pattern

以上所有的選擇器都可以混合使用

總結(jié)

tsquery 是一個(gè)非常方便和值得使用的 ast 輔助工具,它使用極為簡(jiǎn)單的 api 和學(xué)習(xí)成本較低的選擇器規(guī)則,提供了對(duì)抽象和復(fù)雜的 AST 語法樹較強(qiáng)的查詢能力,可以在我們對(duì) AST 進(jìn)行處理時(shí)節(jié)省大量的編寫成本。

如果你對(duì) tsquery 的選擇器規(guī)則抱有疑問,可以在 TSQuery Playground 上進(jìn)行在線的測(cè)試。

參考內(nèi)容:

Easier TypeScript tooling with TSQuery

在文章最后打個(gè)招聘廣告:

有贊招聘前端工程師,實(shí)習(xí)、校招、社招都可,具體要求可以參考https://job.youzan.com/,同時(shí)您也可以將簡(jiǎn)歷投遞到我的內(nèi)推郵箱:[email protected]

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97820.html

相關(guān)文章

  • 探索babel和babel插件是怎么工作

    摘要:我們更多要去做的是去修改和改變生成的這個(gè)抽象語法樹。我們已經(jīng)知道會(huì)遍歷節(jié)點(diǎn)組成的抽象語法樹,每一個(gè)節(jié)點(diǎn)都會(huì)有自己對(duì)應(yīng)的比如變量節(jié)點(diǎn)等。 你有可能會(huì)聽到過這個(gè)詞 webpack工程師 ,這個(gè)看似像是一個(gè)專業(yè)很強(qiáng)的職位其實(shí)很多時(shí)候是一些前端對(duì)現(xiàn)在前端工作方式對(duì)一些吐槽,對(duì)于一個(gè)之前沒有接觸過webpack,nodejs,babel 之類的工具的人來說,看到大量的配置文件后很多人都會(huì)看懵 s...

    dongxiawu 評(píng)論0 收藏0
  • 使用 Phan 為你 PHP 項(xiàng)目保駕護(hù)航 - 代碼靜態(tài)掃描

    摘要:比如上面的例子文件文件我們利用做了語法解析檢測(cè),代碼如下報(bào)錯(cuò)哪里類重復(fù)了不存在查看該屬性是否存在于父類中原理能就是對(duì)解析出來的繼續(xù)做分析,但是前人栽樹后人乘涼,這樣的完整工具已經(jīng)有大神幫我們做好了。 原文:我的個(gè)人博客 https://mengkang.net/1356.html 工作了兩三年,技術(shù)停滯不前,迷茫沒有方向,不如看下我的直播 PHP 進(jìn)階之路 (金三銀四跳槽必考,一般人...

    array_huang 評(píng)論0 收藏0
  • Hive介紹

    摘要:通過給用戶提供的一系列交互接口,接收到用戶的指令,使用自己的,結(jié)合元數(shù)據(jù),將這些指令翻譯成,提交到中執(zhí)行,最后,將執(zhí)行返回的結(jié)果輸出到用戶交互接口。什么是Hivehive簡(jiǎn)介hive是由Facebook開源用于解決海量結(jié)構(gòu)化日志的數(shù)據(jù)統(tǒng)計(jì)工具,是基于Hadoop的一個(gè)數(shù)據(jù)倉庫工具,可以將結(jié)構(gòu)化的數(shù)據(jù)文件映射為一張表,并提供類 SQL查詢功能。Hive本質(zhì)將HQL轉(zhuǎn)化成MapReduce程序。...

    Tecode 評(píng)論0 收藏0
  • Babylon-AST初探-代碼查詢(Retrieve)

    摘要:針對(duì)語法樹節(jié)點(diǎn)的查詢操作通常伴隨著和這兩種方法見下一篇文章。注意上述代碼打印出的和中的并不完全一致。如函數(shù),在中的為,但其實(shí)際的為。這個(gè)大家一定要注意哦,因?yàn)樵谖覀兒竺娴膶?shí)際代碼中也有用到。 ??在上一篇文章中,我們介紹了AST的Create。在這篇文章中,我們接著來介紹AST的Retrieve。??針對(duì)語法樹節(jié)點(diǎn)的查詢(Retrieve)操作通常伴隨著Update和Remove(這兩...

    wangdai 評(píng)論0 收藏0
  • AST抽象語法樹——最基礎(chǔ)javascript重點(diǎn)知識(shí),99%人根本不了解

    摘要:抽象語法樹,是一個(gè)非常基礎(chǔ)而重要的知識(shí)點(diǎn),但國(guó)內(nèi)的文檔卻幾乎一片空白。事實(shí)上,在世界中,你可以認(rèn)為抽象語法樹是最底層。通過抽象語法樹解析,我們可以像童年時(shí)拆解玩具一樣,透視這臺(tái)機(jī)器的運(yùn)轉(zhuǎn),并且重新按著你的意愿來組裝。 抽象語法樹(AST),是一個(gè)非?;A(chǔ)而重要的知識(shí)點(diǎn),但國(guó)內(nèi)的文檔卻幾乎一片空白。本文將帶大家從底層了解AST,并且通過發(fā)布一個(gè)小型前端工具,來帶大家了解AST的強(qiáng)大功能 ...

    godiscoder 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<