1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | 1× 1× 1× 1× 1× 7× 5× 5× 5× 5× 5× 5× 5× 5× 5× 5× 4× 4× 2× 2× 2× 2× 2× 5× 1× 7× 7× 7× 7× 7× 7× 1× 6× 6× 6× 6× 30× 6× 5× 5× 5× 5× 5× 5× 5× | 'use strict'; const PATH = require('path'); const Memory = new WeakMap(); module.exports = {loader, getter}; function getter(self){ // There's no reason for the user to directly modify the routes // so, always return a copy of the original array. const routes = Memory.get(this).map(route => Object.assign({}, route)); this.debug(self.path, 'getter:routes', routes); return routes; } function loader(self, route){ // Validate route properties route = validator.call(this, self, route); const info = `${self.path}:${route.bundle.name}`; this.debug(info, 'init', route); // get the currently loaded routes const routes = Memory.get(this) || []; // Check if route bundle actually exists and require it const bundle$ = this.observable .of(route) .switchMap(route => this.util.rx .path(route.bundle.path) .isDir() .map(isDir => { if (isDir) route.bundle.path = PATH.join(route.bundle.path, 'index'); return route; })) .switchMap(route => this.util.rx .path(route.bundle.path + this.path.ext) .isFile() .map(isFile => { const {path, name} = route.bundle; if (!isFile) throw this.error(`Invalid bundle: ${name} (${path})`); // File exist, load the handler. const data = require(path); if (!this.util.is(data).function()) throw this.error.type({ name: `${info}.bundle:${name}`, type: 'function', data: data }); route.bundle.data = data; // make the bundle available on routes Memory.set(this, routes.concat(route)) this.debug(info, 'load', route); return route; })); // returns the route with parsed bundle return bundle$; } function validator(self, route){ const info = `${self.path}:route`; const methods = this.conf[self.name].methods; // Path Iif (!this.util.is(route.path).string()) throw this.error.type({ info: `${info}.path`, type: 'String', data: route.path }); // Methods if (!route.method) route.method = [methods[0].name]; const is = this.util.is(route.method); if (!is.string() && !is.array()) throw this.error.type({ name : `${info}.method`, type : 'String or Array', data : route.method }); Iif (is.string()) route.method = [route.method]; Iif (!route.method.length) throw this.error.type({ name : `${info}.method`, type : 'Non empty Array', data : route.method }); const types = []; route.method.forEach(method => { const avail = methods.filter(m => m.name === method); if (!avail.length) throw this.error.type({ name : `${info}.method`, type : `valid method (${avail.join(',')})`, data : method }); const type = avail.shift().type; Eif (types.indexOf(type) === -1) types.push(type); }); Iif (types.length > 1) throw this.error.type({ name: `${info}.method(type)`, type: 'same type', data: types }); route.type = types[0]; // Bundles Iif (!this.util.is(route.bundle).string()) throw this.error.type({ name: `${info}.bundle`, type: 'String', data: route.bundle }); route.bundle = { name: route.bundle, path: PATH.join(this.path.bundles, route.bundle.replace(/\//g, PATH.sep)) }; return route; } |