MrT is a tool for making simple and complex chained interfaces on javascript libraries.
The resulting syntax is easy-to-read while still being flexible and 100% vanilla-js.
// Example interface for a web server
const webServer = new WebServer()
.public
.get("/account")
.action(accountController.list)
.get("/account/:id")
.action(accountController.show)
.authenticated
.authorized("owner", "admin")
.put("/account/:id")
.action(accountController.update)
.authorized("admin")
.post("/account")
.action(accountController.create)
.delete("/account/:id")
.action(accountController.delete)
.listen(3000);
The easiest and fastest way to install MrT is through the node package manager
:
$ npm install mrt --save
Whenever one constructor extends another, .super
must be called in the extended object's constructor before this
can be called.
This can be a gotcha for many developers, so MrT has a built-in pseudo-constructor called .initialize
that can be used by extended objects without the need to call .super
.
import Component from "mrt";
// Without using initialize
class Person extends Component {
constructor(name) {
super(name);
this.properties("name");
this.name(name);
}
}
// Using initialize
class Person extends Component {
initialize(name) {
this.properties("name");
this.name(name);
}
}
Define a simple chainable property that sets and gets a raw value:
class Person extends Component {
initialize() {
this.properties("name");
}
}
const person = new Person();
person.name("Jana");
person.name(); // "Jana"
class Person extends Component {
initialize() {
this.properties("nicknames").multi;
}
}
const person = new Person();
person.nicknames("Jana Banana", "Jananana");
person.nicknames(); // ["Jana Banana", "Jananana"]
class Person extends Component {
initialize() {
this.properties("nicknames").aggregate;
}
}
const person = new Person();
person.nicknames("Jana Banana");
person.nicknames("Jananana");
person.nicknames(); // ["Jana Banana", "Jananana"]
class Person extends Component {
initialize() {
this.properties("citiesVisited").multi.aggregate;
}
}
const person = new Person();
person.citiesVisited("Toledo", "OH");
person.citiesVisited("Colorado Springs", "CO");
person.citiesVisited(); // [["Toledo", "OH"], ["Colorado Springs", "CO"]]
class Person extends Component {
initialize() {
this.properties("values").multi.aggregate.flat;
}
}
const person = new Person();
person.values("one", "two");
person.values("three", "four");
person.values(); // [ "one", "two", "three", "four" ]
class Person extends Component {
initialize() {
this.properties("favoriteCities").merged;
}
}
const person = new Person();
person.mergedValues({"CO": "Colorado Springs", "KS": "Wichita"});
person.mergedValues({"CO": "Boulder"});
person.mergedValues(); // {"CO": "Boulder", "KS": "Wichita"}
class Person extends Component {
initialize() {
this.properties("favoriteNumber").filter(this.castIntegers);
}
castIntegers(value) {
const newValue = parseInt(value);
if (newValue) {
return newValue;
} else {
return value;
}
}
}
const person = new Person();
person.favoriteNumber("1");
person.favoriteNumber(); // 1
Call a synchronous callback each time a new value is set on the property
class Person extends Component {
initialize() {
this.properties("favoriteNumber").then(this.doSomething);
}
doSomething(value) {
// No returns. Just a simple synchronous callback.
}
}
const person = new Person();
person.favoriteNumber("1");
person.favoriteNumber(); // 1
A link creates a method which returns a new instance of the provided linkConstructor
.
The new instance is given a copy of all methods from the parent link. This is what enables MrT to chain multiple tiers.
import Component from "mrt";
class Car extends Component {
initialize() {
this.link("wheel", Wheel);
}
}
class Wheel extends Component {
initialize(diameter) {
this.properties("diameter");
this.diameter(diameter);
}
}
const car = new Car();
const wheel1 = car.wheel(10);
car
.wheel(10)
.wheel(10)
.wheel(10);
import Component from "mrt";
class Car extends Component {
initialize() {
this.link("wheel", Wheel).getter;
}
}
class Wheel extends Component {}
const car = new Car();
const wheel1 = car.wheel;
car
.wheel
.wheel
.wheel;
import Component from "mrt";
class Car extends Component {
initialize() {
this.properties("color");
this.link("door", Door).inherit("color");
}
}
class Door extends Component {}
const car = new Car();
car.color("Red");
const door = car.door;
door.color(); // "Red"
import Component from "mrt";
class Car extends Component {
initialize() {
this.properties("color");
this.link("door", Door).into("doors");
}
}
class Door extends Component {}
const car = new Car();
car
.door
.door;
car.doors.length; // 2
import Component from "mrt";
class Car extends Component {
initialize() {
this.properties("color");
this.link("door", Door).into("doors").key("side");
}
}
class Door extends Component {
initialize(side) {
this.properties("side");
this.side(side);
}
}
const car = new Car();
car
.door("left")
.door("right");
car.doors.left; // left door object
car.doors.right; // right door object
import Component from "mrt";
class Car extends Component {
initialize() {
this.properties("color");
this.link("door", Door).then(newDoor => {
// Called each time a link is created
});
}
}
class Door extends Component {}
const car = new Car();
car
.door()
.door();
import Component from "mrt";
class Car extends Component {
initialize() {
this.properties("color");
this.link("door", Door).apply(this);
}
}
class Door extends Component {
initialize(car, color) {
car; // Automatically passed by .arguments(this) in Car
color; // "green"
}
}
const car = new Car();
car.door("green");