Socket
Socket
Sign inDemoInstall

babel-plugin-prototype-prop-define

Package Overview
Dependencies
1
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.2.1 to 2.3.0

2

package.json
{
"name": "babel-plugin-prototype-prop-define",
"version": "2.2.1",
"version": "2.3.0",
"description": "Transform assignments to properties on built-in prototypes to Object.defineProperty calls",

@@ -5,0 +5,0 @@ "main": "src/index.js",

@@ -13,3 +13,3 @@ <!-- START doctoc generated TOC please keep comment here to allow auto update -->

### background
### transformation

@@ -32,10 +32,43 @@ If your primordials are frozen, such as in [SES](https://github.com/agoric/ses), assigning keys that are found on the prototype will throw an error.

const x = {}
Object.defineProperty(x, 'toString', {
value: () => 'hello',
writable: true,
enumerable: true,
configurable: true,
})
(function (parent, key, value) {
Object.defineProperty(parent, key, {
value: value,
writable: true,
enumerable: true,
configurable: true
})
return value;
})(x, "toString", () => 'hello');
x.toString()
// => 'hello'
```
The code is transformed into an IIFE in order to ensure the "parent" (`x`), "key" (`y`) and "value" (`() => 'hello'`) statements are evaluated exactly once, and that the whole expression resolves to the value of the "value" statement. This is needed because `Object.defineProperty` calls resolve to `undefined`.
For "computed" assignment, the resulting code is a little uglier.
```js
const x = {};
const y = 'toString';
x[y] = () => 'hello'
```
becomes
```js
const x = {};
const y = 'toString';
(function (parent, key, value) {
["constructor", "__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__", "isPrototypeOf", "propertyIsEnumerable", "toString", "valueOf", "__proto__", "toLocaleString", "length", "concat", "find", "findIndex", "pop", "push", "shift", "unshift", "slice", "splice", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", "every", "some", "reduce", "reduceRight", "join", "reverse", "sort", "lastIndexOf", "copyWithin", "fill", "values", "name", "arguments", "caller", "apply", "bind", "call", "message"].includes(key) ? Object.defineProperty(parent, key, {
value: value,
writable: true,
enumerable: true,
configurable: true
}) : parent[key] = value;
return value;
})(x, y, () => true);
```
Here the check that is normally performed at parse time (checking if the key is in this whitelist), is performed at runtime to determine if normal assignment or `Object.defineProperty` should be used.

@@ -56,2 +56,4 @@ const primordialKeySet = new Set([

const SKIP_PARSE_FLAG = 'prototype-prop-define-skip'
module.exports = () =>

@@ -82,3 +84,3 @@ // {

// internal flag to skip node
if (node.prototypePropDefineSkip) return
if (node[SKIP_PARSE_FLAG]) return

@@ -137,3 +139,3 @@ // ensure basic assignment (not += etc)

const definePropertyExpression = createDefinePropertyExpression(
const definePropertyExpression = createDefinePropertyAndResolveExpression(
parentStatement,

@@ -151,3 +153,7 @@ propertyKeyStatement,

function createDefinePropertyExpression(
// (function(parent, key, value){
// Object.defineProperty(parent, key, value);
// return value
// })(a, b, c)
function createDefinePropertyAndResolveExpression (
parentStatement,

@@ -157,2 +163,29 @@ propertyKeyStatement,

) {
const body = [
createDefinePropertyExpression(
createIdentifier('parent'),
createIdentifier('key'),
createIdentifier('value'),
),
{
"type": "ReturnStatement",
"argument": createIdentifier('value')
}
]
const args = [
['parent', parentStatement],
['key', propertyKeyStatement],
['value', valueStatement],
]
return createIife (args, body)
}
// Object.defineProperty(parent, key, value)
function createDefinePropertyExpression (
parentStatement,
propertyKeyStatement,
valueStatement,
) {
return {

@@ -187,13 +220,10 @@ type: 'CallExpression',

// { value: 1, writable: true, enumerable: true, configurable: true }
function createPropertyDescriptor (valueStatement) {
return {
type: 'ObjectExpression',
// { value: 1, writable: true, enumerable: true, configurable: true }
properties: [
{
type: 'ObjectProperty',
key: {
type: 'Identifier',
name: 'value',
},
key: createIdentifier('value'),
value: valueStatement,

@@ -203,6 +233,3 @@ },

type: 'ObjectProperty',
key: {
type: 'Identifier',
name: 'writable',
},
key: createIdentifier('writable'),
value: {

@@ -215,6 +242,3 @@ type: 'BooleanLiteral',

type: 'ObjectProperty',
key: {
type: 'Identifier',
name: 'enumerable',
},
key: createIdentifier('enumerable'),
value: {

@@ -227,6 +251,3 @@ type: 'BooleanLiteral',

type: 'ObjectProperty',
key: {
type: 'Identifier',
name: 'configurable',
},
key: createIdentifier('configurable'),
value: {

@@ -241,9 +262,8 @@ type: 'BooleanLiteral',

// (function(target, key, value){
// (function(parent, key, value){
// [].includes(key) ?
// DEFINE_PROP :
// target[key] = value;
// Object.defineProperty(parent, key, value) :
// parent[key] = value;
// return value
// })(a, b, c)
function createDynamicAssignmentCheck (

@@ -254,2 +274,55 @@ parentStatement,

) {
const body = [
{
"type": "ExpressionStatement",
"expression": {
"type": "ConditionalExpression",
"test": {
"type": "CallExpression",
"callee": {
"type": "MemberExpression",
"object": createPrimordialKeyArray(),
"property": createIdentifier('includes'),
"computed": false
},
"arguments": [
createIdentifier('key'),
]
},
"consequent": createDefinePropertyExpression(
createIdentifier('parent'),
createIdentifier('key'),
createIdentifier('value'),
),
"alternate": {
"type": "AssignmentExpression",
// prevent this plugin from transforming
[SKIP_PARSE_FLAG]: true,
"operator": "=",
"left": {
"type": "MemberExpression",
"object": createIdentifier('parent'),
"property": createIdentifier('key'),
"computed": true
},
"right": createIdentifier('value')
}
}
},
{
"type": "ReturnStatement",
"argument": createIdentifier('value')
}
]
const args = [
['parent', parentStatement],
['key', propertyKeyStatement],
['value', valueStatement],
]
return createIife(args, body)
}
function createIife (args, body) {
return {

@@ -262,96 +335,11 @@ "type": "CallExpression",

"async": false,
"params": [
{
"type": "Identifier",
"name": "target"
},
{
"type": "Identifier",
"name": "key"
},
{
"type": "Identifier",
"name": "value"
}
],
"params": args.map(([argName]) => createIdentifier(argName)),
"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"
}
}
],
body,
"directives": []
}
},
"arguments": [
parentStatement,
propertyKeyStatement,
valueStatement,
]
"arguments": args.map(([_, argValue]) => argValue)
}
}

@@ -369,2 +357,9 @@

}
}
function createIdentifier (name) {
return {
"type": "Identifier",
name,
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc