NAV Navbar
Logo
javascript coffeescript THIS IS AN OLD VERSION see current docs here

TrochaJS

It’s a standalone javascript library that describe route listing. Ideal for client-side route management (SPAs and XHR/Ajax async request) and NodeJS route declaration.

see our Hello World code example to lear more.

What it does

print clean routes for your javascript projects and even help <your favorite> (framework/set of libraries) to describe your app routes.

What it does not

handle route/view for your app nor framework.

See vanilla implementation or Angular 1.X implementation.

98 - Why this library exist

Ugly code example

theRoute = "https://my.domain.com.co/product/" +
myProduct.id +
"/buy" +
"?quantity=" +
sell.quantity;
theRoute = "https://my.domain.com.co/product/"+
myProduct.id+
"/buy"+
"?quantity="+
sell.quantity

Objective code example

theRoute = myRoutes.product.buy.path( {
    product_id: myProduct.id,
    query: {quantity: sell.quantity}
});
theRoute = myRoutes.product.buy.path
    product_id: myProduct.id
    query: quantity: sell.quantity

This library take inspiration from Ruby on Rails routing system, where you describe the routes via a simple name tree and call those routes via dinamic function naming, preventing use of string in views and controllers.

99 - Contributing

You can help me with this documentation editing/translating here, or reporting issues here, or improve the source code here.

100 - Basics

101 - Intro to Trocha JS

Get a copy of the library via npm

npm i trocha

Insert the library within your page

<body>
...Your page tags
<script src="https://<aCDN>/trocha/0.2.0/dist/trocha_library.min.js"></script>
...Your other scripts
</body>

Or via ES6 modules

import {Trocha} from 'trocha'
import {Trocha} from 'trocha'

Now define routes

var myRoutes = new Trocha({
    routes:{
        hello:{
            $id: "name"
        }
    }
});
myRoutes = new Trocha
    routes:
        hello:
            $id: "name"

finally print the routes

console.log(myroutes.hello.path());
console.log(myroutes.hello.path({name: "World"}));
console.log myroutes.hello.path()
console.log myroutes.hello.path name: "World"

This will print:

/hello/:name
/hello/World

Welcome to Trocha JS routes engine, the main goal of this library is to prevent use of annoing/unmantenible strings in sources(JS) and markup(HTML) files of your big projects.

This library does not depend of any other library/framework but can be integrated in those (React/Vue/Angular/Vanilla for example), also can be used on node and any mayor browser.

102 - Defining routes

You can define routes tree with a simple JSON when initialize or after that with a method, please see Best practices and Type of routes for depper explanation

Via JSON constructor

const myRoutes = new Trocha( {
    routes: {
        index: {
            $hide: true
        },
        contact: {},
        hello: {
            $id: "name"
        },
        crud: {
            $type: Trocha.RESOURCE,
            $id: "crud_id"
        },
        faq: "/FrequentlyAskedQuestions"
    }
});
myRoutes = new Trocha
    routes:
        index:
            $hide: true
        contact: {}
        hello:
            $id: "name"
        crud:
            $type: Trocha.RESOURCE
            $id: "crud_id"
        faq: "/FrequentlyAskedQuestions"

This should generate:

 # an empty string return index
/contact
/hello/:name
/crud # get = list
/crud/new # get = view for create
/crud/:crud_id # get = show
/crud/:crud_id/edit # get = view for update
/FrequentlyAskedQuestions # via myRoutes.faq

This is the recomended way to define your routes tree, when create your trocha object simply add a routes object tree.

Note the $ prefix this is used to separate trocha especific inputs of route names, this can be change see Route definition parameters.

Via method

let myRoutes = new Trocha();
myRoutes._newRoute({
    name: "hello",
    id: "name"
});
myRoutes._newAlias({
    name: "faq",
    alias: "/FrequentlyAskedQuestions"
});
myRoutes = new Trocha()
myRoutes._newRoute
    name: "hello"
    id: "name"
myRoutes._newAlias
    name: "faq"
    alias: "/FrequentlyAskedQuestions"

This should generate:

/hello/:name
/FrequentlyAskedQuestions # via myRoutes.faq

This route definition mode can be used in any part of the code, also is usefull to change a route definition.

Avoid this way, please see Best practices for depper explanation.

103 - Printing routes

See 101’s Via JSON constructor this is a continue of this example

myRoutes.index.path();
myRoutes.contact.path();
myRoutes.hello.path({name:"World"});
myRoutes.crud.list.path();
myRoutes.crud.new.path();
myRoutes.crud.show.path({
    crud_id:"ASD",
    query:{guest:"true"}
});
myRoutes.crud.edit.path();
myRoutes.faq.path();
myRoutes.index.path()
myRoutes.contact.path()
myRoutes.hello.path name: "World"
myRoutes.crud.list.path()
myRoutes.crud.new.path()
myRoutes.crud.show.path
    crud_id: "ASD"
    query: guest: "true"
myRoutes.crud.edit.path()
myRoutes.faq.path()

This should generate:

 # Empty string
/contact
/hello/World
/crud # get = list
/crud/new # get = view for create
/crud/ASD?guest=true # get = show
/crud/:crud_id/edit # get = view for update
/FrequentlyAskedQuestions # via myRoutes.faq

