Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

babel-plugin-idx

Package Overview
Dependencies
Maintainers
3
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

babel-plugin-idx - npm Package Compare versions

Comparing version 1.5.1 to 2.0.0

121

lib/babel-plugin-idx.js

@@ -38,2 +38,38 @@ /**

function checkIdxBindingNode(file, node) {
if (t.isImportDeclaration(node)) {
// E.g. `import '...'`
if (node.specifiers.length === 0) {
throw file.buildCodeFrameError(node, 'The idx import must have a value.');
}
// E.g. `import A, {B} from '...'`
// `import A, * as B from '...'`
// `import {A, B} from '...'`
if (node.specifiers.length > 1) {
throw file.buildCodeFrameError(node.specifiers[1], 'The idx import must be a single specifier.');
}
// `import {default as idx} from '...'` or `import idx from '...'` are ok.
// `import idx, * as idx2 from '...'` is not ok but would've been caught
// above.
if (!t.isSpecifierDefault(node.specifiers[0])) {
throw file.buildCodeFrameError(node.specifiers[0], 'The idx import must be a default import.');
}
// `importKind` is not a property unless flow syntax is enabled.
// On specifiers, `importKind` is not "value" when it's not a type, it's
// `null`.
// E.g. `import type {...} from '...'`
// `import typeof {...} from '...'`
// `import {type ...} from '...'`.
// `import {typeof ...} from '...'`
if (node.importKind === 'type' || node.importKind === 'typeof' || node.specifiers[0].importKind === 'type' || node.specifiers[0].importKind === 'typeof') {
throw file.buildCodeFrameError(node, 'The idx import must be a value import.');
}
} else if (t.isVariableDeclarator(node)) {
// E.g. var {idx} or var [idx]
if (!t.isIdentifier(node.id)) {
throw file.buildCodeFrameError(node.specifiers[0], 'The idx declaration must be an identifier.');
}
}
}
function makeCondition(node, state, inside) {

@@ -48,5 +84,3 @@ if (inside) {

function makeChain(node, state, inside) {
if (t.isCallExpression(node)) {
return makeChain(node.callee, state, makeCondition(t.CallExpression(state.temp, node.arguments), state, inside));
} else if (t.isMemberExpression(node)) {
if (t.isMemberExpression(node)) {
return makeChain(node.object, state, makeCondition(t.MemberExpression(state.temp, node.property, node.computed), state, inside));

@@ -59,21 +93,66 @@ } else if (t.isIdentifier(node)) {

} else {
throw state.file.buildCodeFrameError(node, 'The `idx` body can only be composed of properties and methods.');
throw state.file.buildCodeFrameError(node, 'idx callbacks may only access properties on the callback parameter.');
}
}
var idxVisitor = {
CallExpression: function CallExpression(path, state) {
var node = path.node;
if (t.isIdentifier(node.callee) && node.callee.name === 'idx') {
checkIdxArguments(state.file, node);
var temp = path.scope.generateUidIdentifier('ref');
var replacement = makeChain(node.arguments[1].body, {
file: state.file,
input: node.arguments[0],
base: node.arguments[1].params[0],
temp: temp
});
path.replaceWith(replacement);
path.scope.push({ id: temp });
function visitIdxCallExpression(path, state) {
var node = path.node;
checkIdxArguments(state.file, node);
var temp = path.scope.generateUidIdentifier('ref');
var replacement = makeChain(node.arguments[1].body, {
file: state.file,
input: node.arguments[0],
base: node.arguments[1].params[0],
temp: temp
});
path.replaceWith(replacement);
// Hoist to the top if it's an async method.
if (path.scope.path.isClassMethod({ async: true })) {
path.scope.push({ id: temp, _blockHoist: 3 });
} else {
path.scope.push({ id: temp });
}
}
function isIdxImportOrRequire(node, name) {
if (t.isImportDeclaration(node)) {
return t.isStringLiteral(node.source, { value: name });
} else if (t.isVariableDeclarator(node)) {
return t.isCallExpression(node.init) && t.isIdentifier(node.init.callee, { name: 'require' }) && t.isLiteral(node.init.arguments[0], { value: name });
} else {
return false;
}
}
var declareVisitor = {
'ImportDeclaration|VariableDeclarator': function ImportDeclarationVariableDeclarator(path, state) {
if (!isIdxImportOrRequire(path.node, state.importName)) {
return;
}
checkIdxBindingNode(state.file, path.node);
var bindingName = t.isImportDeclaration(path.node) ? path.node.specifiers[0].local.name : path.node.id.name;
var idxBinding = path.scope.getOwnBinding(bindingName);
idxBinding.constantViolations.forEach(function (refPath) {
throw state.file.buildCodeFrameError(refPath.node, '`idx` cannot be redefined.');
});
var didTransform = false;
var didSkip = false;
idxBinding.referencePaths.forEach(function (refPath) {
if (refPath.node === idxBinding.node) {
// Do nothing...
} else if (refPath.parentPath.isCallExpression()) {
visitIdxCallExpression(refPath.parentPath, state);
didTransform = true;
} else {
// Should this throw?
didSkip = true;
}
});
if (didTransform && !didSkip) {
path.remove();
}
}

@@ -85,4 +164,5 @@ };

Program: function Program(path, state) {
var importName = state.opts.importName || 'idx';
// If there can't reasonably be an idx call, exit fast.
if (path.scope.getOwnBinding('idx') || idxRe.test(state.file.code)) {
if (importName !== 'idx' || idxRe.test(state.file.code)) {
// We're very strict about the shape of idx. Some transforms, like

@@ -92,3 +172,4 @@ // "babel-plugin-transform-async-to-generator", will convert arrow

// our transformation before any one else interferes.
path.traverse(idxVisitor, state);
var newState = { file: state.file, importName: importName };
path.traverse(declareVisitor, newState);
}

@@ -95,0 +176,0 @@ }

2

package.json
{
"name": "babel-plugin-idx",
"version": "1.5.1",
"version": "2.0.0",
"description": "Babel plugin for transforming the idx utility function.",

@@ -5,0 +5,0 @@ "main": "lib/babel-plugin-idx.js",

@@ -11,6 +11,6 @@ # idx [![Circle Status](https://circleci.com/gh/facebookincubator/idx/tree/master.svg?style=shield&circle-token=da61f3cf105f22309c8ca0ba4482daa538bf5349)](https://circleci.com/gh/facebookincubator/idx)

Consider the following type:
Consider the following type for `props`:
```javascript
const props: {
type User = {
user: ?{

@@ -41,2 +41,16 @@ name: string,

## Flow Type
[Flow](https://flow.org/) understands the `idx` idiom:
```javascript
// @flow
import idx from 'idx';
function getName(props: User): ?string {
return idx(props, _ => _.user.name);
}
```
## Babel Transform

@@ -46,11 +60,41 @@

behavior and is not meant to be executed. The `idx` function is used in
conjunction with a Babel plugin that replaces it with better performing code:
conjunction with a Babel plugin that replaces it with better performing code.
This babel plugin searches for requires or imports to the `idx` module and
replaces all its usages, so this code:
```javascript
props.user == null ? props.user :
props.user.friends == null ? props.user.friends :
props.user.friends[0] == null ? props.user.friends[0] :
props.user.friends[0].friends
import idx from 'idx';
function getFriends() {
return idx(props, _ => _.user.friends[0].friends)
};
```
gets transformed to something like:
```javascript
function getFriends() {
props.user == null ? props.user :
props.user.friends == null ? props.user.friends :
props.user.friends[0] == null ? props.user.friends[0] :
return props.user.friends[0].friends
}
```
(note that the original `import` gets also removed).
It's possible to customize the name of the import/require, so code that is not
directly requiring the `idx` npm package can also get transformed:
```javascript
{
plugins: [
["babel-plugin-idx", {
importName: './idx',
}]
]
}
```
All this machinery exists due to the fact that an existential operator does not

@@ -57,0 +101,0 @@ currently exist in JavaScript.

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc