Skip to content

stephanos/babel-plugin-immutable-record

Repository files navigation

babel-plugin-immutable-record Build Status Coverage Status

This plugin is acts as a preprocessor: it takes a mutable class and generates a record with the following properties:

  • immutable
  • type-safe
  • update() to do partial updates
  • toMap() to export an untyped Map

It's based Facebook's immutable-js and Flow.

Usage

If you run the plugin on the following input

/* @flow */

import Record from './record';

@Record()
class MyBand {
  name: string;
  members: string[];
  active: boolean = true;
}

it will create a file similar to this (details have been omitted):

/* @flow */

import Record from '../decorator';
import { List, Map } from 'immutable';

@Record()
class MyBand extends Record.Base {
  constructor(init: MyBandInit) { /* ... */ }

  get name(): string { /* ... */ }
  get members(): List<string> { /* ... */ }
  get active(): boolean { /* ... */ }

  update(update: MyBandUpdate): MyBand { /* ... */ }
  toMap(): Map<string, any> { /* ... */ }
}

type MyBandInit = { name: string; members: List<string>; active?: boolean };
type MyBandUpdate = { name?: string; members?: List<string>; active?: boolean };

The Flow type checker will prevent:

  • missing fields on initalisation
  • wrong type for a field
  • data for undefined properties

This shows how you could use it:

const band = new MyBand({
  name: 'The Be Sharps',
  members: List(['Homer', 'Apu', 'Seymour', 'Clancy'])
});
console.log(band.name); // prints 'The Be Sharps'

const newBand = band.update({ members: band.members.set(3, 'Barney') });
console.log(newBand.members.get(3)); // prints 'Barney'

Get Started

(1) Install the plugin:

npm install babel-plugin-immutable-record --save-dev

(2) Add the additional step to your build process, for example in Gulp 4:

var rename = require('gulp-rename');

gulp.task('generate', function () {
  return gulp.src('src/**/*.t.js')
    .pipe(babel({
      "plugins": [
        "babel-plugin-syntax-flow",
        'babel-plugin-syntax-decorators',
        'babel-plugin-syntax-class-properties',
        "babel-plugin-immutable-record"
      ]
    }))
    .pipe(rename((path) => { path.basename = path.basename.replace('.t', '') }))
    .pipe(gulp.dest('src'));
});

gulp.task('watch', function () {
  gulp.watch(['src/**/*.t.js'], gulp.series('generate'));
  // ...
});

NOTE: This is important. The output of the plugin should be part of the source code, not the transpiled build. Also, your regular watch task should ignore *.t.js and NOT trigger the generate task - otherwise you created an endless loop.

(3) Finally, you need to define the decorator in your source code:

/* @flow */

function Record(): Function {
  return () => {};
}

class Base {}
Record.Base = Base;

export default Record;

Advanced

Custom decorator

You can pick a custom name for the decorator (default is Record):

{
  "plugins": [
    ...
    ["babel-plugin-immutable-record", {
      "decorator": "ImmutableContainer"
    }]
  ]
}

Obviously, you'll then need to adapt the decorator's source file accordingly.

Header

To insert a custom header at the top of the file (e.g. to disable ESLint):

{
  "plugins": [
    ...
    ["babel-plugin-immutable-record", {
      "header": "my comment"
    }]
  ]
}

About

Generate immutable, statically typed records

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published