Babel plugin that introduces partial application syntax using ? tokens in argument lists to create partially applied functions
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
This 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.