Parse a function into an object using espree, acorn or babylon parsers. Extensible through Smart Plugins
npm install parse-function
align="center"
src="https://cdn.jsdelivr.net/emojione/assets/svg/1f54e.svg"
width="256"
height="256"
alt="Parse a function"
/>
> Parse a function into an object using espree, acorn or babylon parsers.
> Extensible through Smart Plugins
Please consider following this project's author,
Charlike Mike Reagent, and :star: the project
to show your :heart: and support.
[![Code style][codestyle-img]][codestyle-url]
[![CircleCI linux build][linuxbuild-img]][linuxbuild-url]
[![CodeCov coverage status][codecoverage-img]][codecoverage-url]
[![Renovate App Status][renovateapp-img]][renovateapp-url]
[![Make A Pull Request][prs-welcome-img]][prs-welcome-url]
[![Time Since Last Commit][last-commit-img]][last-commit-url]
If you have any _how-to_ kind of questions, please read the [Contributing
Guide][contributing-url] and [Code of Conduct][code_of_conduct-url] documents.
For bugs reports and feature requests, [please create an issue][open-issue-url]
or ping @tunnckoCore at Twitter.
[![Conventional Commits][ccommits-img]][ccommits-url]
[![Minimum Required Nodejs][nodejs-img]][npmv-url]
[![NPM Downloads Monthly][downloads-monthly-img]][npmv-url]
[![NPM Downloads Total][downloads-total-img]][npmv-url]
[![Share Love Tweet][twitter-share-img]][twitter-share-url]
[![Twitter][twitter-img]][twitter-url]
Project is semantically versioned & automatically released
from GitHub Actions with
Lerna.
[![Become a Patron][patreon-img]][patreon-url]
[![Buy me a Kofi][kofi-img]][kofi-url]
[![PayPal Donation][paypal-img]][paypal-url]
[![Bitcoin Coinbase][bitcoin-img]][bitcoin-url]
[![Keybase PGP][keybase-img]][keybase-url]
| Topic | Contact |
| :--------------------------------------------------------------- | ------------------------------------------------: |
| Any legal or licensing questions, like private or commerical use | ![tunnckocore_legal][tunnckocore_legal] |
| For any critical problems and security reports | ![tunnckocore_security][tunnckocore_security] |
| Consulting, professional support, personal or team training | ![tunnckocore_consulting][tunnckocore_consulting] |
| For any questions about Open Source, partnerships and sponsoring | ![tunnckocore_opensource][tunnckocore_opensource] |
- Always up-to-date: auto-publish new version when new version of dependency
is out, Renovate
- Standard: using StandardJS, Prettier, SemVer, Semantic Release and
conventional commits
- Smart Plugins: for extending the core API or the end Result,
see .use method and Plugins Architecture
- Extensible: using plugins for working directly on AST nodes, see the
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
- Tested: with 450+ tests for _200%_ coverage
- Install
- Which version to use?
- Notes
- Throws in one specific case
- Function named _"anonymous"_
- Real anonymous function
- Plugins Architecture
- API
- parseFunction
- .parse
- .use
- .define
- Contributing
- Guides and Community
- Support the project
- Contributors
- License
_(TOC generated by verb using
markdown-toc)_
This project requires Node.js >=8.11 _(see
Support & Release Policy)_.
Install it using yarn or
npm.
_We highly recommend to use Yarn when you
think to contribute to this project._
``bash`
$ yarn add parse-function
There's no breaking changes between the v2.x version. The only breaking isv2.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.acorn.parse
Where this "full", means "almost full", because it has bugs. This version also
uses () real parser to do the parsing.
Use v3.x
When you want to use different parser instead of the default babylon.parse, byoptions.parse
passing custom parse function to the option. **From this versionnode >= 4
we require **.
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. See the 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.
> _see: issue #3 and
> 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.
> _see:
> test/index.js#L319-L324
> and 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.isNamedtrue
will be , because in fact it's a named function.
> _see:
> test/index.js#L326-L331
> and Result section_
Only if you pass really an anonymous function you will get result.name equalnull
to , result.isAnonymous equal to true and result.isNamed equal tofalse.
> _see: the .use method,
> test/index.js#L305-L317
> and
> 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 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 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 comingresult
from the parser and 2) the is an object too - the end
Result, on which you can add more properties if you want.
_Generated using jest-runner-docs._
> Initializes with optional opts object which is passed directly to the.use
> desired parser and returns an object with and .parse methods. The.parseExpression
> default parse which is used is [babylon][]'s method fromv7
> .
#### Signature
`ts`
function(opts = {})
#### Params
- opts {object} - optional, merged with options passed to .parse methodreturns
- {object} - app object with .use and .parse methods
#### Examples
`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 a given code and returns a result object with useful properties -name
> such as , body and args. By default it uses Babylon parser, but youoptions.parse
> can switch it by passing - for exampleoptions.parse: acorn.parse
> . In the below example will show how to useacorn
> parser, instead of the default one.
#### Params
- code {Function|string} - any kind of function or string to be parsedoptions
- {object} - directly passed to the parser babylon, acorn, espreeoptions.parse
- {Function} - by default babylon.parseExpression, alloptions
are passed as second argumentreturns
- {object} - result see result section for more info
#### Examples
`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
`
> Add a plugin fn function for extending the API or working on the AST nodes.fn
> The is immediately invoked and passed with app argument which isparseFunction()
> instance of call. That fn may return another function that(node, result)
> accepts signature, where node is an AST node and result.parse
> is an object which will be returned result from the .parse
> method. This retuned function is called on each node only when method
> is called.
#### Params
- fn {Function} - plugin to be calledreturns
- {object} - app instance for chaining
_See Plugins Architecture section._
#### Examples
`jsapp
// plugin extending the Hello ${place}!
app.use((app) => {
app.define(app, '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 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 {object} - the object on which to define the propertyprop
- {string} - the name of the property to be defined or modifiedval
- {any} - the descriptor for the property being defined or modifiedreturns
- {object} - obj the passed object, but modified
#### Examples
`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 propertyapp.parse
// to the end result, returned from .parse
app.use((app) => {
return (node, result) => {
// this function is called
// only when 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
`
Please read the [Contributing Guide][contributing-url] and [Code of
Conduct][code_of_conduct-url] documents for advices.
For bug reports and feature requests, please join our [community][community-url]
forum and open a thread there with prefixing the title of the thread with the
name of the project if there's no separate channel for it.
Consider reading the
Support and Release Policy
guide if you are interested in what are the supported Node.js versions and how
we proceed. In short, we support latest two even-numbered Node.js release lines.
[Become a Partner or Sponsor?][kofi-url] :dollar: Check the OpenSource
Commision (tier). :tada: You can get your company logo, link & name on this
file. It's also rendered on package's page in [npmjs.com][npmv-url] and
yarnpkg.com sites too! :rocket:
Not financial support? Okey!
Pull requests,
stars and all kind of
contributions
are always welcome. :sparkles:
This project follows the
all-contributors
specification. Contributions of any kind are welcome!
Thanks goes to these wonderful people
(emoji key), consider showing
your support to them:
Charlike Mike Reagent 🚇 💻 📖 🤔 🚧 ⚠️ |
Copyright (c) 2016-present, Charlike Mike Reagent
Released under the [MPL-2.0 License][license-url].
[contributing-url]: https://github.com/tunnckoCore/opensource/blob/master/CONTRIBUTING.md
[code_of_conduct-url]: https://github.com/tunnckoCore/opensource/blob/master/CODE_OF_CONDUCT.md
[npmv-url]: https://www.npmjs.com/package/parse-function
[npmv-img]: https://badgen.net/npm/v/parse-function?icon=npm&cache=300
[license-url]: https://github.com/tunnckoCore/opensource/blob/master/packages/parse-function/LICENSE
[license-img]: https://badgen.net/npm/license/parse-function?cache=300
[libera-manifesto-url]: https://liberamanifesto.com
[libera-manifesto-img]: https://badgen.net/badge/libera/manifesto/grey
[codecoverage-img]: https://badgen.net/badge/coverage/100%25/green?icon=codecov&cache=300
[codecoverage-url]: https://codecov.io/gh/tunnckoCore/opensource
[codestyle-url]: https://github.com/airbnb/javascript
[codestyle-img]: https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb&cache=300
[linuxbuild-url]: https://github.com/tunnckocore/opensource/actions
[linuxbuild-img]: https://badgen.net/github/checks/tunnckoCore/opensource/master?cache=300&label=build&icon=github
[ccommits-url]: https://conventionalcommits.org/
[ccommits-img]: https://badgen.net/badge/conventional%20commits/v1.0.0/green?cache=300
[standard-release-url]: https://github.com/standard-release/standard-release
[standard-release-img]: https://badgen.net/badge/semantically/released/05c5ff?cache=300
[community-img]: https://badgen.net/badge/join/community/7b16ff?cache=300
[community-url]: https://github.com/tunnckocorehq/community
[last-commit-img]: https://badgen.net/github/last-commit/tunnckoCore/opensource/master?cache=300
[last-commit-url]: https://github.com/tunnckoCore/opensource/commits/master
[nodejs-img]: https://badgen.net/badge/node/>=8.11/green?cache=300
[downloads-weekly-img]: https://badgen.net/npm/dw/parse-function?icon=npm&cache=300
[downloads-monthly-img]: https://badgen.net/npm/dm/parse-function?icon=npm&cache=300
[downloads-total-img]: https://badgen.net/npm/dt/parse-function?icon=npm&cache=300
[renovateapp-url]: https://renovatebot.com
[renovateapp-img]: https://badgen.net/badge/renovate/enabled/green?cache=300
[prs-welcome-img]: https://badgen.net/badge/PRs/welcome/green?cache=300
[prs-welcome-url]: http://makeapullrequest.com
[paypal-url]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HYJJEZNSGAPGC&source=url
[paypal-img]: https://badgen.net/badge/PayPal/donate/003087?cache=300&icon=https://simpleicons.now.sh/paypal/fff
[kofi-url]: https://ko-fi.com/tunnckoCore
[kofi-img]: https://badgen.net/badge/Buy%20me/a%20coffee/29abe0c2?cache=300&icon=https://rawcdn.githack.com/tunnckoCore/badgen-icons/f8264c6414e0bec449dd86f2241d50a9b89a1203/icons/kofi.svg
[bitcoin-url]: https://www.blockchain.com/btc/payment_request?address=3QNHKun1K1SUui1b4Z3KEGPPsWC1TgtnqA&message=Open+Source+Software&amount_local=10¤cy=USD
[bitcoin-img]: https://badgen.net/badge/Bitcoin%20tip/3QNHKun...b4Z3KEGPPsWC1TgtnqA/yellow?cache=300&icon=https://simpleicons.now.sh/bitcoin/fff
[keybase-url]: https://keybase.io/tunnckoCore
[keybase-img]: https://badgen.net/keybase/pgp/tunnckoCore?cache=300
[twitter-url]: https://twitter.com/tunnckoCore
[twitter-img]: https://badgen.net/twitter/follow/tunnckoCore?icon=twitter&color=1da1f2&cache=300
[patreon-url]: https://www.patreon.com/bePatron?u=5579781
[patreon-img]: https://badgen.net/badge/Become/a%20patron/F96854?icon=patreon
[patreon-sponsor-img]: https://badgen.net/badge/become/a%20sponsor/F96854?icon=patreon
[twitter-share-url]: https://twitter.com/intent/tweet?text=https://ghub.now.sh/parse-function&via=tunnckoCore
[twitter-share-img]: https://badgen.net/badge/twitter/share/1da1f2?icon=twitter
[open-issue-url]: https://github.com/tunnckoCore/opensource/issues/new
[tunnckocore_legal]: https://badgen.net/https/liam-badge-daknys6gadky.runkit.sh/com/legal/tunnckocore?label&color=A56016&icon=https://svgshare.com/i/Dt6.svg
[tunnckocore_consulting]: https://badgen.net/https/liam-badge-daknys6gadky.runkit.sh/com/consulting/tunnckocore?label&color=07ba96&icon=https://svgshare.com/i/Dt6.svg
[tunnckocore_security]: https://badgen.net/https/liam-badge-daknys6gadky.runkit.sh/com/security/tunnckocore?label&color=ed1848&icon=https://svgshare.com/i/Dt6.svg
[tunnckocore_opensource]: https://badgen.net/https/liam-badge-daknys6gadky.runkit.sh/com/opensource/tunnckocore?label&color=ff7a2f&icon=https://svgshare.com/i/Dt6.svg
[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/
[cacache]: https://github.com/npm/cacache
[collect-mentions]: https://github.com/olstenlarck/collect-mentions
[define-property]: https://github.com/jonschlinkert/define-property
[espree]: https://github.com/eslint/espree
[execa]: https://github.com/sindresorhus/execa
[fast-glob]: https://github.com/mrmlnc/fast-glob
[glob]: https://github.com/isaacs/node-glob
[globby]: https://github.com/sindresorhus/globby
[koa-convert]: https://github.com/gyson/koa-convert
[koa]: https://github.com/koajs/koa
[tiny-glob]: https://github.com/terkelg/tiny-glob