Babel plugin that introduces partial application syntax using ? tokens in argument lists to create partially applied functions
npx @tessl/cli install tessl/npm-babel--plugin-proposal-partial-application@7.27.0This Babel plugin introduces partial application syntax to JavaScript and TypeScript, allowing developers to use the ? token as a placeholder in function argument lists to create partially applied functions. The plugin transforms these placeholders into closures that accept the missing arguments while maintaining proper scope and context.
npm install --save-dev @babel/plugin-proposal-partial-applicationSince this is a Babel plugin, it's used in Babel configuration rather than imported directly in application code:
{
"plugins": ["@babel/plugin-proposal-partial-application"]
}Or with options:
// babel.config.js
module.exports = {
plugins: [
["@babel/plugin-proposal-partial-application", {
// Plugin options if any
}]
]
};The plugin enables partial application syntax in your JavaScript/TypeScript code:
// Basic partial application
const addOne = add(1, ?);
// Equivalent to: const addOne = (x) => add(1, x);
// Method calls
const logMessage = console.log(?);
// Equivalent to: const logMessage = (msg) => console.log(msg);
// Multiple placeholders
const formatter = format(?, "bold", ?);
// Equivalent to: const formatter = (text, color) => format(text, "bold", color);The plugin operates as a Babel AST transformer that:
? token recognitionthis binding for method callsThe main export is a Babel plugin factory function that returns a plugin configuration object.
// Import pattern for implementation reference
import { declare } from "@babel/helper-plugin-utils";
import { types as t, type Scope } from "@babel/core";
export default declare(api => BabelPlugin);
interface BabelPlugin {
name: string;
manipulateOptions: (opts: any, parser: ParserOptions) => void;
visitor: {
CallExpression: (path: NodePath<t.CallExpression>) => void;
};
}
interface ParserOptions {
plugins: string[];
}
type CallArgsWithoutPlaceholder = Exclude<
t.CallExpression["arguments"][number],
t.ArgumentPlaceholder
>[];Transforms call expressions containing ? placeholders into equivalent closure functions.
// Input:
const result = func(1, ?, 3);
// Output:
const result = (function(_argPlaceholder) {
return func(1, _argPlaceholder, 3);
});// Input:
const method = obj.doSomething(?, "param");
// Output:
const method = (function(_argPlaceholder) {
return obj.doSomething.call(obj, _argPlaceholder, "param");
});// Input:
const multiArg = func(?, "middle", ?);
// Output:
const multiArg = (function(_argPlaceholder, _argPlaceholder2) {
return func(_argPlaceholder, "middle", _argPlaceholder2);
});// Input:
const nested = a.b.c.method(?, value);
// Output:
const nested = (function(_argPlaceholder) {
const _receiver = a.b.c;
const _method = _receiver.method;
return _method.call(_receiver, _argPlaceholder, value);
});// Input:
const withSpread = func(a, ...args, ?);
// Output:
const withSpread = (function(_argPlaceholder) {
return func(a, ...args, _argPlaceholder);
});The plugin provides the following configuration properties:
interface PluginConfiguration {
/** Plugin identifier name */
name: "proposal-partial-application";
/**
* Configures the parser to recognize partial application syntax
* @param opts - Babel options (unused)
* @param parser - Parser configuration object
*/
manipulateOptions: (opts: any, parser: ParserOptions) => void;
/**
* AST visitor methods for transforming partial application syntax
*/
visitor: {
/**
* Transforms CallExpression nodes containing ArgumentPlaceholder tokens
* @param path - NodePath for the CallExpression
*/
CallExpression: (path: NodePath<t.CallExpression>) => void;
};
}These are private implementation details exposed for completeness:
/**
* Checks if a call expression contains ArgumentPlaceholder tokens
* @param node - CallExpression node to check
* @returns Boolean indicating presence of placeholders
*/
function hasArgumentPlaceholder(node: t.CallExpression): boolean;
/**
* Processes and unwraps arguments, handling immutable values and scope
* @param callExpr - Object destructuring CallExpression arguments
* @param scope - Babel scope for identifier generation
* @returns Array of assignment expressions for argument initialization
*/
function unwrapArguments(
{ arguments: args }: t.CallExpression,
scope: Scope,
): t.AssignmentExpression[];
/**
* Replaces ArgumentPlaceholder tokens with generated parameter identifiers
* @param node - CallExpression containing placeholders
* @param scope - Babel scope for identifier generation
* @returns Tuple of [placeholder parameters, processed arguments]
*/
function replacePlaceholders(
node: t.CallExpression,
scope: Scope
): [t.Identifier[], CallArgsWithoutPlaceholder];func(?, arg) → (x) => func(x, arg)obj.method(?) → (x) => obj.method(x)func(?, ?, arg) → (x, y) => func(x, y, arg)func(arg1, ?, arg3, ?) → (x, y) => func(arg1, x, arg3, y)func(...args, ?) → (x) => func(...args, x)a.b.c.method(?) → (x) => a.b.c.method(x)fn1(?)(fn2(?)) → (x) => fn1(x)(fn2)The plugin automatically adds the "partialApplication" parser plugin to enable ? token recognition:
/**
* Parser plugin identifier for partial application syntax
*/
type ParserPlugin = "partialApplication";The plugin handles various edge cases:
this binding for method calls// Before transformation:
const foo = bar(?);
// After transformation:
var _bar;
const foo = (_bar = bar, function bar(_argPlaceholder) {
return _bar(_argPlaceholder);
});// Before transformation:
const g = o.f(?, x, 1);
// After transformation:
var _o, _o$f, _x;
const g = (_o = o, _o$f = _o.f, _x = x, function f(_argPlaceholder) {
return _o$f.call(_o, _argPlaceholder, _x, 1);
});// Before transformation:
const h = p.b(1, y, x, 2, ?);
// After transformation:
var _p, _p$b, _y, _x2;
const h = (_p = p, _p$b = _p.b, _y = y, _x2 = x, function b(_argPlaceholder2) {
return _p$b.call(_p, 1, _y, _x2, 2, _argPlaceholder2);
});This plugin enables functional programming patterns in JavaScript by providing a concise syntax for partial application, reducing the need for manual wrapper functions and improving code readability in functional-style codebases.