Babel Plugin Parameter Decorator

raw JSON →
1.0.16 verified Sat Apr 25 auth: no javascript

A Babel plugin that transforms function parameter decorators to behave like TypeScript parameter decorators. Current stable version is 1.0.16, with infrequent releases. It enables parameter decorators on constructor parameters and method parameters when using Babel with legacy decorator support. Unlike TypeScript's built-in support, this plugin requires the separate `@babel/plugin-proposal-decorators` with `legacy: true` and optionally `@babel/plugin-proposal-class-properties`. It is the only dedicated Babel plugin for parameter decorator transformation as of 2024, filling a gap left by other decorator plugins. Works with both JavaScript and TypeScript via Babel presets.

error Error: [BABEL] unknown: Decorators are not enabled.
cause Missing @babel/plugin-proposal-decorators plugin in Babel config.
fix
Add ["@babel/plugin-proposal-decorators", { "legacy": true }] before babel-plugin-parameter-decorator.
error TypeError: Cannot read properties of undefined (reading 'forEach')
cause Parameter decorator used on a method without the companion method decorator (e.g., @validate) writing metadata.
fix
Ensure a method decorator writes the metadata that the parameter decorator expects; example uses @validate.
error Error: Parameter decorator is not a function
cause Incorrect import or invalid decorator function; parameter decorator must return a function that takes (target, propertyKey, parameterIndex).
fix
Define parameter decorator correctly: function decorator(key) { return function(target, propKey, paramIndex) { ... }; }
gotcha Plugin must be placed after @babel/plugin-proposal-decorators in plugins array.
fix Ensure order: [['@babel/plugin-proposal-decorators', {legacy: true}], 'babel-plugin-parameter-decorator']
gotcha If using @babel/preset-typescript, TypeScript-only imports used in decorators will be removed by default, breaking references.
fix Set 'onlyRemoveTypeImports' to true in preset options: ['@babel/preset-typescript', { onlyRemoveTypeImports: true }]
gotcha Requires @babel/plugin-proposal-decorators with legacy: true; the newer '2023-01' or '2023-11' decorator proposal is not supported.
fix Use legacy: true (the Stage 1 decorators proposal).
npm install babel-plugin-parameter-decorator
yarn add babel-plugin-parameter-decorator
pnpm add babel-plugin-parameter-decorator

Shows how to install, configure Babel with plugin-proposal-decorators (legacy mode) and this plugin, and then transpile a class with parameter decorators.

// Install dependencies
// npm install --save-dev @babel/core @babel/cli @babel/plugin-proposal-decorators babel-plugin-parameter-decorator

// .babelrc
{
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    "babel-plugin-parameter-decorator"
  ]
}

// input.js
function required(key) {
  return function (target, propertyKey, parameterIndex) {
    const metadata = `meta_${propertyKey}`;
    target[metadata] = [
      ...(target[metadata] || []),
      { index: parameterIndex, key }
    ];
  };
}

function validate(target, property, descriptor) {
  const fn = descriptor.value;
  descriptor.value = function(...args) {
    const metadata = `meta_${property}`;
    target[metadata].forEach(function(meta) {
      if (args[meta.index] === undefined) {
        throw new Error(`${meta.key} is required`);
      }
    });
    return fn.apply(this, args);
  };
  return descriptor;
}

class Greeter {
  constructor(message) {
    this.greeting = message;
  }

  @validate
  greet(@required('name') name) {
    return "Hello " + name + ", " + this.greeting;
  }
}

// Run: npx babel input.js --out-file output.js