parse-function
Advanced tools
Comparing version 5.4.1 to 5.4.2
@@ -6,2 +6,13 @@ # Change Log | ||
## [5.4.2](https://github.com/tunnckoCore/opensource/compare/parse-function@5.4.1...parse-function@5.4.2) (2019-10-22) | ||
### Bug Fixes | ||
* update errors in parse-function, run docs+fmt ([667c253](https://github.com/tunnckoCore/opensource/commit/667c2539f668bfe07659ea397d9dda1305b7da4e)) | ||
## [5.4.1](https://github.com/tunnckoCore/opensource/compare/parse-function@5.4.0...parse-function@5.4.1) (2019-10-22) | ||
@@ -8,0 +19,0 @@ |
@@ -28,3 +28,2 @@ 'use strict'; | ||
const utils = {}; | ||
utils.define = typeof Reflect !== 'undefined' ? Reflect.defineProperty : Object.defineProperty; | ||
utils.arrayify = arrify_1; | ||
@@ -52,11 +51,11 @@ | ||
utils.setHiddenDefaults = function setHiddenDefaults(result, code) { | ||
utils.define(result, 'defaults', {}); | ||
utils.define(result, 'value', code); | ||
utils.define(result, 'isValid', code.length > 0); | ||
utils.define(result, 'isArrow', false); | ||
utils.define(result, 'isAsync', false); | ||
utils.define(result, 'isNamed', false); | ||
utils.define(result, 'isAnonymous', false); | ||
utils.define(result, 'isGenerator', false); | ||
utils.define(result, 'isExpression', false); | ||
result.defaults = {}; | ||
result.value = code; | ||
result.isValid = code.length > 0; | ||
result.isArrow = false; | ||
result.isAsync = false; | ||
result.isNamed = false; | ||
result.isAnonymous = false; | ||
result.isGenerator = false; | ||
result.isExpression = false; | ||
return result; | ||
@@ -88,9 +87,9 @@ }; | ||
const props = (app => (node, result) => { | ||
app.define(result, 'isArrow', node.type.startsWith('Arrow')); | ||
app.define(result, 'isAsync', node.async || false); | ||
app.define(result, 'isGenerator', node.generator || false); | ||
app.define(result, 'isExpression', node.expression || false); | ||
app.define(result, 'isAnonymous', node.id === null); | ||
app.define(result, 'isNamed', !result.isAnonymous); | ||
const props = (() => (node, result) => { | ||
result.isArrow = node.type.startsWith('Arrow'); | ||
result.isAsync = node.async || false; | ||
result.isGenerator = node.generator || false; | ||
result.isExpression = node.expression || false; | ||
result.isAnonymous = node.id === null; | ||
result.isNamed = !result.isAnonymous; | ||
result.name = result.isAnonymous ? null : node.id.name; | ||
@@ -135,3 +134,3 @@ return result; | ||
result = props(app)(node, result); | ||
result = props()(node, result); | ||
result = params()(node, result); | ||
@@ -143,3 +142,3 @@ result = body()(node, result); | ||
function parseFunction(opts = {}) { | ||
const plugins = [...fakeChange]; | ||
const plugins = []; | ||
const app = { | ||
@@ -146,0 +145,0 @@ parse(code, options) { |
@@ -26,3 +26,2 @@ import { parseExpression } from '@babel/parser'; | ||
const utils = {}; | ||
utils.define = typeof Reflect !== 'undefined' ? Reflect.defineProperty : Object.defineProperty; | ||
utils.arrayify = arrify_1; | ||
@@ -50,11 +49,11 @@ | ||
utils.setHiddenDefaults = function setHiddenDefaults(result, code) { | ||
utils.define(result, 'defaults', {}); | ||
utils.define(result, 'value', code); | ||
utils.define(result, 'isValid', code.length > 0); | ||
utils.define(result, 'isArrow', false); | ||
utils.define(result, 'isAsync', false); | ||
utils.define(result, 'isNamed', false); | ||
utils.define(result, 'isAnonymous', false); | ||
utils.define(result, 'isGenerator', false); | ||
utils.define(result, 'isExpression', false); | ||
result.defaults = {}; | ||
result.value = code; | ||
result.isValid = code.length > 0; | ||
result.isArrow = false; | ||
result.isAsync = false; | ||
result.isNamed = false; | ||
result.isAnonymous = false; | ||
result.isGenerator = false; | ||
result.isExpression = false; | ||
return result; | ||
@@ -86,9 +85,9 @@ }; | ||
const props = (app => (node, result) => { | ||
app.define(result, 'isArrow', node.type.startsWith('Arrow')); | ||
app.define(result, 'isAsync', node.async || false); | ||
app.define(result, 'isGenerator', node.generator || false); | ||
app.define(result, 'isExpression', node.expression || false); | ||
app.define(result, 'isAnonymous', node.id === null); | ||
app.define(result, 'isNamed', !result.isAnonymous); | ||
const props = (() => (node, result) => { | ||
result.isArrow = node.type.startsWith('Arrow'); | ||
result.isAsync = node.async || false; | ||
result.isGenerator = node.generator || false; | ||
result.isExpression = node.expression || false; | ||
result.isAnonymous = node.id === null; | ||
result.isNamed = !result.isAnonymous; | ||
result.name = result.isAnonymous ? null : node.id.name; | ||
@@ -133,3 +132,3 @@ return result; | ||
result = props(app)(node, result); | ||
result = props()(node, result); | ||
result = params()(node, result); | ||
@@ -141,3 +140,3 @@ result = body()(node, result); | ||
function parseFunction(opts = {}) { | ||
const plugins = [...fakeChange]; | ||
const plugins = []; | ||
const app = { | ||
@@ -144,0 +143,0 @@ parse(code, options) { |
{ | ||
"name": "parse-function", | ||
"version": "5.4.1", | ||
"version": "5.4.2", | ||
"description": "Parse a function into an object using espree, acorn or babylon parsers. Extensible through Smart Plugins", | ||
@@ -64,2 +64,12 @@ "repository": { | ||
}, | ||
"jest": { | ||
"coverageThreshold": { | ||
"src/**/*.js": { | ||
"statements": 100, | ||
"branches": 100, | ||
"functions": 100, | ||
"lines": 100 | ||
} | ||
} | ||
}, | ||
"licenseStart": 2016, | ||
@@ -91,13 +101,3 @@ "verb": { | ||
}, | ||
"jest": { | ||
"coverageThreshold": { | ||
"src/**/*.js": { | ||
"statements": 100, | ||
"branches": 100, | ||
"functions": 100, | ||
"lines": 100 | ||
} | ||
} | ||
}, | ||
"gitHead": "6c19103482bd5eeabc6d9c8ca7cc12cf3ea21d07" | ||
"gitHead": "13bc1e024e35fce9f89c1b027ec05d01a5cba5af" | ||
} |
366
README.md
@@ -55,29 +55,7 @@ # parse-function [![npm version][npmv-img]][npmv-url] [![License][license-img]][license-url] | ||
## Features | ||
() => include(process.cwd() + '/.verb.head.md') | ||
- **Always up-to-date:** auto-publish new version when new version of dependency is out, [Renovate](https://renovateapp.com) | ||
- **Standard:** using StandardJS, Prettier, SemVer, Semantic Release and conventional commits | ||
- **Smart Plugins:** for extending the core API or the end [Result](#result), see [.use](#use) method and [Plugins Architecture](#plugins-architecture) | ||
- **Extensible:** using plugins for working directly on AST nodes, see the [Plugins Architecture](#plugins-architecture) | ||
- **ES2020+ Ready:** by using `.parseExpression` method of the Babel `v7.x` parser | ||
- **Customization:** allows switching the parser, through `options.parse` | ||
- **Support for:** arrow functions, default parameters, generators and async/await functions | ||
- **Stable:** battle-tested in production and against all parsers - [espree][], [acorn][], [@babel/parser](https://npmjs.com/packages/@babel/parser) | ||
- **Tested:** with [450+ tests](./test/index.js) for _200%_ coverage | ||
## Table of Contents | ||
- [Install](#install) | ||
- [Which version to use?](#which-version-to-use) | ||
- [Notes](#notes) | ||
- [Throws in one specific case](#throws-in-one-specific-case) | ||
- [Function named _"anonymous"_](#function-named-_anonymous_) | ||
- [Real anonymous function](#real-anonymous-function) | ||
- [Plugins Architecture](#plugins-architecture) | ||
- [API](#api) | ||
- [parseFunction](#parsefunction) | ||
- [.parse](#parse) | ||
- [.use](#use) | ||
- [.define](#define) | ||
- [Result](#result) | ||
- [Contributing](#contributing) | ||
@@ -102,342 +80,6 @@ - [Guides and Community](#guides-and-community) | ||
## Which version to use? | ||
() => include(process.cwd() + '/.verb.md') | ||
There's no breaking changes between the `v2.x` version. The only breaking is `v2.1` which also is not | ||
working properly, so no use it. | ||
**Use v2.0.x** | ||
When you don't need support for `arrow functions` and `es6 default params`. This version | ||
uses a RegExp expression to work. | ||
**Use v2.2.x** | ||
Only when you need a _basic_ support for `es6 features` like arrow functions. This version | ||
uses a RegExp expression to work. | ||
**Use v2.3.x** | ||
When you want _full\*_ support for `arrow functions` and `es6 default params`. Where this "full", | ||
means "almost full", because it has bugs. This version also uses (`acorn.parse`) real parser | ||
to do the parsing. | ||
**Use v3.x** | ||
When you want to use different parser instead of the default `babylon.parse`, by passing custom | ||
parse function to the `options.parse` option. **From this version we require `node >= 4`**. | ||
**Use v4.x** | ||
When you want full customization and most stable support for old and modern features. This version | ||
uses `babylon.parseExpression` for parsing and provides a [Plugins API](#plugins-architecture). | ||
See the [Features](#features) section for more info. | ||
**Use v5.x** | ||
It is basically the same as `v4`, but requires Node 6 & npm 5. Another is boilerplate stuff. | ||
**[back to top](#readme)** | ||
## Notes | ||
### Throws in one specific case | ||
> _see: [issue #3](https://github.com/tunnckoCore/parse-function/issues/3) and [test/index.js#L229-L235](https://github.com/tunnckoCore/parse-function/blob/master/test/index.js#L229-L235)_ | ||
It may throw in one specific case, otherwise it won't throw, so you should | ||
relay on the `result.isValid` for sure. | ||
### Function named _"anonymous"_ | ||
> _see: [test/index.js#L319-L324](https://github.com/tunnckoCore/parse-function/blob/master/test/index.js#L319-L324) and [Result](#result) section_ | ||
If you pass a function which is named _"anonymous"_ the `result.name` will be `'anonymous'`, | ||
but the `result.isAnonymous` will be `false` and `result.isNamed` will be `true`, because | ||
in fact it's a named function. | ||
### Real anonymous function | ||
> _see: [test/index.js#L326-L331](https://github.com/tunnckoCore/parse-function/blob/master/test/index.js#L326-L331) and [Result](#result) section_ | ||
Only if you pass really an anonymous function you will get `result.name` equal to `null`, | ||
`result.isAnonymous` equal to `true` and `result.isNamed` equal to `false`. | ||
**[back to top](#readme)** | ||
### Plugins Architecture | ||
> _see: the [.use](#use) method, [test/index.js#L305-L317](https://github.com/tunnckoCore/parse-function/blob/master/test/index.js#L305-L317) and [test/index.js#L396-L414](https://github.com/tunnckoCore/parse-function/blob/master/test/index.js#L396-L414)_ | ||
A more human description of the plugin mechanism. Plugins are **synchronous** - no support | ||
and no need for **async** plugins here, but notice that you can do that manually, because | ||
that exact architecture. | ||
The first function that is passed to the [.use](#use) method is used for extending the core API, | ||
for example adding a new method to the `app` instance. That function is immediately invoked. | ||
```js | ||
const parseFunction = require('parse-function'); | ||
const app = parseFunction(); | ||
app.use((self) => { | ||
// self is same as `app` | ||
console.log(self.use); | ||
console.log(self.parse); | ||
console.log(self.define); | ||
self.define(self, 'foo', (bar) => bar + 1); | ||
}); | ||
console.log(app.foo(2)); // => 3 | ||
``` | ||
On the other side, if you want to access the AST of the parser, you should return a function | ||
from that plugin, which function is passed with `(node, result)` signature. | ||
This function is lazy plugin, it is called only when the [.parse](#parse) method is called. | ||
```js | ||
const parseFunction = require('parse-function'); | ||
const app = parseFunction(); | ||
app.use((self) => { | ||
console.log('immediately called'); | ||
return (node, result) => { | ||
console.log('called only when .parse is invoked'); | ||
console.log(node); | ||
console.log(result); | ||
}; | ||
}); | ||
``` | ||
Where **1)** the `node` argument is an object - actual and real AST Node coming from the parser | ||
and **2)** the `result` is an object too - the end [Result](#result), on which | ||
you can add more properties if you want. | ||
**[back to top](#readme)** | ||
<!-- docks-start --> | ||
## API | ||
_Generated using [jest-runner-docs](https://npmjs.com/package/jest-runner-docs)._ | ||
### [parseFunction](./src/index.js#L52) | ||
> Initializes with optional `opts` object which is passed directly | ||
> to the desired parser and returns an object | ||
> with `.use` and `.parse` methods. The default parse which | ||
> is used is [babylon][]'s `.parseExpression` method from `v7`. | ||
**Signature** | ||
```ts | ||
function(opts) | ||
``` | ||
**Params** | ||
- `opts` - optional, merged with options passed to `.parse` method | ||
- `returns` - app object with `.use` and `.parse` methods | ||
**Example** | ||
```js | ||
const parseFunction = require('parse-function'); | ||
const app = parseFunction({ | ||
ecmaVersion: 2017, | ||
}); | ||
const fixtureFn = (a, b, c) => { | ||
a = b + c; | ||
return a + 2; | ||
}; | ||
const result = app.parse(fixtureFn); | ||
console.log(result); | ||
// see more | ||
console.log(result.name); // => null | ||
console.log(result.isNamed); // => false | ||
console.log(result.isArrow); // => true | ||
console.log(result.isAnonymous); // => true | ||
// array of names of the arguments | ||
console.log(result.args); // => ['a', 'b', 'c'] | ||
// comma-separated names of the arguments | ||
console.log(result.params); // => 'a, b, c' | ||
``` | ||
### [.parse](./src/index.js#L117) | ||
> Parse a given `code` and returns a `result` object | ||
> with useful properties - such as `name`, `body` and `args`. | ||
> By default it uses Babylon parser, but you can switch it by | ||
> passing `options.parse` - for example `options.parse: acorn.parse`. | ||
> In the below example will show how to use `acorn` parser, instead | ||
> of the default one. | ||
**Params** | ||
- `code` - any kind of function or string to be parsed | ||
- `options` - directly passed to the parser babylon, acorn, espree | ||
- `options.parse` - by default `babylon.parseExpression`, | ||
all `options` are passed as second argument | ||
- `returns` - result see [result section](#result) for more info | ||
**Example** | ||
```js | ||
const acorn = require('acorn'); | ||
const parseFn = require('parse-function'); | ||
const app = parseFn(); | ||
const fn = function foo(bar, baz) { | ||
return bar * baz; | ||
}; | ||
const result = app.parse(fn, { | ||
parse: acorn.parse, | ||
ecmaVersion: 2017, | ||
}); | ||
console.log(result.name); // => 'foo' | ||
console.log(result.args); // => ['bar', 'baz'] | ||
console.log(result.body); // => ' return bar * baz ' | ||
console.log(result.isNamed); // => true | ||
console.log(result.isArrow); // => false | ||
console.log(result.isAnonymous); // => false | ||
console.log(result.isGenerator); // => false | ||
``` | ||
### [.use](./src/index.js#L170) | ||
> Add a plugin `fn` function for extending the API or working on the | ||
> AST nodes. The `fn` is immediately invoked and passed | ||
> with `app` argument which is instance of `parseFunction()` call. | ||
> That `fn` may return another function that | ||
> accepts `(node, result)` signature, where `node` is an AST node | ||
> and `result` is an object which will be returned [result](#result) | ||
> from the `.parse` method. This retuned function is called on each | ||
> node only when `.parse` method is called. | ||
**Params** | ||
- `fn` - plugin to be called | ||
- `returns` - app instance for chaining | ||
_See [Plugins Architecture](#plugins-architecture) section._ | ||
**Example** | ||
```js | ||
// plugin extending the `app` | ||
app.use((app) => { | ||
app.define(app, 'hello', (place) => `Hello ${place}!`); | ||
}); | ||
const hi = app.hello('World'); | ||
console.log(hi); // => 'Hello World!' | ||
// or plugin that works on AST nodes | ||
app.use((app) => (node, result) => { | ||
if (node.type === 'ArrowFunctionExpression') { | ||
result.thatIsArrow = true; | ||
} | ||
return result; | ||
}); | ||
const result = app.parse((a, b) => a + b + 123); | ||
console.log(result.name); // => null | ||
console.log(result.isArrow); // => true | ||
console.log(result.thatIsArrow); // => true | ||
const result = app.parse(function foo() { | ||
return 123; | ||
}); | ||
console.log(result.name); // => 'foo' | ||
console.log(result.isArrow); // => false | ||
console.log(result.thatIsArrow); // => undefined | ||
``` | ||
### [.define](./src/index.js#L228) | ||
> Define a non-enumerable property on an object. Just | ||
> a convenience mirror of the [define-property][] library, | ||
> so check out its docs. Useful to be used in plugins. | ||
**Params** | ||
- `obj` - the object on which to define the property | ||
- `prop` - the name of the property to be defined or modified | ||
- `val` - the descriptor for the property being defined or modified | ||
- `returns` - obj the passed object, but modified | ||
**Example** | ||
```js | ||
const parseFunction = require('parse-function'); | ||
const app = parseFunction(); | ||
// use it like `define-property` lib | ||
const obj = {}; | ||
app.define(obj, 'hi', 'world'); | ||
console.log(obj); // => { hi: 'world' } | ||
// or define a custom plugin that adds `.foo` property | ||
// to the end result, returned from `app.parse` | ||
app.use((app) => { | ||
return (node, result) => { | ||
// this function is called | ||
// only when `.parse` is called | ||
app.define(result, 'foo', 123); | ||
return result; | ||
}; | ||
}); | ||
// fixture function to be parsed | ||
const asyncFn = async (qux) => { | ||
const bar = await Promise.resolve(qux); | ||
return bar; | ||
}; | ||
const result = app.parse(asyncFn); | ||
console.log(result.name); // => null | ||
console.log(result.foo); // => 123 | ||
console.log(result.args); // => ['qux'] | ||
console.log(result.isAsync); // => true | ||
console.log(result.isArrow); // => true | ||
console.log(result.isNamed); // => false | ||
console.log(result.isAnonymous); // => true | ||
``` | ||
<!-- docks-end --> | ||
## Result | ||
> In the result object you have `name`, `args`, `params`, `body` and few hidden properties | ||
> that can be useful to determine what the function is - arrow, regular, async/await or generator. | ||
- `name` **{String|null}**: name of the passed function or `null` if anonymous | ||
- `args` **{Array}**: arguments of the function | ||
- `params` **{String}**: comma-separated list representing the `args` | ||
- `defaults` **{Object}**: key/value pairs, useful when use ES2015 default arguments | ||
- `body` **{String}**: actual body of the function, respects trailing newlines and whitespaces | ||
- `isValid` **{Boolean}**: is the given value valid or not, that's because it never throws! | ||
- `isAsync` **{Boolean}**: `true` if function is ES2015 async/await function | ||
- `isArrow` **{Boolean}**: `true` if the function is arrow function | ||
- `isNamed` **{Boolean}**: `true` if function has name, or `false` if is anonymous | ||
- `isGenerator` **{Boolean}**: `true` if the function is ES2015 generator function | ||
- `isAnonymous` **{Boolean}**: `true` if the function don't have name | ||
**[back to top](#readme)** | ||
**[back to top](#readme)** | ||
## Contributing | ||
@@ -572,5 +214,1 @@ | ||
[tunnckocore_newsletter]: https://badgen.net/https/liam-badge-daknys6gadky.runkit.sh/com/newsletter/tunnckocore?label&color=5199FF&icon=https://svgshare.com/i/Dt6.svg | ||
[acorn]: https://github.com/acornjs/acorn | ||
[babylon]: https://babeljs.io/ | ||
[define-property]: https://github.com/jonschlinkert/define-property | ||
[espree]: https://github.com/eslint/espree |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
0
68268
298
212