babel-plugin-prototype-prop-define
Advanced tools
Comparing version 2.0.2 to 2.2.0
{ | ||
"name": "babel-plugin-prototype-prop-define", | ||
"version": "2.0.2", | ||
"version": "2.2.0", | ||
"description": "Transform assignments to properties on built-in prototypes to Object.defineProperty calls", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -57,9 +57,17 @@ import path from 'path' | ||
`, | ||
// 'key as string': ` | ||
'dynamic key': ` | ||
// const x = {} | ||
// x["toString"] = () => true | ||
const x = {} | ||
;['toString'].forEach(key => { | ||
x[key] = () => true | ||
}) | ||
`, | ||
'key as string': ` | ||
// `, | ||
const x = {} | ||
x["toString"] = () => true | ||
`, | ||
}, | ||
}) |
202
src/index.js
@@ -72,2 +72,3 @@ const primordialKeySet = new Set([ | ||
AssignmentExpression(path) { | ||
// | ||
@@ -79,2 +80,6 @@ // match | ||
const {node} = path | ||
// internal flag to skip node | ||
if (node.prototypePropDefineSkip) return | ||
// ensure basic assignment (not += etc) | ||
@@ -86,33 +91,56 @@ if (node.operator !== '=') return | ||
if (member.type !== 'MemberExpression') return | ||
if (member.computed) return | ||
// ensure member is a member expression for "prototype" | ||
// assignmentParent -> "Xyz" | ||
const assignmentParent = member.object | ||
// assignmentParent -> "toString" | ||
// assignmentPropertyr -> "toString" | ||
const assignmentProperty = member.property | ||
if (assignmentProperty.type !== 'Identifier') return | ||
if (!primordialKeySet.has(assignmentProperty.name)) return | ||
// assignmentValue -> "function(){ return "hello" }" | ||
const assignmentValue = node.right | ||
// | ||
// transform | ||
// | ||
// parentStatement -> "Xyz" | ||
const parentStatement = assignmentParent | ||
// propertyKeyStatement -> "toString" | ||
const propertyKeyStatement = memberPropToDefinePropKeyArg( | ||
assignmentProperty, | ||
) | ||
// valueStatement -> "function(){ return "hello" }" | ||
const valueStatement = assignmentValue | ||
const isDynamicAssignment = member.computed && assignmentProperty.type !== 'StringLiteral' | ||
if (isDynamicAssignment) { | ||
const dynamicAssignmentCheck = createDynamicAssignmentCheck( | ||
parentStatement, | ||
assignmentProperty, | ||
valueStatement, | ||
) | ||
const definePropertyExpression = createDefinePropertyExpression( | ||
parentStatement, | ||
propertyKeyStatement, | ||
valueStatement, | ||
) | ||
path.replaceWith(dynamicAssignmentCheck) | ||
path.replaceWith(definePropertyExpression) | ||
} else { | ||
let assignmentKey | ||
switch (assignmentProperty.type) { | ||
case 'StringLiteral': | ||
assignmentKey = assignmentProperty.value | ||
break | ||
case 'Identifier': | ||
assignmentKey = assignmentProperty.name | ||
break | ||
default: | ||
return | ||
} | ||
// if (assignmentProperty.type !== 'Identifier') return | ||
// skip if proeprty not on whitelist | ||
if (!primordialKeySet.has(assignmentKey)) return | ||
// propertyKeyStatement -> "toString" | ||
const propertyKeyStatement = createStringLiteral( | ||
assignmentKey, | ||
) | ||
const definePropertyExpression = createDefinePropertyExpression( | ||
parentStatement, | ||
propertyKeyStatement, | ||
valueStatement, | ||
) | ||
path.replaceWith(definePropertyExpression) | ||
} | ||
}, | ||
@@ -150,10 +178,10 @@ }, | ||
function memberPropToDefinePropKeyArg(memberProp) { | ||
function createStringLiteral (value) { | ||
return { | ||
type: 'StringLiteral', | ||
value: memberProp.name, | ||
value, | ||
} | ||
} | ||
function createPropertyDescriptor(valueStatement) { | ||
function createPropertyDescriptor (valueStatement) { | ||
return { | ||
@@ -207,1 +235,131 @@ type: 'ObjectExpression', | ||
} | ||
// (function(target, key, value){ | ||
// [].includes(key) ? | ||
// DEFINE_PROP : | ||
// target[key] = value; | ||
// return value | ||
// })(a, b, c) | ||
function createDynamicAssignmentCheck ( | ||
parentStatement, | ||
propertyKeyStatement, | ||
valueStatement, | ||
) { | ||
return { | ||
"type": "ExpressionStatement", | ||
"expression": { | ||
"type": "CallExpression", | ||
"callee": { | ||
"type": "FunctionExpression", | ||
"id": null, | ||
"generator": false, | ||
"async": false, | ||
"params": [ | ||
{ | ||
"type": "Identifier", | ||
"name": "target" | ||
}, | ||
{ | ||
"type": "Identifier", | ||
"name": "key" | ||
}, | ||
{ | ||
"type": "Identifier", | ||
"name": "value" | ||
} | ||
], | ||
"body": { | ||
"type": "BlockStatement", | ||
"body": [ | ||
{ | ||
"type": "ExpressionStatement", | ||
"expression": { | ||
"type": "ConditionalExpression", | ||
"test": { | ||
"type": "CallExpression", | ||
"callee": { | ||
"type": "MemberExpression", | ||
"object": createPrimordialKeyArray(), | ||
"property": { | ||
"type": "Identifier", | ||
"name": "includes" | ||
}, | ||
"computed": false | ||
}, | ||
"arguments": [ | ||
{ | ||
"type": "Identifier", | ||
"name": "key" | ||
} | ||
] | ||
}, | ||
"consequent": createDefinePropertyExpression( | ||
{ | ||
"type": "Identifier", | ||
"name": "target" | ||
}, | ||
{ | ||
"type": "Identifier", | ||
"name": "key" | ||
}, | ||
{ | ||
"type": "Identifier", | ||
"name": "value" | ||
}, | ||
), | ||
"alternate": { | ||
"type": "AssignmentExpression", | ||
"operator": "=", | ||
"left": { | ||
"type": "MemberExpression", | ||
"object": { | ||
"type": "Identifier", | ||
"name": "target" | ||
}, | ||
"property": { | ||
"type": "Identifier", | ||
"name": "key" | ||
}, | ||
"computed": true | ||
}, | ||
"right": { | ||
"type": "Identifier", | ||
"name": "value" | ||
}, | ||
"prototypePropDefineSkip": true | ||
} | ||
} | ||
}, | ||
{ | ||
"type": "ReturnStatement", | ||
"argument": { | ||
"type": "Identifier", | ||
"name": "value" | ||
} | ||
} | ||
], | ||
"directives": [] | ||
} | ||
}, | ||
"arguments": [ | ||
parentStatement, | ||
propertyKeyStatement, | ||
valueStatement, | ||
] | ||
} | ||
} | ||
} | ||
function createPrimordialKeyArray () { | ||
return { | ||
"type": "ArrayExpression", | ||
"elements": Array.from(primordialKeySet).map(key => { | ||
return { | ||
type: 'StringLiteral', | ||
value: key, | ||
} | ||
}) | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
32652
391