To print any of your routes simply use path() function at the end of the route. See Route printing parameters

200 - API

201 - Type of routes

There are 4 type of routes (see Constants):

Route

const myRoutes = new Trocha( {
    routes: {
        person: {
            $id: "name",
            $hide: true,
            attributes: {}
        }
    }
});
//OR
let myRoutes = new Trocha();
myRoutes._newRoute( {
    name: "person",
    hide: true,
    id: "name"
});
myRoutes.person._newRoute( {
    name: "attributes"
});
myRoutes = new Trocha
    routes:
        person:
            $id: "name"
            $hide: true
            attributes: {}
#OR
myRoutes = new Trocha()
myRoutes._newRoute
    name: "person"
    hide: true
    id: "name"
myRoutes.person._newRoute name: "attributes"

This should generate:

/:name
/:name/attributes

The simplest and base for any other type, it represent: <name>/[:<id>](id is optional).

Resource

const myRoutes = new Trocha( {
    routes: {
        products: {
            $type: Trocha.RESOURCE,
            $id: "product_id"
        }
    }
});
//OR
let myRoutes = new Trocha();
myRoutes._newResource( {
    name: "products",
    id: "product_id"
});
myRoutes = new Trocha
    routes:
        products:
            $type: Trocha.RESOURCE
            $id: "product_id"
#OR
myRoutes = new Trocha()
myRoutes._newResource
    name: "products",
    id: "product_id"

This should generate:

/products # list of
/products/new
/products/:product_id # show of
/products/:product_id/edit

Is a configurable set of routes, ideal for CRUD routes:

This kind of routes is useful also for RESTful request

Custom resource

apiResource = new Trocha.$RESOURCE; // Note the $, this is an object not the String
delete apiResource.new;
delete apiResource.edit;
delete apiResource.show;
apiResource.list = {$id: false}; // Override/Remove $hide: true
apiResource.create = {$hide: true, $id: false, $method: Trocha.POST};
apiResource.read = {$hide: true};
apiResource.update = {$hide: true, $method: Trocha.PATCH};
apiResource.delete = {$hide: true, $method: Trocha.DELETE};

serverRoutes = new Trocha( {
    domain: 'https://myRESTfulAPI.net.co',
    post: '.json',
    alwaysPost: true,
    alwaysUrl: true,
    // customSelector: 'ñ',
    routes: {
        products: {
            $type: Trocha.RESOURCE, // Note this is String
            $id: 'product_id'
            $resource: apiResource
        }
    }
});
apiResource = new Trocha.$RESOURCE # Note the $, this is an object not a String
delete apiResource.new
delete apiResource.edit
delete apiResource.show
apiResource.list = {$id: false} # Override $hide: true
apiResource.create = {$hide: true, $id: false, $method: Trocha.POST}
apiResource.read = {$hide: true}
apiResource.update = {$hide: true, $method: Trocha.PATCH}
apiResource.delete = {$hide: true, $method: Trocha.DELETE}

serverRoutes = new Trocha
    domain: 'https://myRESTfulAPI.net.co'
    post: '.json'
    alwaysPost: true
    alwaysUrl: true
    # customSelector: 'ñ'
    routes:
        products:
            $type: Trocha.RESOURCE # Note this is String (whitout the $ prefix)
            $id: 'product_id'
            $resource: apiResource

This should generate:

https://myRESTfulAPI.net.co/products/list.json # list with method get
https://myRESTfulAPI.net.co/products.json # create with method post
https://myRESTfulAPI.net.co/products/:product_id.json # read with method get
https://myRESTfulAPI.net.co/products/:product_id.json # update with method patch
https://myRESTfulAPI.net.co/products/:product_id.json # delete with method delete

You can create your customs resources, ideal for RESTful apis (see Best practices, Methods and Constants )

When you’re defining your trocha object add a resource object, it will be use has reference for any resource within this trocha object.

Scope

const myRoutes = new Trocha( {
    routes: {
        language: {
            $type: Trocha.SCOPE,
            id: "language_id",
            dashboard: {}
        }
    }
});
//OR
let myRoutes = new Trocha();
myRoutes._newScope({name: "language", id: "language_id"});
myRoutes.language._newRoute({name: "dashboard"});

console.log(myRoutes.language.dashboard.path({language_id: 'esBO'}));
console.log(myRoutes.dashboard.path());
myRoutes = new Trocha
    routes:
        language:
            $type: Trocha.SCOPE
            id: "language_id"
            dashboard: {}
#OR
myRoutes = new Trocha()
myRoutes._newScope name: "language", id: "language_id"
myRoutes.language._newRoute name: "dashboard"

console.log myRoutes.language.dashboard.path language_id: 'esBO'
console.log myRoutes.dashboard.path()

This should print:

/esBO/dashboard
/dashboard

Is an optional level of the route tree.

Alias

