babel-plugin-transform-class

    0.3.0 • Public • Published

    babel-plugin-transform-class

    NPM version Greenkeeper badge Build Status Coverage Status MIT Licensed

    A minimalist ES6 class babel transformer

    Overview

    Transpiler are very powerful, but can be frustrating when generated code do not fit to what we'd like.

    Use this transform plugin if you like what it generates for you. The generated code is ES3 compliant as long as you also add the 2 required polyfills.

    So, this transform plugin purely concentrate itself on the ES6 class notation.

    It uses only one traverse visitor and... It does not inject any helper function

    Class / Constructor

    The class Declaration & its constructor, become function declarations

    function MyClass(args) {/* code */}

    Prototype methods

    The class methods are assigned to the constructor prototype using Object.assign(MyClass.prototype, {/* methods */});. The method shortand notation foo() {/* code */} becomes foo: function foo() {/* code */} (to get function name support)

    Object.assign(MyClass.prototype, {
        foo: function foo() {/* code */}
    });

    Static methods

    The statics methods are assigned to the constructor using Object.assign.

    Object.assign(MyClass, {/* static methods */});

    Prototype inheritance

    The prototype inheritance declared by the ES6 extends instruction use Object.create() to create the prototype of the class. The class constructor is fixed back using Object.assign() along the method definitions.

    MyClass.prototype = Object.create(ParentClass.prototype);
    Object.assign(MyClass.prototype, {
        foo: function foo() {/* code */},
        constructor: MyClass
    });

    new.target

    The new.target property, is transpiled to this.constructor. As, with pure function constructor based prototype inheritance, the this instance is created by the child class, and given to the parent class constructor & methods (see super), this.constructor refers to the child class prototype constructor property, itself fixed to the child class function itself, matching to the constructor invoked by new.

    Constructor, methods, & static methods super call

    The constructor super(arg1, arg2) call is transpiled to ParentClass.call(this, arg1, arg2), the method super.methodName(arg1, arg2) call, to ParentClass.prototype.methodName.call(this, arg1, arg2), and the static method super.methodName(arg1, arg2) call, to ParentClass.methodName.call(this, arg1, arg2).

    Let's play

    To get a better idea of the result, you can play with it there: https://astexplorer.net/#/gist/0178b41edea28820b2452e3422059cbd/latest

    Up to come

    • Sourcemap tests (to check impact of transformations approaches on babel sourcemap generation)
    • ECMAScript stage 2 class properties notation and decorators may be potentially added as they make sense to complete class definition

    Example

    In

    class AbstractClass {
      constructor(a) {}
      publicMethod(foo, bar) {
        console.log('Abstract', new.target);
        this.bar = bar;
      }
    }
     
    class MyClass extends AbstractClass {
        static staticMethod(a, b) {
          console.log('static', a, b);
        }
        constructor(a) {
            super(a);
            this.bar = 51;
        }
        publicMethod(foo, bar) {
          super.publicMethod(foo, bar);
          console.log('MyClass', new.target);
        }
    }

    Out

    function AbstractClass(a) {}
     
    Object.assign(AbstractClass.prototype, {
      publicMethod: function publicMethod(foo, bar) {
        console.log('Abstract', this.constructor);
        this.bar = bar;
      }
    });
     
    function MyClass(a) {
      AbstractClass.call(this, a);
      this.bar = 51;
    }
     
    MyClass.prototype = Object.create(AbstractClass.prototype);
    Object.assign(MyClass.prototype, {
      publicMethod: function publicMethod(foo, bar) {
        AbstractClass.prototype.publicMethod.call(this, foo, bar);
        console.log('MyClass', this.constructor);
      },
      constructor: MyClass
    });
    Object.assign(MyClass, {
      staticMethod: function staticMethod(a, b) {
        console.log('static', a, b);
      }
    });

    Dependencies

    This transform plugin requires the JS target environment to at least support Object.create() & Object.assign(), either natively or via a polyfill (polyfills are intentionally not included, use the one of your choice).

    The Object.create(prototype, properties) call currently only use the first parameter (prototype), so their is no need to include polyfill support of its second argument (the properties object definitions) for now.

    Chosen Limitations from the ES6 standard

    Many ES6 class features may either be checked at edit time instead of runtime or lead to dangerous and/or not reviewer friendly code patterns.

    Here an example of some class related ESLint options:

    and the chosen limitations that allows lighter, more readable, and faster code:

    1. It does not support expressions as parent class, only class/constructor names
    2. It does not support getter/setter
    3. It does not throw errors if you invoke the constructor without the new keyword (see rule "capIsNew": true)
    4. It does not check if you use this before calling super() (see rule no-this-before-super: "error")
    5. It does not support nested classes (classes defined inside a class method)

    Last limitation

    • This transform plugin do not properly extends native Objects such as Date, Array, Function, etc

    Installation

    $ npm install babel-plugin-transform-class

    Usage

    Via .babelrc (Recommended)

    .babelrc

    {
      "plugins": ["transform-class"]
    }

    Via CLI

    $ babel --plugins transform-class script.js

    Via Node API

    require("babel-core")
    .transform("class A extends B { constructor() { super(); }}", {
      plugins: ["transform-class"]
    });

    Install

    npm i babel-plugin-transform-class

    DownloadsWeekly Downloads

    156

    Version

    0.3.0

    License

    MIT

    Last publish

    Collaborators

    • amorgaut