前置知识
- AST spec
- Babel 插件开发手册
源码解析
源代码
import { declare } from "@babel/helper-plugin-utils";
import { types as t } from "@babel/core";
export default declare(api => {
api.assertVersion(7);
return {
name: "transform-member-expression-literals",
visitor: {
MemberExpression: {
exit({ node }) {
const prop = node.property;
if (
!node.computed &&
t.isIdentifier(prop) &&
!t.isValidES3Identifier(prop.name)
) {
// foo.default -> foo["default"]
node.property = t.stringLiteral(prop.name);
node.computed = true;
}
},
},
},
};
});
用途
官方说明
看 UT,对象的key如果是关键字,会从.
形式转为[]
形式
// input.js
test.catch;
test.catch.foo;
test["catch"];
test["catch"].foo;
// output.js
test["catch"];
test["catch"].foo;
test["catch"];
test["catch"].foo;
解析
通过Babel 插件开发手册,可知插件中的访问器处理 MemberExpression,AST spec中 MemberExpression 说明如下:
interface MemberExpression <: Expression, Pattern {
type: "MemberExpression";
object: Expression | Super;
property: Expression | PrivateName;
computed: boolean;
}
A member expression. If computed is true, the node corresponds to a computed (a[b]) member expression and property is an Expression. If computed is false, the node corresponds to a static (a.b) member expression and property is an Identifier or a PrivateName.
意思是:成员表达式。如果 computed 为 true,则节点对应于计算的(a[b])成员表达式,而 property 是表达式。如果 computed 为 false,则节点对应于静态(a.b)成员表达式,并且属性是标识符或 PrivateName。
exit 方法的参数是一个响应式的 Path 对象, 包含 parent, node 等属性。path.node.property得到一个AST节点的属性值
t.isIdentifier(prop)
相当于 node.property.type === 'identifier'
isValidES3Identifier
主要验证下 key 合法性,部分代码如下:
/**
* Check if the input `name` is a valid identifier name
* and isn't a reserved word.
*/
export default function isValidIdentifier(
name: string,
reserved: boolean = true,
): boolean {
if (typeof name !== "string") return false;
if (reserved) {
if (isKeyword(name) || isStrictReservedWord(name)) {
return false;
} else if (name === "await") {
// invalid in module, valid in script; better be safe (see #4952)
return false;
}
}
return isIdentifierName(name);
}
const RESERVED_WORDS_ES3_ONLY: Set<string> = new Set([
"abstract",
"boolean",
"byte",
"char",
"double",
"enum",
"final",
"float",
"goto",
"implements",
"int",
"interface",
"long",
"native",
"package",
"private",
"protected",
"public",
"short",
"static",
"synchronized",
"throws",
"transient",
"volatile",
]);
/**
* Check if the input `name` is a valid identifier name according to the ES3 specification.
*
* Additional ES3 reserved words are
*/
export default function isValidES3Identifier(name: string): boolean {
return isValidIdentifier(name) && !RESERVED_WORDS_ES3_ONLY.has(name);
}
node.property = t.stringLiteral(prop.name);
作用是把 PrivateName 改为 Expression。
interface PrivateName <: Node {
type: "PrivateName";
id: Identifier;
}
interface Literal <: Expression { }
interface StringLiteral <: Literal {
type: "StringLiteral";
value: string;
}
AST树对比(去掉了解析的位置信息)
// test.catch.foo;
{
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "test"
},
"property": {
"type": "Identifier",
"name": "catch"
},
"computed": false,
"optional": false
},
"property": {
"type": "Identifier",
"name": "foo"
},
"computed": false,
"optional": false
}
}
],
"sourceType": "module"
}
// test["catch"].foo
{
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "test"
},
"property": {
"type": "Literal",
"start": 5,
"end": 12,
"value": "catch",
"raw": "\"catch\""
},
"computed": true,
"optional": false
},
"property": {
"type": "Identifier",
"name": "foo"
},
"computed": false,
"optional": false
}
}
],
"sourceType": "module"
}
变动部分
// test.catch.foo;
"property": {
"type": "Identifier",
"name": "catch"
},
"computed": false,
// test["catch"].foo
"property": {
"type": "Literal",
"value": "catch",
"raw": "\"catch\""
},
"computed": true,
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!