const cdns = new Trocha( {
    routes: {
        // This is a cool vanilla views/routing system more @ http://mtrpcic.net/pathjs/
        pathjs: "https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js"
        images: {
            $type: Trocha.ALIAS,
            $alias: "https://cdn.mydomain.io/images",
            $id: "image_token",
            desktop: 'full_size_for_desktop'
        }
    }
});
//OR
let cdns = new Trocha();
cdns._newAlias( {
    name: "pathjs",
    alias: "https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js"
});
cdns._newAlias( {
    name: "images",
    alias: "https://cdn.mydomain.io/images",
    $id: "image_token"
});
cdns.images._newAlias({
    name: "desktop",
    alias: "full_size_for_desktop"
})
console.log(cdns.pathjs.path());
console.log(cdns.images.path({image_token: 'car.jpg'}));
console.log(cdns.images.desktop.path({query:{colour:'mono'}}));
cdns = new Trocha
    routes:
        # This is a cool vanilla views/routing system more @ http://mtrpcic.net/pathjs/
        pathjs: 'https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js'
        images:
            $type: Trocha.ALIAS
            $alias: 'https://cdn.mydomain.io/images'
            $id: 'image_token'
            desktop: 'full_size_for_desktop'
#OR
cdns = new Trocha()
cdns._newAlias
    name: 'pathjs'
    alias: 'https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js'
cdns._newAlias
    name: 'images'
    $id: 'image_token'
    alias: 'https://cdn.mydomain.io/images'
cdns.images._newAlias
    name: 'desktop'
    alias: 'full_size_for_desktop'

console.log cdns.pathjs.path()
console.log cdns.images.path image_token: 'car.jpg'
console.log cdns.images.desktop.path query: colour:'mono'

This should print:

https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js
https://cdn.mydomain.io/images/car.jpg
https://cdn.mydomain.io/images/:image_token/full_size_for_desktop?colour=mono

This type of route can render an specific string independent of the name, it’s usefull to print cdns and very long and isolated paths

202 - Constants

console.log(Trocha.GET);
console.log Trocha.GET

This should print:

GET

The Trocha class also offers a set of useful constants, to call those constants simply write Trocha.<CONST_NAME> or within the module include import {Trocha, GET, ROUTE, $RESOURCE} from 'trocha'.

Route types names

const ROUTES = new Trocha({
    routes:{
        route_a: {
            $type: Trocha.ROUTE // Not necesary
        },
        route_b: {},
        scope: {
            $type: Trocha.SCOPE
        },
        resource: {
            $type: Trocha.RESOURCE
        },
        alias: { // if alias don't have child, should be use the alias string directly
            $type: Trocha.ALIAS,
            $alias: "theAlias"
        }
    }
});
ROUTES = new Trocha
    routes:
        route_a:
            $type: Trocha.ROUTE # Not necesary
        route_b: {}
        scope:
            $type: Trocha.SCOPE
        resource:
            $type: Trocha.RESOURCE
        alias: # if alias don't have child, should be use the alias string directly
            $type: Trocha.ALIAS
            $alias: "theAlias"

There are 4 type of routes implemented in trocha but only 2 route type names normally is needed to be use:

The other 2 can be defined via:

See Type of routes.

HTTP request methods names

const ROUTES = {
    SERVER: new Trocha({
        domain: 'https://myRESTfulAPI.net.co',
        alwaysUrl: true,
        routes:{
            users: {
                login: {
                    $method: Trocha.PATCH
                }
            }
        }
    });
};
ROUTES.SERVER = new Trocha
    domain: 'https://myRESTfulAPI.net.co'
    alwaysUrl: true
    routes:
        users:
            login:
                $method: Trocha.PATCH

This should generate:

users.login:
    url: https://myRESTfulAPI.net.co/users/login
    method: PATCH

You can use this in Angular 1.X xhr calls, for example:

// some Angular 1.X code
data.user = {
    username: $scope.data.user.toLowerCase(),
    password: $scope.data.password
};
$http({
    url: ROUTES.SERVER.users.login.path(),
    method: ROUTES.SERVER.users.login.$method,
    data: data
} ).then( (response) => {
    // Your amazing login success code
}, (response) => {
    // Your amazing login fail code
});
# some Angular 1.X code
data.user =
    username: $scope.data.user.toLowerCase()
    password: $scope.data.password
$http
    url: ROUTES.SERVER.users.login.path()
    method: ROUTES.SERVER.users.login.$method
    data: data
.then (response) ->
    # Your amazing login success code
, (response) ->
    # Your amazing login fail code

There are 9 HTTP request methods names implemented in trocha:

Those names are usefull when you’re using the route object to point a RESTful server see Angular 1.X implentation You can set/get the method name of any of your routes via the $method param/attribute. Remember the objective of trocha is to avoid the use of repetitive or unmantenable Strings

Resource base object

var myResource = Trocha.$RESOURCE
const ROUTES = new Trocha({customSelector: 'TC_'})
var myOtherResource = ROUTES.TC_RESOURCE

myResource = Trocha.$RESOURCE
ROUTES = new Trocha customSelector: 'TC_'
myOtherResource = ROUTES.TC_RESOURCE

This should generate:

{
"myResource": {
    "$id": "id",
    "edit": {},
    "list": {
        "$hide": true,
        "$id": false
    },
    "new": {
        "$id": false
    },
    "show": {
        "$hide": true
    }
},
"myOtherResource": {
    "TC_id": "id",
    "edit": {},
    "list": {
        "TC_hide": true,
        "TC_id": false
    },
    "new": {
        "TC_id": false
    },
    "show": {
        "TC_hide": true
    }
}}

Trocha.$RESOURCE This routes tree (object like the routes: {...} you do) define how any resource will be created within this trocha object, you can modify this object if you want to create Custom resources

203 - Route definition parameters

When you’re creating your trocha object you can set some basic parameters so when a route need to be printed it will do with more or less content if you like.

Routes & its parameters

myRoutes = new Trocha( {
    routes: {
        home: {}, // A simple route
        The: { // It's supports many levels of hierarchy
            quick: {
                brown: {
                    fox: {
                        jumps: {
                            over: {
                                the: {
                                    lazy: {
                                        dog: {}}}}}}}}}, // that's why I prefer coffeescript ;)
        people: {
            $id: "name",
            update: {
                $hide: true, // The "update" will be hidden
                $method: Trocha.PATCH // This can be part of a (custom) resource ;)
            }
        },
        ninja: { // see 300 - Real World applications > Advance ID handling
            $id: "ninja_shadow",
            $justId: true,
            flying_shuriken: {
                $parentId: false,
                $id: 'shuriken_id'
            },
            silent_knife: { // note it does the same as Previous example, but more presise
                ninja_shadow: false,
                $id: 'knife_id'
            }
        }
    }
});
console.log(myRoutes.home.path());
console.log(myRoutes.The.quick.brown.path());
console.log(myRoutes.The.quick.brown.fox.jumps.over.the.lazy.dog.path());
console.log(myRoutes.people.update.path());
console.log(myRoutes.people.update.$method);
console.log(myRoutes.ninja.path());
console.log(myRoutes.ninja.flying_shuriken.path({shuriken_id: 'the·distracting·one'}));
console.log(myRoutes.ninja.silent_knife.path({knife_id: 'the·killer·one'}));
myRoutes = new Trocha
    routes:
        home: {} # A simple route
        The: # It's supports many levels of hierarchy
            quick:
                brown:
                    fox:
                        jumps:
                            over:
                                the:
                                    lazy:
                                        dog: {} # that's why I prefer coffeescript ;)
        people:
            $id: "name"
            update:
                $hide: true # The "update" will be hidden
                $method: Trocha.PATCH # This can be part of a (custom) resource ;)
        ninja: # see 300 - Real World applications > Advance ID handling
            $id: "ninja_shadow"
            $justId: true
            flying_shuriken:
                $parentId: false
                $id: 'shuriken_id'
            silent_knife: # note it does the same as Previous example, but more presise
                ninja_shadow: false
                $id: 'knife_id'

console.log myRoutes.home.path()
console.log myRoutes.The.quick.brown.path()
console.log myRoutes.The.quick.brown.fox.jumps.over.the.lazy.dog.path()
console.log myRoutes.people.update.path()
console.log myRoutes.people.update.$method
console.log myRoutes.ninja.path()
console.log myRoutes.ninja.flying_shuriken.path shuriken_id: 'the·distracting·one'
console.log myRoutes.ninja.silent_knife.path knife_id: 'the·killer·one'

This should print:

/home
/people/:name
PATCH
/:ninja_shadow
/flying_shuriken/the·distracting·one
/silent_knife/the·killer·one
/The/quick/brown
/The/quick/brown/fox/jumps/over/the/lazy/dog

routes is an optional(but recomended) object that define the entire routes tree of your trocha object.

A trivial example: routes:{<name>:{...route parameters...}, <name>:"<alias>"}

Each route type suport diferent parameters, here a list on how to use:

route resource scope alias Type What does
$name (*) Mandatory Mandatory Mandatory Mandatory String the name of this part of the path
$alias (*) NA NA NA Mandatory String An String that replace the name
$id Optional Mandatory NA NA String A modificable ID_name see Best practices
$method Optional NA NA NA String Define wich method will be used when requested this path
$hide Optional NA NA NA Bool(True) If true hide the actual name of this part of the path (ideal for indexs)
$justId Optional Optional Optional NA Bool(True) Same as $hide but needs $id
$parent_id Optional Optional Optional NA Bool(False) If false the parent id will be absent, can be Override in path()
<Id> Optional Optional Optional NA Bool(False) If false the id will be absent, can be Override in path()

Note if $hide or $justId are false will do nothing, same goes to $parent_id or \<Id\> if true

(*) Also note name and alias are only used when the route is defined vía method

Domain & Always Url

serverRoutes = new Trocha( {
    domain: 'https://mydomain.net.co',
    alwaysUrl: true,
    routes: {
        home: {}
    }
});
console.log(serverRoutes.home.path());
serverRoutes = new Trocha
    domain: 'https://mydomain.net.co'
    alwaysUrl: true
    routes: home: {}
console.log serverRoutes.home.path()

This should print:

https://mydomain.net.co/home

You can set the domain of your routes via domain constructor attribute and choice if you want to always print with alwaysUrl, if you want to print the domain just fewer times see url printing parameter.

This is very usefull when you’re defining routes for a RESTful server.

Prefix & postfix string

templateRoutes = new Trocha( {
    pre: '/templates', // note the /
    post: '-myH45H.html',
    alwaysPost: true,
    routes: {
        home: {}
    }
});
console.log(templateRoutes.home.path());
console.log(templateRoutes.home.path({post: false}));
console.log(templateRoutes.home.path({pre: true}));
console.log(templateRoutes.home.path({ext: true})); // only if alwaysPost is not set
templateRoutes = new Trocha
    pre: '/templates' # note the /
    post: '-myH45H.html'
    alwaysPost: true
    routes: home: {}
console.log templateRoutes.home.path()
console.log templateRoutes.home.path post: false
console.log templateRoutes.home.path pre: true
console.log templateRoutes.home.path ext: true # only if alwaysPost is not set

This should print:

/home-myH45H.html
/home
/templates/home-myH45H.html
/templates/home-myH45H.html

You can add Strings at the begining or end your path if you needed, for example if you need add an extention like .html to all your routes simply add as a contructor attribute post: ".html", alwaysPost: true,

see Route printing parameters for furter explanation

$ & customSelector

myRoutes = new Trocha( {
    customSelector: 'TRCH',
    routes: {
        hello: {
            TRCHid: 'name',
            TRCHmethod: Trocha.GET,
            $id: {}
        }
    }
});
console.log(myRoutes.hello.path({name: 'World'}));
console.log(myRoutes.hello.TRCHid);
console.log(myRoutes.hello.$id);
console.log(myRoutes.hello.TRCHmethod);
console.log(myRoutes.hello.$id.path());
myRoutes = new Trocha
    customSelector: 'TRCH'
    routes:
        hello:
            TRCHid: 'name'
            TRCHmethod: Trocha.GET
            $id: {}
console.log myRoutes.hello.path {name: 'World'}
console.log myRoutes.hello.TRCHid
console.log myRoutes.hello.$id
console.log myRoutes.hello.TRCHmethod
console.log myRoutes.hello.$id.path()

This should print:

/hello/World
name
Object {... trocha route object ...}
GET
/hello/:name/$id

.

If you have a route like this /asd/$id/qwe you will notice you can’t directly set an $id route name, thats because by default the JSON constructor use $ as a prefix to reserved names.

If you need to use it anyway, you can overide the selector, simply add customSelector: 'TRCH' to your inicializer object.

204 - Route printing parameters

myRoutes = new Trocha( {
    pre: '/templates', // note the /
    post: '-myH45H.html',
    domain: 'https://mydomain.net.co',
    routes: {
        town: {
            $id: 'town_name',
            house: {
                $id: 'address'
            }
        }
    }
});
console.log(myRoutes.town.path());
console.log(myRoutes.town.path({url: true})); //only if alwaysUrl is not set
console.log(myRoutes.town.path({pre: true}));
console.log(myRoutes.town.path({post: true})); //only if alwaysPost is not set
console.log(myRoutes.town.path({ext: true}));
console.log(myRoutes.town.path({hide: true}));
console.log(myRoutes.town.path({query: {description: true, pictures: 4}}));
console.log(myRoutes.town.path({fragment: 'references'}));
console.log(myRoutes.town.house.path({parentId: false}));
console.log(myRoutes.town.house.path({id: false}));
console.log(myRoutes.town.house.path({
    town_name: 'Sydney_NSW',
    address: 'P._Sherman_42_wallaby_way'
}));

myRoutes = new Trocha
    pre: '/templates' # note the /
    post: '-myH45H.html'
    domain: 'https://mydomain.net.co'
    routes:
        town:
            $id: 'town_name'
            house:
                $id: 'address'
console.log myRoutes.town.path()
console.log myRoutes.town.path url: true # only if alwaysUrl is not set
console.log myRoutes.town.path pre: true
console.log myRoutes.town.path post: true # only if alwaysPost is not set
console.log myRoutes.town.path ext: true
console.log myRoutes.town.path hide: true
console.log myRoutes.town.path
    query:
        description: true
        pictures: 4
console.log myRoutes.town.path fragment: 'references'
console.log myRoutes.town.house.path parentId: false
console.log myRoutes.town.house.path id: false
console.log myRoutes.town.house.path
    town_name: 'Sydney_NSW'
    address: 'P._Sherman_42_wallaby_way'

This should print:

/town/:town_name
https://mydomain.net.co/town/:town_name
/templates/town/:town_name
/town/:town_name-myH45H.html
/templates/town/:town_name-myH45H.html
/:town_name
/town/:town_name?description=true&pictures=4
/town/:town_name#references
/town/house/:address
/town/:town_name/house
/town/Sydney_NSW/house/P._Sherman_42_wallaby_way

After you define your routes the next think you wanna do is print those routes, to do that simply use the path({args}) at the end of your desire route.

Parameters:

205 - Methods & attributes

When you create your own trocha object it offers a tree of routes objects where most of object offer a variety of methods/attributes. here the explanation what it does.

$name

myRoutes = new Trocha( {
    routes: {
        country: {
            state: {
                city: {
                    town: {}}}}
    }
});
console.log(myRoutes.country.$name);
console.log(myRoutes.country.state.$name);
console.log(myRoutes.country.state.city.town.$name);
myRoutes = new Trocha
    routes:
        country:
            state:
                city:
                    town: {}
console.log myRoutes.country.$name
console.log myRoutes.country.state.$name
console.log myRoutes.country.state.city.town.$name

This should print:

country
state
town

<selector>name Is a String, last child of the route.

$as

myRoutes = new Trocha( {
    routes: {
        country: {
            state: {
                city: {
                    town: {}}}}
    }
});
console.log(myRoutes.country.$as);
console.log(myRoutes.country.state.$as);
console.log(myRoutes.country.state.city.town.$as);
myRoutes = new Trocha
    routes:
        country:
            state:
                city:
                    town: {}
console.log myRoutes.country.$as
console.log myRoutes.country.state.$as
console.log myRoutes.country.state.city.town.$as

This should print:

country
country_state
country_state_city_town

<selector>as Is a String, concatenate parent names and it self. (to easy identify the route).

This attribute is really useful if you want to declare controllers for your route handler like Angular.

$method

serverRoutes = new Trocha( {
    routes: {
        students: {
            $method: Trocha.GET,
            create: { $method: Trocha.POST}}
    }
});
console.log(serverRoutes.students.$method);
console.log(serverRoutes.students.create.$method);
myRoutes = new Trocha
    routes:
        students:
            $method: Trocha.GET
            create: $method: Trocha.POST
console.log myRoutes.students.$method
console.log myRoutes.students.create.$method

This should print:

GET
POST

<selector>method Is a String, the desired method of this route. See Constants methods names on how to set this String.

This attribute is really useful if you want to make XHR (ajax) calls, see JQuery example.

Methods

path

<route>.path({args}) See Route printing parameters.

_new<Route type>

let myRoutes = new Trocha();
myRoutes._newRoute({
    name: "person",
    // Optionals
    id: "name",
    hide: true,
    method: Trocha.PUT
});
myRoutes._newScope({
    name: "language",
    // Optionals
    id: "lng"
});
myRoutes._newResource({
    name: "products",
    id: "product_id",
    // Optionals
    resource: {
        show: {},
        list: {
            $hide: true
        }
    }
});
myRoutes._newAlias({
    name: "faq",
    alias: "FrequentlyAskedQuestions"
});
myRoutes = new Trocha()
myRoutes._newRoute {
    name: "person"
    # Optionals
    id: "name"
    hide: true
    method: Trocha.PUT
}
myRoutes._newScope {
    name: "language"
    # Optionals
    id: "lng"
}
myRoutes._newResource {
    name: "products"
    id: "product_id"
    # Optionals
    resource:
        show: {}
        list:
            $hide: true
}
myRoutes._newAlias {
    name: "faq"
    alias: "FrequentlyAskedQuestions"
}

This methods helps to create new child routes.

Avoid this way, please see Best practices for depper explanation.

300 - Real World applications

Note the main goal of this library is to declare routes, not to handle.

When to use

When do not use

Alternativeto TrochaJS

Advance ID handling

/reports
/reports/123
/reports/tables
/reports/tables/321
myRoutes = new Trocha( {
    routes: {
        reports: {
            $id: 'report_id',
            tables: {
                show: {$hide: true},
                $id: 'table_id',
                // Next (any of two)lines makes the best solution
                // parentId: false // OR
                // report_id: false
            }}
    }
});
myRoutes = new Trocha
    routes:
        reports:
            $id: 'report_id'
            tables:
                show: $hide: true
                $id: 'table_id'
                # Next (any of two)lines makes the best solution
                # parentId: false #  OR
                # report_id: false

You can get this with:

console.log myRoutes.reports.path({report_id: false})
console.log myRoutes.reports.path({report_id: ''}) // equal to previous
console.log myRoutes.reports.path({report_id: 123})

console.log myRoutes.reports.path({report_id: 'tables'}) // may be not the best idea
console.log myRoutes.reports.tables.path({parentId: false, table_id: false}) // :(
console.log myRoutes.reports.tables.show.path({report_id: false})
console.log myRoutes.reports.tables.show.path({parentId: false})
// if parentId defined in contructor (best idea)
console.log myRoutes.reports.tables.show.path()
console.log myRoutes.reports.tables.path(table_id: 321)
console.log myRoutes.reports.path report_id = false
console.log myRoutes.reports.path report_id = '' # equal to previous
console.log myRoutes.reports.path report_id = 123

console.log myRoutes.reports.path report_id = 'tables' # may be not the best idea
console.log myRoutes.reports.tables.path parentId: false, table_id: false # :(
console.log myRoutes.reports.tables.show.path report_id = false
console.log myRoutes.reports.tables.show.path parentId: false
# if `(parentId or report_id): false` defined in contructor (best idea)
console.log myRoutes.reports.tables.show.path()
console.log myRoutes.reports.tables.path table_id: 321

You can get this with:

/reports
/reports
/reports/123

/reports/tables # :(
/reports/tables # :(
/reports/tables/:table_id
/reports/tables/:table_id

/reports/tables # :)
/reports/tables/321 # :)

See the requested routes:

In some cases is useful to set the parentId: false or \<Id\>: false in the contructor for DRY code

301 - Best practices

ñ00 Never point to master

BAD idea

<script src="https://cdn.rawgit.com/DFOXpro/trocha/master/dist/Trocha.min.js"></script>

GOOD idea

<script src="https://cdn.rawgit.com/DFOXpro/trocha/0.1.3/dist/Trocha.min.js"></script>

Wherever you use this library never point to master branch, use always an especific version of the library.

WHY?

Any change between versions (releases, revision, etc) may change the behavior of this library.

