or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-babel-plugin-transform-es2015-computed-properties

Babel plugin that compiles ES2015 computed properties to ES5-compatible code

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/babel-plugin-transform-es2015-computed-properties@6.24.x

To install, run

npx @tessl/cli install tessl/npm-babel-plugin-transform-es2015-computed-properties@6.24.0

index.mddocs/

babel-plugin-transform-es2015-computed-properties

A Babel plugin that compiles ES2015 computed properties to ES5-compatible code. It transforms dynamic property names (using expressions in square brackets) into runtime assignments using either Object.defineProperty for spec compliance or simple property assignments in loose mode.

Package Information

  • Package Name: babel-plugin-transform-es2015-computed-properties
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install --save-dev babel-plugin-transform-es2015-computed-properties

Core Imports

// Via .babelrc configuration (recommended)
{
  "plugins": ["transform-es2015-computed-properties"]
}

// Via Node API
const babel = require("babel-core");
const plugin = require("babel-plugin-transform-es2015-computed-properties");

Basic Usage

Via .babelrc (Recommended)

Without options:

{
  "plugins": ["transform-es2015-computed-properties"]
}

With options:

{
  "plugins": [
    ["transform-es2015-computed-properties", {
      "loose": true
    }]
  ]
}

Via CLI

babel --plugins transform-es2015-computed-properties script.js

Via Node API

require("babel-core").transform("code", {
  plugins: ["transform-es2015-computed-properties"]
});

Transformation Example

Input:

var obj = {
  ["x" + foo]: "heh",
  ["y" + bar]: "noo",
  foo: "foo",
  bar: "bar"
};

Output (spec mode):

var _obj;

function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }
  return obj;
}

var obj = (
  _obj = {},
  _defineProperty(_obj, "x" + foo, "heh"),
  _defineProperty(_obj, "y" + bar, "noo"),
  _defineProperty(_obj, "foo", "foo"),
  _defineProperty(_obj, "bar", "bar"),
  _obj
);

Output (loose mode):

var _obj;

var obj = (
  _obj = {},
  _obj["x" + foo] = "heh",
  _obj["y" + bar] = "noo",
  _obj.foo = "foo",
  _obj.bar = "bar",
  _obj
);

Capabilities

Plugin Export

The main plugin factory function that creates a Babel plugin configuration.

/**
 * Main plugin factory function that creates a Babel plugin
 * @param {Object} api - Babel API objects
 * @param {Object} api.types - Babel types utilities
 * @param {Function} api.template - Babel template builder
 * @returns {Object} Babel plugin configuration with visitor pattern
 */
function plugin({ types, template }) {
  return {
    visitor: {
      ObjectExpression: {
        exit(path, state) { /* transformation logic */ }
      }
    }
  };
}

// ES6 export (source)
export default plugin;

// CommonJS export (built)
module.exports = plugin;

Plugin Configuration Options

Configuration options passed via Babel configuration.

/**
 * Plugin options interface
 */
interface PluginOptions {
  /** 
   * Use simple property assignments instead of Object.defineProperty
   * @default false
   */
  loose?: boolean;
}

Visitor Pattern

The plugin uses Babel's visitor pattern to transform object expressions.

interface PluginVisitor {
  /** Visitor for ObjectExpression AST nodes */
  ObjectExpression: {
    /** Transform object expressions containing computed properties */
    exit(path: NodePath<ObjectExpression>, state: PluginState): void;
  };
}

interface PluginState {
  /** Plugin configuration options */
  opts: PluginOptions;
  /** Add Babel runtime helper function */
  addHelper(name: string): Identifier;
}

Transformation Modes

The plugin supports two transformation modes:

Spec Mode (Default)

Uses Object.defineProperty for standards-compliant property definitions.

/**
 * Spec-compliant transformation mode
 * Uses Object.defineProperty for property definitions
 * Handles special cases like __proto__ properties
 * @param {TransformationInfo} info - Transformation context
 * @returns {CallExpression|undefined} Single expression for single property or undefined for multiple
 */
function spec(info: TransformationInfo): CallExpression | undefined;

Loose Mode

Uses simple property assignments for better performance.

/**
 * Loose transformation mode
 * Uses simple property assignments instead of Object.defineProperty
 * Better performance but less standards-compliant
 * @param {TransformationInfo} info - Transformation context
 */
function loose(info: TransformationInfo): void;

Supported Transformation Patterns

The plugin handles different types of object properties and usage contexts:

Data Properties

Regular object properties with values.

// Input
var obj = { [key]: value };

// Output (spec mode)
Object.defineProperty(obj, key, value);

// Output (loose mode)  
obj[key] = value;

Accessor Properties

Getter and setter properties with computed names.

// Input
var obj = {
  get [foobar]() {
    return "foobar";
  },
  set [foobar](x) {
    console.log(x);
  }
};

// Output uses mutator map and defineEnumerableProperties helper
var _obj, _mutatorMap;
_obj = {};
_mutatorMap = {};
_mutatorMap[foobar] = _mutatorMap[foobar] || {};
_mutatorMap[foobar].get = function() { return "foobar"; };
_mutatorMap[foobar].set = function(x) { console.log(x); };
babelHelpers.defineEnumerableProperties(_obj, _mutatorMap);

Method Properties

Object methods with computed names.

// Input
var obj = {
  [foobar]() {
    return "foobar";
  }
};

// Methods are converted to function expressions and processed as data properties
var _obj;
_obj = {};
_defineProperty(_obj, foobar, function() { return "foobar"; });

Mixed Properties

Objects with both computed and non-computed properties.

// Input
var obj = {
  foo: "foo",
  [computed]: "computed",
  bar: "bar"
};

// Non-computed properties before first computed property stay in object literal
// All properties after first computed property are handled separately

Special Cases

  • proto properties: Always use assignment regardless of mode
  • Symbol properties: Handled as computed properties when used in computed position
  • Single vs Multiple: Single computed properties can be optimized to direct expressions
  • Function arguments: Works in function call arguments and other expression contexts
  • Variable assignments: Works when object is assigned to variables or returned from functions

Types

/**
 * Transformation context information
 */
interface TransformationInfo {
  /** Generated object identifier */
  objId: Identifier;
  /** Array of transformation statements */
  body: Statement[];
  /** Array of computed property nodes */
  computedProps: ObjectProperty[];
  /** Initial object expression for non-computed properties */
  initPropExpression: ObjectExpression;
  /** Function to get mutator map identifier */
  getMutatorId(): Identifier;
  /** Current transformation scope */
  scope: Scope;
  /** Plugin transformation state */
  state: PluginState;
}

/**
 * Babel AST node types used by the plugin
 */
type ObjectProperty = {
  kind: "get" | "set" | "init";
  computed: boolean;
  key: Expression;
  value: Expression;
};

type ObjectMethod = {
  kind: "method" | "get" | "set";
  computed: boolean;
  key: Expression;
  params: Pattern[];
  body: BlockStatement;
  generator: boolean;
  async: boolean;
};

type ObjectExpression = {
  properties: (ObjectProperty | ObjectMethod)[];
};

type NodePath<T> = {
  node: T;
  parent: Node;
  scope: Scope;
  replaceWith(node: Node): void;
  replaceWithMultiple(nodes: Node[]): void;
};

type Scope = {
  generateUidIdentifierBasedOnNode(node: Node): Identifier;
  generateUidIdentifier(name: string): Identifier;
  maybeGenerateMemoised(node: Node): Identifier | null;
};

Error Handling

The plugin handles various edge cases during transformation:

  • Mixed Properties: Objects with both computed and non-computed properties
  • Special Properties: __proto__ properties are always handled with assignment
  • Accessor Properties: Getters and setters use mutator maps
  • Single vs Multiple Properties: Optimized output for single computed properties

Internal Utilities

The plugin uses several internal utility functions for transformation:

/**
 * Build template for mutator map assignments
 */
const buildMutatorMapAssign = template(`
  MUTATOR_MAP_REF[KEY] = MUTATOR_MAP_REF[KEY] || {};
  MUTATOR_MAP_REF[KEY].KIND = VALUE;
`);

/**
 * Extract value from property node
 * @param {ObjectProperty|ObjectMethod} prop - Property node
 * @returns {Expression} Property value expression
 */
function getValue(prop: ObjectProperty | ObjectMethod): Expression;

/**
 * Push property assignment to transformation body
 * @param {Identifier} objId - Object identifier
 * @param {ObjectProperty} prop - Property node
 * @param {Statement[]} body - Transformation statements array
 */
function pushAssign(objId: Identifier, prop: ObjectProperty, body: Statement[]): void;

/**
 * Push mutator property definition to transformation body
 * @param {TransformationInfo} info - Transformation context
 * @param {ObjectProperty} prop - Property node with getter/setter
 */
function pushMutatorDefine(info: TransformationInfo, prop: ObjectProperty): void;

Dependencies

The plugin requires these Babel packages:

  • babel-template@^6.24.1: Template building utilities
  • babel-runtime@^6.22.0: Runtime helper functions

Runtime helpers used:

  • defineProperty: For Object.defineProperty calls in spec mode
  • defineEnumerableProperties: For getter/setter properties