[Javascript AST] 0. Introduction: Write a simple BabelJS plugin
To write a simple Babel plugin, we can use http://astexplorer.net/ to help us.
The plugin we want to write is:
var foo = 'o'
var bar = 'o'
foo === bar
function foo(foo, bar) {
foo === bar;
}
We want to trasnform the code which highlighted in foo() function to:
_foo === _bar
Notice that, we also have 'foo === bar' which is not inside foo() function. But we don't want to touch that.
To get started, we have code below:
export default function(babel) {
const { types: t } = babel;
return {
name: "add_underscore",
visitor: {
// your code here
}
};
}
All the code is under 'visitor' prop.
By hightlight the code we can see, it is a 'BinaryExpression':

So we focus on 'BinaryExpression':
export default function(babel) {
const { types: t } = babel;
return {
name: "add_underscore",
visitor: {
BinaryExpression(path) {
}
}
};
}
'path' param contains all the information we need.
If add a console.log() inside BinarayExpression() function, we can see two logs, one is from global scope, another one is from 'foo()' scope. We only want to get one from foo() function scope:
The way to do is check 'path.scope.block.type', which is current code' block scope.
'foo === bar' exisits on global belongs to 'Program':
the one exists in foo() belongs to 'BlockStatement':
BinaryExpression(path) {
// remove global one
if (path.scope.block.type === "Program") {
return;
}
}
And the opreator we want to check is '===':
BinaryExpression(path) {
if (path.scope.block.type === "Program") {
return;
}
if (path.node.operator !== "===") {
return;
}
}
Now we have located the one 'foo === bar' we want, we can start to replace the name:
export default function(babel) {
const { types: t } = babel;
return {
name: "add_underscore",
visitor: {
BinaryExpression(path) {
if (path.scope.block.type === "Program") {
return;
}
if (path.node.operator !== "===") {
return;
}
// locate the 'foo' and 'bar'
// as left and right Identifier
const leftIdentifier = path.node.left;
const rightIndentifier = path.node.right;
// generate a new identifier
const newLeftIdentifier = path.scope.generateUidIdentifier(leftIdentifier.name);
const newRightIdentifier = path.scope.generateUidIdentifier(
rightIndentifier.name
);
// replace the old with new one
path.node.left = t.identifier(newLeftIdentifier.name);
path.node.right = t.identifier(newRightIdentifier.name);
}
}
};
}
Now the generate code looks like:
var foo = 'o'
var bar = 'o'
foo === bar
function foo(foo, bar) {
_foo === _bar;
}
The code have successfully transform to '_foo === _bar'.
But clearly the code won't work, because _foo and _bar is undefined.
We need to update the params in the function as well.
// update params in the function
const [fooParam, barParam] = path.scope.block.params;
fooParam.name = t.identifier(newLeftIdentifier.name).name;
barParam.name = t.identifier(newRightIdentifier.name).name;
All Code:
export default function(babel) {
const { types: t } = babel;
return {
name: "add_underscore",
visitor: {
BinaryExpression(path) {
if (path.scope.block.type === "Program") {
return;
}
if (path.node.operator !== "===") {
return;
}
// locate the 'foo' and 'bar'
// as left and right Identifier
const leftIdentifier = path.node.left;
const rightIndentifier = path.node.right;
// generate a new identifier
const newLeftIdentifier = path.scope.generateUidIdentifier(leftIdentifier.name);
const newRightIdentifier = path.scope.generateUidIdentifier(
rightIndentifier.name
);
// replace the old with new one
path.node.left = t.identifier(newLeftIdentifier.name);
path.node.right = t.identifier(newRightIdentifier.name);
// update params in the function
const [fooParam, barParam] = path.scope.block.params;
fooParam.name = t.identifier(newLeftIdentifier.name).name;
barParam.name = t.identifier(newRightIdentifier.name).name;
}
}
};
}
[Notice]: this is a just learning note for myself. The approache might not be optimal.
[Javascript AST] 0. Introduction: Write a simple BabelJS plugin的更多相关文章
- [Javascript AST] 2. Introduction: Write a simple ESLint rule
What we want to do is checking if user write nested if statements which actually can combine to one: ...
- [Javascript AST] 1. Continue: Write a simple Babel plugin
We want to write a Babel Plugin, which move 'const versionRegex = /(/d+)\.(/d+)\.(/d+)/gi' out of fu ...
- js中 javascript:void(0) 用法详解
点击链接不做任何事情: <a href="#" onclick="return false">test</a> <a href=& ...
- html 空链接 href="#"与href="javascript:void(0)"的区别
#包含了一个位置信息 默认的锚是#top 也就是网页的上端 而javascript:void(0) 仅仅表示一个死链接 这就是为什么有的时候页面很长浏览链接明明是#但跳动到了页首 而javascrip ...
- a href=#与 a href=javascript:void(0) 的区别
a href="#"> 点击链接后,页面会向上滚到页首,# 默认锚点为 #TOP <a href="javascript:void(0)" onCl ...
- href使用 javascript:;与javascript:void(0)防跳到顶部
有时候我们在编写js过程中,需要触发事件而不需要返回值,那么就可能需要这样的写法 href=”#”,包含了一个位置信息.默认的锚是#top,也就是网页的上端,当连续快速点击此链接时会导致浏览器巨慢 ...
- javascript:void(0)
这是不是一个设计缺陷呢 void(0)这种用法巧妙利用void关键字的特性返回undefined(且没有副作用).因为不是关键字,比如直接使用undefined,内容可能被改写. 再来看为啥使用0,而 ...
- <a href=”#”>与 <a href=”javascript:void(0)” 的区别
<a href=”#”>中的“#”其实是锚点的意思,默认为#top,所以当页面比较长的时候,使用这种方式会让页面刷新到页首(页面的最上部) javascript:void(0)其实是一个死 ...
- 超级链接a中javascript:void(0)弹出另外一个框问题
转字:http://my.oschina.net/castusz/blog/68186 结果在IE.Firefox.Chrome都是先执行的onclick事件,在项目中我们尽量不要同时使用这两种方式. ...
随机推荐
- Magento--修改已存在的订单的运费
遇到一种情况,需要在下单后再由管理员添加订单运费,然后顾客再付款.那么问题来了,如何给订单添加运费呢?下面是一段代码,可以实现该功能: $orderId = 'your order id';$orde ...
- 129.C++面试一百题(1-51)
- spring-security-oauth2注解详解
spring-security-oauth2支持的注解有: 1.EnableOAuth2Client 适用于使用spring security,并且想从Oauth2认证服务器来获取授权的web应用环境 ...
- 版本控制Git(1)——理解暂存区
一.svn和Git的比较 我们都知道传统的源代码管理都是以服务器为中心的,每个开发者都直接连在中间服务器上, 本地修改,然后commit到svn服务器上.这种做法看似完美,但是有致命的缺陷. 1. 开 ...
- Python(十一) 原生爬虫
一.分析抓取目的确定抓取页面 #爬取主播人气排行 二.整理爬虫常规思路 爬虫前奏 明确目的 找到数据对应的网页 分析网页的结构找到数据所在的标签位置 模拟 HTTP 请求, 向服务器发送这个请 ...
- HTTP 各种特性应用(二)
一.Cookie 通过 Set-Cookie 设置. 下次浏览器请求就会带上. 键值对,可以设置多个. Cookie 属性 max-age 和 expires 设置过期时间 Secure 只在 htt ...
- [Chromium文档转载,第002章]Mojo C++ Bindings API
Mojo C++ Bindings API This document is a subset of the Mojo documentation. Contents Overview Getting ...
- CCF模拟题 字符串匹配
字符串匹配 时间限制: 1.0s 内存限制: 256.0MB 问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你的程序还需支持大小写敏感选项:当选项打开时,表示同一个字母的大写 ...
- QTP校验数据库中数据后台项目
数据校验功能后台主要包含两个类:QTPCommonServlet.java和QTPCommonDao.java 当中QTPCommonServlet.java为: package com.runqia ...
- servlet学习(1)
1.Servlet是sun公司提供的一门用于开发动态web资源的技术. 2.Servlet在web应用的位置: 3.创建Servlet的三种方式: (1)实现servlet的接口 (2)继承Gener ...