ñ01 Prefer JSON constructor

BAD idea

let myRoutes = new Trocha();
myRoutes._newRoute({args...});
...
myRoutes = new Trocha()
myRoutes._newRoute {args...}
...

GOOD idea

const myRoutes = new Trocha({
    routes: {... my routes ...}
});
myRoutes = new Trocha
    routes: {... my routes ...}

Always use the JSON constructor to declarate the routes tree, avoid the creation methods.

WHY?

ñ02 Use const

BAD idea

let myRoutes = new Trocha({
    routes: {... my routes ...}
});
myRoutes = new Trocha
    routes: {... my routes ...}
...

GOOD idea

const myRoutes = new Trocha({
    routes: {... my routes ...}
});
const myRoutes = new Trocha {... my routes ...} # for CS2

# for coffeescript vanilla :(
__myRoutes = {... my routes ...}
`const myRoutes = new Trocha({
    routes: __myRoutes
});
`
delete __myRoutes

Use variable type const

WHY?

ñ03 Use diferent trocha objects to diferent route scopes

BAD idea

const myRoutes = new Trocha({
    routes: {
        client routes ...
        serverA routes ...
        serverB routes ...
    }
});
myRoutes = new Trocha
    routes:
        client routes ...
        serverA routes ...
        serverB routes ...

GOOD idea

