Babel Plugin for Named Function Parameters
npm install babel-plugin-named-params
babel-plugin-named-params
=========================
Babel Plugin for Named Function Parameters


About
-----
This is a Babel transpiler plugin for transforming non-standard
named function parameters in ECMAScript 2015 source code.
In particular, it transpiles the following input constructs...
``js`
fn(a = "foo", 42, d = "bar", 7)
baz.quux.fn(a = "foo", 42, d = "bar", 7)
...to the output constructs...
`js`
T(undefined, fn, [ 42, 7 ], { a: "foo", d: "bar" })
T(baz.quux, baz.quux.fn, [ 42, 7 ], { a "foo", d: "bar" })
...where T is the "trampoline" functionbabel-runtime-named-params
of the corresponding run-time module.fn
Assuming the function was declared as function fn (a, b,
c, d) { ... }, these output constructs under run-time finally translate into...
`js`
fn.apply(undefined, [ "foo", 42, 7, "bar" ])
baz.quux.fn.apply(baz.quux, [ "foo", 42, 7, "bar" ])
...or the equivalent of the regular calls:
`js`
fn("foo", 42, 7, "bar")
baz.quux.fn("foo", 42, 7, "bar")
Motivation
----------
This plugin is motivated by the wish of the author to have a more
elegant approach to named parameters in JavaScript than the
usual convention of passing an object argument provides. For
such a conventional ECMAScript 2018 function declaration...
`js`
function foo (arg1, arg2, options) {
let { opt1, opt2 } = { opt1: "def1", opt2: "def2", ...options }
console.log(arg1, arg2, opt1, opt2)
}
...in addition, to the regular usage...
`js`
foo("val1", "val2", { opt1: "val3", opt2: "val4" })
// -> "val1", "val2", "val3", "val4"
...you can now use it with less boilerplate...
`js`
foo("val1", "val2", opt1 = "val3", opt2 = "val4")
// -> "val1", "val2", "val3", "val4"
...and even make the function declaration more elegant:
`js`
function foo (arg1, arg2, opt1 = "def1", opt2 = "def2") {
console.log(arg1, arg2, opt1, opt2)
}
Additionally, similar to Unix command-line option arguments (-x or--xx), which most of the time can be mixed with positional arguments,
one can now mix named and positional function arguments, too.
Features
--------
The following particular features are provided:
- Parameter Syntax: Named parameters are syntax-wise just ECMAScript assignment expressions
inside function argument lists.
But instead of assigning to a variable in the lexical scope of the
function call, this now assigns to a parameter of the function call.
- Parameter Ordering: Named and positional parameters can be provided in an arbitrary order.
For a function declaration function fn (a, b, c) { ... } all of thefn(x, y, z)
following function calls result in a call :
`js`
fn(a = x, b = y, c = z) // named parameters only
fn(x, b = y, z) // mixed parameters only (in positional order)
fn(b = y, x, z) // mixed parameters only (in arbitrary order)
fn(x, z, b = y) // mixed parameters only (in arbitrary order)
In other words, the algorithm for determining the function call
parameters is: first, the parameters (names and positions) of
the target function are determined via the function source code
(Function.prototype.toString()). Second, all named parameters areundefined
translated to resulting positional parameters at their particular
positions. Third, all original positional parameters are translated to
resulting positional parameters at still unused positions (from left
to right). All remaining unused positions are filled with the value .
- Options Parameter: In the JavaScript world, there is the convention of
having an options function parameter which receives an object offunction fn (a, b, c, options) { ... }
options. In case a named parameter in the function call is not found
in the function declaration, but such an options parameter exists,
the named parameter is passed as an option parameter field. For a
function declaration all offn(x, y, z, { foo: 42,
the following function calls result in a call
bar: 7 }):
`js`
fn(x, y, z, options = { foo: 42, bar: 7 }) // explicit options parameter (in positional order)
fn(options = { foo: 42, bar: 7 }, x, y, z) // explicit options parameter (in arbitrary order)
fn(x, y, z, foo = 42, bar = 7) // options as named parameters
fn(foo = 42, bar = 7, x, y, z) // options as named parameters
fn(x, y, z, options = { foo: 42 }, baz = 7) // explicit and implicit options
fn(x, y, z, baz = 7, options = { foo: 42 }) // explicit and implicit options
fn(a = x, b = y, c = z, foo = 42, bar = 7) // everything as named parameters
Caveat Emptor
-------------
- Function Declaration and Transpilation: Although the named parameters need
a Babel-based transpilation theirself, the function declarations
should not be transpiled to a target environment below ECMAScript
2015, as Babel would remove parameters with defaults from the
function declaration. To be able to use function declarations of the
form fn (a, b, c = def1, d = def2) { ... } you have to at least@babel/preset-env
target an ECMAScript 2015 environment like Node 6 with the help of
or the underlying func-params utility functionc
will to be able to determine the and d parameters.
- Increased Code Size: As the determination of function parameters is
done under run-time (to support arbitrary existing code which is not
part of the transpilation process itself), the resulting code size
of your application increased by about 26KB. This is harmless for
applications and libraries in the Node environments or applications
in Browser environments, but can hurt you for libraries in Browser
environments. Hence, try to not use this feature for libraries
intended to be used in Browser environments or accept that their size
increases by about 26KB.
- Decreased Run-Time Performance: As the determination of function parameters is
done under run-time (to support arbitrary existing code which is not
part of the transpilation process itself), the run-time performance
decreases somewhat. At least on the first function invocation.
Internally, the source code of the target function is parsed and the
result cached in memory. So, on the first function invocation, the parsing causes the
function invocation to be much slower than the regular invocation, while on the
second and all subsequent function invocation, the indirect function invocation
is just slightly slower than the regular invocation.
- Assignment Expression: As explained above, this plugin changes the
semantics of the assignment expressions inside function argument
lists. By definition, in foo(id = expr) the expr is assigned to aid
variable with the identifier in the lexical scope of the functionexpr
call. With this plugin, this is no longer the case. Now isid
assigned to the parameter with the identifier in the function
declaration. This is a change is semantics, of course. On the other
hand, an assignment expression inside a function argument list could
be considered a strange coding practice anyway.
Installation
------------
`shell`
$ npm install @babel/core
$ npm install @babel/preset-env
$ npm install babel-plugin-named-params
$ npm install babel-runtime-named-params
Usage
-----
- .babelrc:
`json`
{
"presets": [
[ "@babel/preset-env", {
"targets": {
"node": "6.0"
}
} ]
],
"plugins": [
[ "named-params", {
"options": true,
"caching": true
} ]
]
}
- sample.js:
`jsa=<${a}> b=<${b}> c=<${c}> d=<${d}>
const f1 = (a, b, c = "foo", d = "bar") => {
console.log()
}
f1(1, 2, 3, 4)
f1(1, 2, d = "4", 3)
f1(1, 2, d = "4", c = "3")
f1(a = "1", 2, c = "3", d = "4")
const f2 = (a, b, options = {}) => {
console.log(a=<${a}> b=<${b}> options=<${JSON.stringify(options)}>)`
}
f2(1, 2)
f2(1, 2, { foo: "bar", baz: "quux" })
f2(1, 2, options = { foo: "bar", baz: "quux" })
f2(1, 2, foo = "bar", baz = "quux")
f2(1, 2, baz = "quux", options = { foo: "bar" })
- $ babel-node sample.js
```
a=<1> b=<2> c=<3> d=<4>
a=<1> b=<2> c=<3> d=<4>
a=<1> b=<2> c=<3> d=<4>
a=<1> b=<2> c=<3> d=<4>
a=<1> b=<2> options=<{}>
a=<1> b=<2> options=<{"foo":"bar","baz":"quux"}>
a=<1> b=<2> options=<{"foo":"bar","baz":"quux"}>
a=<1> b=<2> options=<{"foo":"bar","baz":"quux"}>
a=<1> b=<2> options=<{"foo":"bar","baz":"quux"}>
License
-------
Copyright (c) 2018-2021 Dr. Ralf S. Engelschall (http://engelschall.com/)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.