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

babel-plugin-transform-flow-to-gen

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

babel-plugin-transform-flow-to-gen - npm Package Compare versions

Comparing version 0.0.13 to 0.0.14-0

98

lib/plugin.js

@@ -17,9 +17,4 @@ 'use strict';

var isTopLevelExport = function isTopLevelExport(path) {
return !!(t.isExportDefaultDeclaration(path.parentPath) || t.isExportNamedDeclaration(path.parentPath) || t.isVariableDeclarator(path.parentPath) && t.isVariableDeclaration(path.parentPath.parentPath) && isTopLevelExport(path.parentPath.parentPath));
};
var walkToRoot = function walkToRoot(path) {
while (!t.isProgram(path.parentPath)) {
// eslint-disable-next-line no-param-reassign
var walkToScope = function walkToScope(path) {
while (!t.SCOPABLE_TYPES.includes(path.parentPath.type)) {
path = path.parentPath;

@@ -31,2 +26,8 @@ }

var nameCount = 0;
var nextName = function nextName() {
nameCount += 1;
return _GEN_ID2.default + '_EXP_' + nameCount + '__';
};
return {

@@ -37,16 +38,17 @@ inherits: require('babel-plugin-syntax-flow'),

ImportDeclaration: function ImportDeclaration(path) {
if (path.node.importKind === 'type') {
// eslint-disable-next-line no-param-reassign
path.node.importKind = 'value';
var node = path.node;
if (node.importKind === 'type') {
node.importKind = 'value';
}
},
ExportNamedDeclaration: function ExportNamedDeclaration(path) {
if (path.node.exportKind === 'type') {
var _path$node = path.node,
declaration = _path$node.declaration,
specifiers = _path$node.specifiers;
var node = path.node;
if (node.exportKind === 'type') {
var declaration = node.declaration;
path.node.exportKind = 'value';
node.exportKind = 'value';
if (declaration) {

@@ -65,3 +67,2 @@ var namedExport = {

var node = path.node;
var ast = (0, _transformType2.default)(node.id.name, node.right, node.typeParameters);

@@ -71,25 +72,58 @@ path.replaceWithMultiple(ast);

FunctionDeclaration: function FunctionDeclaration(path) {
if (allParamsAreTyped(path.node) && isTopLevelExport(path)) {
var name = path.node.id.name;
var fn = (0, _transformFunction2.default)(name, path.node.params, path.node.typeParameters);
var root = walkToRoot(path);
root.insertAfter(fn);
var node = path.node;
if (!allParamsAreTyped(node)) {
return;
}
var name = node.id.name;
var fn = (0, _transformFunction2.default)(name, node.params, node.typeParameters);
var root = walkToScope(path);
var nodes = [root.node].concat(fn);
root.replaceWithMultiple(nodes);
},
FunctionExpression: function FunctionExpression(path) {
if (allParamsAreTyped(path.node) && isTopLevelExport(path) && t.isVariableDeclarator(path.parentPath)) {
var node = path.node;
if (!allParamsAreTyped(node)) {
return;
}
if (t.isVariableDeclarator(path.parentPath)) {
var name = path.parentPath.node.id.name;
var fn = (0, _transformFunction2.default)(name, path.node.params, path.node.typeParameters);
var root = walkToRoot(path);
root.insertAfter(fn);
var fn = (0, _transformFunction2.default)(name, node.params, node.typeParameters);
var root = walkToScope(path);
var nodes = [root.node].concat(fn);
root.replaceWithMultiple(nodes);
}
if (t.isReturnStatement(path.parentPath)) {
node.id = node.id || t.identifier(nextName());
var _name = node.id.name;
var _fn = (0, _transformFunction2.default)(_name, node.params, node.typeParameters);
var _root = path.parentPath;
var _nodes = [node].concat(_fn).concat(t.returnStatement(t.identifier(_name)));
_root.replaceWithMultiple(_nodes);
}
},
// just transform to function expression to avoid dealing with more AST semantics
ArrowFunctionExpression: function ArrowFunctionExpression(path) {
if (allParamsAreTyped(path.node) && isTopLevelExport(path) && !t.isCallExpression(path.parentPath)) {
var name = path.parentPath.node.id.name;
var fn = (0, _transformFunction2.default)(name, path.node.params, path.node.typeParameters);
var root = walkToRoot(path);
root.insertAfter(fn);
var node = path.node;
var id = t.identifier(nextName());
var params = node.params;
var body = node.body;
if (!t.isBlockStatement(body)) {
body = t.blockStatement([t.returnStatement(body)]);
}
var exp = t.functionExpression(id, params, body);
exp.typeParameters = node.typeParameters;
path.replaceWith(exp);
}

@@ -100,2 +134,6 @@ }

var _GEN_ID = require('./GEN_ID');
var _GEN_ID2 = _interopRequireDefault(_GEN_ID);
var _transformType = require('./transformType');

@@ -102,0 +140,0 @@

@@ -1,2 +0,2 @@

'use strict';
"use strict";

@@ -17,15 +17,15 @@ Object.defineProperty(exports, "__esModule", {

Array: function Array(params) {
return { type: 'array', elementType: params[0] };
return { type: "array", elementType: params[0] };
},
Object: function Object(params) {
return { type: 'object', members: {}, indexers: [] };
Object: function Object() {
return { type: "object", members: {}, indexers: [] };
},
$Gen: function $Gen(params) {
return { type: 'generator', typeAlias: params[0], caller: params[1].name };
return { type: "generator", typeAlias: params[0], caller: params[1].name };
},
$Keys: function $Keys(params) {
return { type: 'typeAliasKeys', typeAlias: params[0] };
return { type: "typeAliasKeys", typeAlias: params[0] };
},
$Shape: function $Shape(params) {
return { type: 'typeAliasShape', typeAlias: params[0] };
return { type: "typeAliasShape", typeAlias: params[0] };
},

@@ -40,7 +40,7 @@ $Subtype: function $Subtype(params) {

var type = path.type.replace('TypeAnnotation', '').toLowerCase();
var type = path.type.replace("TypeAnnotation", "").toLowerCase();
var base = { type: type, optional: optional };
switch (type) {
case 'generic':
case "generic":
{

@@ -55,9 +55,9 @@ var typeParameters = path.typeParameters;

if (Boolean(SPECIAL_GENERICS[name])) {
if (SPECIAL_GENERICS[name]) {
return _extends({}, SPECIAL_GENERICS[name](args), { optional: optional });
} else {
return { type: 'typeAlias', optional: optional, name: name, args: args };
}
return { type: "typeAlias", optional: optional, name: name, args: args };
}
case 'object':
case "object":
{

@@ -72,3 +72,3 @@ var members = path.properties.reduce(function (acc, prop) {

var indexers = path.indexers.reduce(function (acc, index) {
if (index.id.name !== 'key') {
if (index.id.name !== "key") {
return acc;

@@ -90,21 +90,21 @@ }

}
case 'array':
case "array":
return _extends({}, base, { elementType: typeAST(path.elementType) });
case 'nullliteral':
return { type: 'literal', optional: optional, value: null };
case 'booleanliteral':
case 'numericliteral':
case 'stringliteral':
return { type: 'literal', optional: optional, value: path.value };
case 'intersection':
case 'tuple':
case 'union':
case "nullliteral":
return { type: "literal", optional: optional, value: null };
case "booleanliteral":
case "numericliteral":
case "stringliteral":
return { type: "literal", optional: optional, value: path.value };
case "intersection":
case "tuple":
case "union":
return _extends({}, base, { entries: path.types.map(function (p) {
return typeAST(p);
}) });
case 'nullable':
case "nullable":
return _extends({}, base, { value: typeAST(path.typeAnnotation) });
case 'any':
case 'mixed':
return { type: 'garbage', optional: optional };
case "any":
case "mixed":
return { type: "garbage", optional: optional };
// case `void`:

@@ -111,0 +111,0 @@ // case `function`:

{
"name": "babel-plugin-transform-flow-to-gen",
"version": "0.0.13",
"version": "0.0.14-0",
"description": "Turn flow definitions into generator functions",

@@ -10,3 +10,5 @@ "main": "lib/index.js",

"test": "jest",
"test:watch": "DEBUG=1 npm run test -- --watchAll --noCache",
"lint": "eslint --fix --ext .js src/",
"precommit": "npm run test && npm run lint",
"prepublish": "rm -rf lib && babel src --out-dir lib --ignore __test__,test.js",

@@ -18,3 +20,2 @@ "postpublish": "rm -rf lib",

"babel-plugin-syntax-flow": "^6.18.0",
"eslint-plugin-flowtype": "^2.29.2",
"testcheck": "^0.1.4"

@@ -34,5 +35,9 @@ },

"eslint-config-airbnb-base": "^11.0.0",
"eslint-plugin-flowtype": "^2.29.2",
"eslint-plugin-import": "^2.2.0",
"husky": "^0.13.2",
"jest": "^18.1.0",
"np": "^2.12.0"
"np": "^2.12.0",
"prettier": "^0.22.0",
"prettier-eslint": "^4.3.2"
},

@@ -59,5 +64,14 @@ "babel": {

"env": {
"node": true,
"browser": true,
"jest": true
},
"prettierOptions": {
"singleQuote": true,
"brackSpacing": false,
"trailingComma": "all",
"parser": "flow",
"printWidth": 100,
"write": "**/*.js"
},
"rules": {

@@ -64,0 +78,0 @@ "arrow-parens": [

# Flow to gen
_Transforms flow type aliases into generators for property based testing_
_Transforms Flow annotations into TestCheck generators for randomized testing_
## Motivation
This Babel plugin attempts to alleviate the manual task of creating and maintaining fixtures/mocks by transforming all Flowtype type aliases
into generator functions for mock data. Additionally, it provides a framework for automatically generating random input for
typed functions and React components. If you're unfamiliar with generative or property based testing, please check out an implementation of
[Quickcheck](https://en.wikipedia.org/wiki/QuickCheck) in your language of choice. Also look at
[testcheck.js](https://github.com/leebyron/testcheck-js) which is 100% compatible and wrapped by the runtime of this library.
Read [this blog post](https://medium.com/@gabescholz/randomized-testing-in-javascript-without-lifting-a-finger-8d616d7048af)
By running this Babel transform on your code:
- all type aliases are transformed in testcheck.js generators
- all typed functions can immediately retrieve randomly generated inputs
- all typed React components can immediately retrieve randomly generated props
TODO:
- handle TypeofTypeAnnotation
- handle ExistentialTypeAnnotation
- handle recursive types
- handle Flow globally defined types
- handle React components
## Demo?

@@ -29,65 +13,27 @@

## Getting Started
## Installing
`babel-plugin-transform-flow-to-gen` transforms your type aliases into functions
that create testcheck.js generators.
## Usage
```js
import {sample, types} from 'babel-plugin-transform-flow-to-gen/api';
yarn add babel-plugin-transform-flow-to-gen
```
type Person<T> = {
firstName: string,
lastName: string,
age: T
}
and add it to your `.babelrc`
// use the generator static member to create samples
const personGen = Person(types.number());
sample(personGen, 20);
// [{
// "firstName": "9OY3o",
// "lastName": "fB",
// "age": 0
// },
// {
// "firstName": "8Hft5LwfK",
// "lastName": "51Vnn54vb9xHO",
// "age": 2
// },
// {
// "firstName": "7i59Sr35GAJiv626uiV",
// "lastName": "s7GIgEf",
// "age": 3
// },
// {
// "firstName": "Mys89F65i36n921",
// "lastName": "",
// "age": 1
// }, ...]
function setFirstName(person: Person<number>, firstName: string) {
// ...
```json
{
"presets": ["es-2015"],
"plugins": ["syntax-flow"],
"env": {
"development": {
"plugins": ["strip-flow-types"]
},
"test": {
"plugins": ["flow-to-gen", "strip-flow-types"]
}
}
}
// returns an array of args for setFirstName
sample(setFirstName.asGenerator());
// [
// [{
// "firstName": "3o",
// "lastName": "j467DA",
// "age": 0
// }, "f02j"]
// , ...]
```
## Installing
```js
yarn add babel-plugin-transform-flow-to-gen
```
## License
MIT
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