const clientRoutes = new Trocha({
    pre: '/the/templates/route',
    post: '_the_hash_and_ext.html',
    routes: {... client routes ...}
});
const serverARoutes = new Trocha({
    domain: 'https://api.serverA.net.co/',
    alwaysUrl: true,
    routes: {... serverA routes ...}
});
const serverBRoutes = new Trocha({
    domain: 'https://api.serverB.net.co/',
    alwaysUrl: true,
    routes: {... serverB routes ...}
});
clientRoutes = new Trocha {
    pre: '/the/templates/route'
    post: '_the_hash_and_ext.html'
    routes: {... client routes ...}
serverARoutes = new Trocha {
    domain: 'https://api.serverA.net.co/'
    alwaysUrl: true
    routes: {... serverA routes ...}
serverBRoutes = new Trocha {
    domain: 'https://api.serverB.net.co/'
    alwaysUrl: true
    routes: {... serverB routes ...}

If your project access to RESTful apis declare a trocha object per server, also use an exclusive object for client views

WHY?

ñ04 If posible use Trocha for(with) async cdns

BAD idea

loadAsyncCDN('www.myCDN.io/min.js');
loadAsyncCDN 'www.myCDN.io/min.js'

GOOD idea

myCDN = new Trocha({routes: min: 'www.myCDN.io/min.js'});
loadAsyncCDN(myCDN.min);
myCDN = new Trocha routes: min: 'www.myCDN.io/min.js'
loadAsyncCDN myCDN.min

If you use async libraries or technologies like AMD use trocha to point the cdn url

WHY?

302 - Vanilla

const handleRoute = (event) => {
    // Your awesome route handle
};

const replaceHref = () => {
    Array.prototype.forEach.call(document.getElementsByTagName("a"), (link) => {
        if(link.dataset.href){
            link.href = eval(
                "clientRoutes." +
                link.dataset.href
            ).path(
                link.dataset.path ? JSON.parse(link.dataset.path) : {}
            );
            link.onclick = handleRoute
        }
    });
};

window.onload = () => {
    replaceHref();
}
handleRoute = (event) ->
    # Your awesome route handle

replaceHref = ->
    Array.prototype.forEach.call document.getElementsByTagName("a"), (link) ->
        if link.dataset.href
            link.href = eval(
                "clientRoutes." + link.dataset.href
            ).path(
                `link.dataset.path ? JSON.parse(link.dataset.path) : {}`
            )
            link.onclick = handleRoute

window.onload = ->
    replaceHref()

If you want to use this library with Vanilla JS(my fav framework ;)) I recomend you to use pathjs to route handle. SEE TRIVIAL EXAMPLE HERE

In this example we write the links <a href > via onload function

303 - JQuery

const succcesAction = (msg) => {
    // Your awesome XHR success handler
};

const doJqueryXHR = (route, path, data) => {
    return $.ajax({
        method: route.$method,
        url: route.path(path),
        data: data
    })
};

doJqueryXHR(serverRoutes.posts.show,{args},{data}).done(succcesAction);
succcesAction = (msg) ->
    # Your awesome XHR success handler

doJqueryXHR = (route, path, data) ->
    $.ajax
        method: route.$method
        url: route.path path
        data: data

doJqueryXHR(serverRoutes.posts.show,{args},{data}).done succcesAction

SEE EXAMPLE HERE

In this example we use an ajax helper that include the route, the path parameters and the data it will send if any.

304 - Angular 1.X

The directive where we include trocha to our Angular project views via <a thref="ROUTE">...

app.directive( 'thref', () => {// Trocha href
    return {
        restrict: 'A',
        link: ($scope, elements, attrs) => {
            route = ROUTES.CLIENT;
            attrs.thref.split('.').forEach((r) => {
                route = route[r];
                if(!route) throw "Invalid thref route"
            });
            if(attrs.tpath)
                try {
                    attrs.tpath = JSON.parse(attrs.tpath)
                } catch(error){
                    console.error('Invalid tpath JSON', error)
                }
            if("string" == typeof route)
                elements[0].href = route; // @TODO in future release this will be obsolete
            else elements[0].href = '#!' + route.path(attrs.tpath)// default hashprefix since 1.6
        }
    }
});
app.directive 'thref', () ->
    restrict: 'A'
    link: ($s, elements, attrs) ->
        route = _routes.client
        attrs.thref.split('.').forEach (r) ->
            route = route[r]
            if !route
                throw "Invalid thref route"
        if attrs.tpath
            try
                attrs.tpath = JSON.parse attrs.tpath
            catch error
                console.error 'Invalid tpath JSON', error
        if "string" == typeof route
            elements[0].href = route # @TODO in future release this will be obsolete
        else
            elements[0].href = '#!' + route.path attrs.tpath # default hashprefix since 1.6
<a thref="trochaJSDocs">click here</a>
<a thref="users.list">Show users list</a>

The factory where we include trocha XHR helper to our Angular project

app.factory('$trocha', [
    '$http',
    ($http) => {
        var $trocha = new Trocha;
        $Trocha.CLIENT = ROUTES.CLIENT;
        $Trocha.SERVER = ROUTES.SERVER;
        $Trocha.xhr = (route, path, data) => {
            let args = {
                url: route.path(path),
                method: route.$method
            }
            if(data) args.data = data;
            return $http(args);
        }
        return $trocha;
    }
]);
app.factory '$trocha', [
    '$http',
    ($http) ->
        $trocha = new Trocha;
        $Trocha.CLIENT = ROUTES.CLIENT
        $Trocha.SERVER = ROUTES.SERVER
        $Trocha.xhr = (route, path, data) ->
            args =
                url: route.path path
                method: route.$method
            args.data = data if data
            $http args
        $trocha
]

The ngRoute config

app.config([
    '$routeProvider'
    ($routeProvider) => {
        $routeProvider.when(ROUTES.CLIENT.the.client.route.path(), {
            templateUrl: ROUTES.CLIENT.the.client.route.path({ext: true}),
            controller: ROUTES.CLIENT.the.client.route.$as
        })
    }
]);
app.config [
    '$routeProvider'
    ($routeProvider) ->
        $routeProvider.when ROUTES.CLIENT.the.client.route.path(),
            templateUrl: ROUTES.CLIENT.the.client.route.path {ext: true}
            controller: ROUTES.CLIENT.the.client.route.$as
]

The controller implementation

app.controller(ROUTES.CLIENT.the.client.route.$as, [
    '$scope', '$trocha', function($scope, $trocha) {
        $scope.data = {
            routes: $Trocha.CLIENT
        };
        $Trocha.xhr($Trocha.SERVER.the.server.route, {path args...}, {data...})
        .then(xhrSuccess, xhrFail);
    }
]);
app.controller ROUTES.CLIENT.the.client.route.$as, [
    '$scope', '$trocha', ($scope, $trocha) ->
        $scope.data =
            routes: $Trocha.CLIENT
        $Trocha.xhr $Trocha.SERVER.the.server.route, {path args...}, {data...}
        .then xhrSuccess, xhrFail
]

SEE EXAMPLE HERE

In this trivial example we use use the $http Angular service to make XHR request and ngRoute to handle routes and templates.

Note various things:

305 - Node

WIP :(

400 - Errors

401 - Route definition errors

402 - Route printing errors

403 - Trobleshoting

404 - Known bugs

418 - HTCPCP

Parce gracias por leerse toda esta documentación, ojalá un día nos tomemos un café con aguapanela.

419 - I’m a Fox

Any comment please tellme via email: dfoxpro at gmail

420 - Enhance Your Calm

Twitter:

You can tag this project via #trochajs, or my self via @dfoxpro

Licence

This project (the library and this documentation) is under Mozilla’s MPLv2.0

TLDR

FAQ

Mozilla Public License, version 2.0

1. Definitions

1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software.

1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution.

1.3. “Contribution” means Covered Software of a particular Contributor.

1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof.

1.5. “Incompatible With Secondary Licenses” means

that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or

that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License.

1.6. “Executable Form” means any form of the work other than Source Code Form.

1.7. “Larger Work” means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software.

1.8. “License” means this document.

1.9. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.

1.10. “Modifications” means any of the following:

any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or

any new file in Source Code Form that contains any Covered Software.

1.11. “Patent Claims” of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version.

1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses.

1.13. “Source Code Form” means the form of the work preferred for making modifications.

1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.

2. License Grants and Conditions

2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:

under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and

under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version.

2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution.

2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor:

for any code that a Contributor has removed from Covered Software; or

for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or

under Patent Claims infringed by Covered Software in the absence of its Contributions.

This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4).

2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3).

2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License.

2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.

2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1.

3. Responsibilities

3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form.

3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then:

such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and

You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License.

3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s).

3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies.

3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction.

4.

Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.

5. Termination

5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice.

5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.

5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination.

6.

Disclaimer of Warranty Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer.

7.

Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.

8.

Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims.

9.

Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor.

10. Versions of the License

10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number.

10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward.

10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License).

10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached.

Exhibit

Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

Exhibit B - “Incompatible With Secondary Licenses” Notice This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.