parse-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.
If you have any how-to kind of questions, please read the Contributing
Guide and Code of Conduct documents.
For bugs reports and feature requests, please create an issue
or ping @tunnckoCore at Twitter.
Project is semantically versioned & automatically released
from GitHub Actions with
Lerna.
Topic | Contact |
---|
Any legal or licensing questions, like private or commerical use | |
For any critical problems and security reports | |
Consulting, professional support, personal or team training | |
For any questions about Open Source, partnerships and sponsoring | |
Features
- 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
Table of Contents
(TOC generated by verb using markdown-toc)
Install
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.
$ yarn add parse-function
Which version to use?
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. 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.
back to top
Notes
Throws in one specific case
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.
Function named "anonymous"
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.isNamed
will be true
, because in fact it's a named function.
Real anonymous function
see:
test/index.js#L326-L331
and 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
Plugins Architecture
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.
const parseFunction = require('parse-function');
const app = parseFunction();
app.use((self) => {
console.log(self.use);
console.log(self.parse);
console.log(self.define);
self.define(self, 'foo', (bar) => bar + 1);
});
console.log(app.foo(2));
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.
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, on which you can add more properties if you want.
back to top
API
Generated using jest-runner-docs.
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
function(opts = {})
Params
opts
{object} - optional, merged with options passed to .parse
methodreturns
{object} - app object with .use
and .parse
methods
Examples
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);
console.log(result.name);
console.log(result.isNamed);
console.log(result.isArrow);
console.log(result.isAnonymous);
console.log(result.args);
console.log(result.params);
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
{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
, all
options
are passed as second argumentreturns
{object} - result see result section for more info
Examples
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);
console.log(result.args);
console.log(result.body);
console.log(result.isNamed);
console.log(result.isArrow);
console.log(result.isAnonymous);
console.log(result.isGenerator);
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 from the .parse
method. This retuned function is called on each node only when .parse
method
is called.
Params
fn
{Function} - plugin to be calledreturns
{object} - app instance for chaining
See Plugins Architecture section.
Examples
app.use((app) => {
app.define(app, 'hello', (place) => `Hello ${place}!`);
});
const hi = app.hello('World');
console.log(hi);
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);
console.log(result.isArrow);
console.log(result.thatIsArrow);
const result = app.parse(function foo() {
return 123;
});
console.log(result.name);
console.log(result.isArrow);
console.log(result.thatIsArrow);
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
const parseFunction = require('parse-function');
const app = parseFunction();
const obj = {};
app.define(obj, 'hi', 'world');
console.log(obj);
app.use((app) => {
return (node, result) => {
app.define(result, 'foo', 123);
return result;
};
});
const asyncFn = async (qux) => {
const bar = await Promise.resolve(qux);
return bar;
};
const result = app.parse(asyncFn);
console.log(result.name);
console.log(result.foo);
console.log(result.args);
console.log(result.isAsync);
console.log(result.isArrow);
console.log(result.isNamed);
console.log(result.isAnonymous);
back to top
Contributing
Guides and Community
Please read the Contributing Guide and Code of
Conduct documents for advices.
For bug reports and feature requests, please join our community
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.
Support the project
Become a Partner or Sponsor? :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 and
yarnpkg.com sites too! :rocket:
Not financial support? Okey!
Pull requests,
stars and all kind of
contributions
are always welcome. :sparkles:
Contributors
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:
back to top
License
Copyright (c) 2016-present,
Charlike Mike Reagent <opensource@tunnckocore.com>
& contributors.
Released under the
MPL-2.0 License.