From 6d2dd791947869dd64364e72828da9c5a7070147 Mon Sep 17 00:00:00 2001 From: Camel Aissani Date: Fri, 15 Jul 2016 21:34:24 +0200 Subject: [PATCH] added jsdoc --- lib/application.js | 199 ++++++++++++++++++++++++++++++++++++--- lib/frontexpress.js | 16 ++++ lib/methods.js | 7 +- lib/middleware.js | 82 ++++++++++++++-- lib/requester.js | 21 +++++ lib/router.js | 133 ++++++++++++++++++++++++++ lib/settings.js | 38 ++++++++ test/application-test.js | 1 + 8 files changed, 477 insertions(+), 20 deletions(-) diff --git a/lib/application.js b/lib/application.js index e933c83..27796cd 100755 --- a/lib/application.js +++ b/lib/application.js @@ -1,23 +1,80 @@ +/** + * Module dependencies. + * @private + */ + import HTTP_METHODS from './methods'; import Settings from './settings'; import Router, {Route} from './router'; import Middleware from './middleware'; + +/** + * Application class. + */ + export default class Application { + + + /** + * Initialize the application. + * + * - setup default configuration + * + * @private + */ + constructor() { this.routers = []; this.DOMLoading = false; this.settings = new Settings(); } - //////////////////////////////////////////////////////// - // Settings - set(name, value) { + + /** + * Assign `setting` to `val`, or return `setting`'s value. + * + * app.set('foo', 'bar'); + * app.set('foo'); + * // => "bar" + * + * @param {String} setting + * @param {*} [val] + * @return {app} for chaining + * @public + */ + + set(...args) { + // get behaviour + if (args.length === 1) { + const name = [args]; + return this.settings.get(name); + } + + // set behaviour + const [name, value] = args; this.settings.set(name, value); + + return this; } - //////////////////////////////////////////////////////// - // Start listening requests + + /** + * Listen for DOM initialization and history state changes. + * + * The callback function is called once the DOM has + * the `document.readyState` equals to 'interactive'. + * + * app.listen(()=> { + * console.log('App is listening requests'); + * console.log('DOM is ready!'); + * }); + * + * + * @param {Function} callback + * @public + */ + listen(callback) { document.onreadystatechange = () => { const uri = window.location.pathname + window.location.search; @@ -48,14 +105,44 @@ export default class Application { }); } - //////////////////////////////////////////////////////// - // Routes + + /** + * Returns a new `Router` instance for the _uri_. + * See the Router api docs for details. + * + * app.route('/'); + * // => new Router instance + * + * @param {String} uri + * @return {Router} for chaining + * + * @public + */ + route(uri) { const router = new Router(uri); this.routers.push(router); return router; } + + /** + * Use the given middleware function or object, with optional _uri_. + * Default _uri_ is "/". + * + * // middleware function will be applied on path "/" + * app.use((req, res, next) => {console.log('Hello')}); + * + * // middleware object will be applied on path "/" + * app.use(new Middleware()); + * + * @param {String} uri + * @param {Middleware|Function} middleware or fn + * @return {app} for chaining + * + * @public + */ + use(...args) { if (args.length === 0) { throw new TypeError('use method takes at least a middleware or a router'); @@ -84,8 +171,18 @@ export default class Application { } } this.routers.push(router); + + return this; } + + /** + * Gather routes from all routers filtered by _uri_ and HTTP _method_. + * See Router#routes() documentation for details. + * + * @private + */ + _routes(uri, method) { const currentRoutes = []; for (const router of this.routers) { @@ -95,6 +192,15 @@ export default class Application { return currentRoutes; } + + /** + * Call `Middleware#entered` on _currentRoutes_. + * Invoked before sending ajax request or when DOM + * is loading (document.readyState === 'loading'). + * + * @private + */ + _callMiddlewareEntered(currentRoutes, request) { for (const route of currentRoutes) { if (route.middleware.entered) { @@ -106,6 +212,15 @@ export default class Application { } } + + /** + * Call `Middleware#updated` or middleware function on _currentRoutes_. + * Invoked on ajax request responding or on DOM ready + * (document.readyState === 'interactive'). + * + * @private + */ + _callMiddlewareUpdated(currentRoutes, request, response) { for (const route of currentRoutes) { route.visited = request; @@ -129,6 +244,14 @@ export default class Application { } } + + /** + * Call `Middleware#exited` on _currentRoutes_. + * Invoked before sending a new ajax request or before DOM unloading. + * + * @private + */ + _callMiddlewareExited() { // calls middleware exited method for (const router of this.routers) { @@ -142,6 +265,14 @@ export default class Application { } } + + /** + * Call `Middleware#failed` or middleware function on _currentRoutes_. + * Invoked when ajax request fails. + * + * @private + */ + _callMiddlewareFailed(currentRoutes, request, response) { for (const route of currentRoutes) { // calls middleware failed method @@ -164,8 +295,13 @@ export default class Application { } } - /////////////////////////////////////////////////////// - // Ajax request + + /** + * Make an ajax request. + * + * @private + */ + _fetch({method, uri, headers, data}, resolve, reject) { const httpMethodTransformer = this.get(`http ${method} transformer`); @@ -202,7 +338,30 @@ export default class Application { } HTTP_METHODS.reduce((reqProto, method) => { - // Middleware methods + + + /** + * Use the given middleware function or object, with optional _uri_ on + * HTTP methods: get, post, put, delete... + * Default _uri_ is "/". + * + * // middleware function will be applied on path "/" + * app.get((req, res, next) => {console.log('Hello')}); + * + * // middleware object will be applied on path "/" and + * app.get(new Middleware()); + * + * // get a setting value + * app.set('foo', 'bar'); + * app.get('foo'); + * // => "bar" + * + * @param {String} uri or setting + * @param {Middleware|Function} middleware or fn + * @return {app} for chaining + * @public + */ + const middlewareMethodName = method.toLowerCase(); reqProto[middlewareMethodName] = function(...args) { if (middlewareMethodName === 'get') { @@ -235,9 +394,27 @@ HTTP_METHODS.reduce((reqProto, method) => { router[middlewareMethodName](baseUri, middleware); this.routers.push(router); + + return this; }; - // HTTP methods + /** + * Ajax request (get, post, put, delete...). + * + * // HTTP GET method + * httpGet('/route1'); + * httpGet({uri: '/route1', data: {'p1': 'val1'}); + * // uri invoked => /route1?p1=val1 + * + * // HTTP POST method + * httpPost('/user'); + * ... + * + * @param {String|Object} uri or object containing uri, http headers, data + * @param {Function} success callback + * @param {Function} failure callback + * @public + */ const httpMethodName = 'http'+method.charAt(0).toUpperCase() + method.slice(1).toLowerCase(); reqProto[httpMethodName] = function(request, resolve, reject) { let {uri, headers, data} = request; diff --git a/lib/frontexpress.js b/lib/frontexpress.js index ceb3a77..89e7183 100755 --- a/lib/frontexpress.js +++ b/lib/frontexpress.js @@ -1,8 +1,24 @@ +/** + * Module dependencies. + */ + import Application from './application'; import Router from './router'; import Middleware from './middleware'; + +/** + * Create a frontexpress application. + * + * @return {Function} + * @api public + */ + const frontexpress = () => new Application(); + +/** + * Expose constructors. + */ frontexpress.Router = (baseUri) => new Router(baseUri); frontexpress.Middleware = (name) => new Middleware(name); diff --git a/lib/methods.js b/lib/methods.js index 0ab799e..092c785 100644 --- a/lib/methods.js +++ b/lib/methods.js @@ -1 +1,6 @@ -export default ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']; \ No newline at end of file +/** + * HTTP method list + * @private + */ + + export default ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']; \ No newline at end of file diff --git a/lib/middleware.js b/lib/middleware.js index d67bb3e..94d91b2 100755 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -1,19 +1,85 @@ +/** + * Middleware object. + * @public + */ + export default class Middleware { + + + /** + * Middleware initialization + * + * @param {String} middleware name + */ + constructor(name='') { this.name = name; } - entered(request) { - } + /** + * Invoked by the app before ajax request are sent or + * during the DOM loading (document.readyState === 'loading'). + * See Application#_callMiddlewareEntered documentation for details. + * + * Override this method to add your custom behaviour + * + * @param {Object} request + * @public + */ - exited(request) { - } + entered(request) { } - updated(request, response) { - } - failed(request, response) { - } + /** + * Invoked by the app before a new ajax request is sent or before the DOM unloading. + * See Application#_callMiddlewareExited documentation for details. + * + * Override this method to add your custom behaviour + * + * @param {Object} request + * @public + */ + + exited(request) { } + + + /** + * Invoked on ajax request responding or on DOM ready + * (document.readyState === 'interactive'). + * See Application#_callMiddlewareUpdated documentation for details. + * + * Override this method to add your custom behaviour + * + * @param {Object} request + * @param {Object} response + * @public + */ + + updated(request, response) { } + + + /** + * Invoked when ajax request fails. + * + * Override this method to add your custom behaviour + * + * @param {Object} request + * @param {Object} response + * @public + */ + failed(request, response) { } + + + /** + * Allow the hand over to the next middleware object or function. + * + * Override this method and return `false` to break execution of + * middleware chain. + * + * @return {Boolean} `true` by default + * + * @public + */ next() { return true; diff --git a/lib/requester.js b/lib/requester.js index ddd4561..f3859a8 100755 --- a/lib/requester.js +++ b/lib/requester.js @@ -1,5 +1,19 @@ +/** + * Module dependencies. + * @private + */ + export default class Requester { + /** + * Make an ajax request. + * + * @param {Object} request + * @param {Function} success callback + * @param {Function} failure callback + * @private + */ + fetch({method, uri, headers, data}, resolve, reject) { const success = (responseText) => { resolve( @@ -43,6 +57,13 @@ export default class Requester { } } + + /** + * Analyse response errors. + * + * @private + */ + _analyzeErrors(response) { // manage exceptions if (response.errorThrown) { diff --git a/lib/router.js b/lib/router.js index 0bb8d30..ab4603b 100755 --- a/lib/router.js +++ b/lib/router.js @@ -1,7 +1,26 @@ +/** + * Module dependencies. + * @private + */ + import HTTP_METHODS from './methods'; import Middleware from './middleware'; + +/** + * Route object. + * @private + */ + class Route { + + + /** + * Initialize the route. + * + * @private + */ + constructor(router, uriPart, method, middleware) { this.router = router; this.uriPart = uriPart; @@ -10,6 +29,13 @@ class Route { this.visited = false; } + + /** + * Return route's uri. + * + * @private + */ + get uri() { if (!this.uriPart && !this.method) { return undefined; @@ -35,7 +61,21 @@ class Route { } } + +/** + * Router object. + * @public + */ + export default class Router { + + + /** + * Initialize the router. + * + * @private + */ + constructor(uri) { if (uri) { this._baseUri = uri; @@ -43,6 +83,13 @@ export default class Router { this._routes = []; } + + /** + * Do some checks and set _baseUri. + * + * @private + */ + set baseUri(uri) { if (!uri) { return; @@ -62,15 +109,36 @@ export default class Router { } } + + /** + * Return router's _baseUri. + * + * @private + */ + get baseUri() { return this._baseUri; } + + /** + * Add a route to the router. + * + * @private + */ + _add(route) { this._routes.push(route); return this; } + + /** + * Gather routes from routers filtered by _uri_ and HTTP _method_. + * + * @private + */ + routes(uri, method) { return this._routes.filter((route) => { if (!route.uri && !route.method) { @@ -106,12 +174,35 @@ export default class Router { }); } + + /** + * Gather visited routes from routers. + * + * @private + */ + visited() { return this._routes.filter((route) => { return route.visited; }); } + + /** + * Use the given middleware function or object on this router. + * + * // middleware function + * router.use((req, res, next) => {console.log('Hello')}); + * + * // middleware object + * router.use(new Middleware()); + * + * @param {Middleware|Function} middleware or fn + * @return {Router} for chaining + * + * @public + */ + use(middleware) { if (!(middleware instanceof Middleware) && (typeof middleware !== 'function') ) { throw new TypeError('use method takes at least a middleware'); @@ -122,6 +213,23 @@ export default class Router { return this; } + + /** + * Use the given middleware function or object on this router for + * all HTTP methods. + * + * // middleware function + * router.all((req, res, next) => {console.log('Hello')}); + * + * // middleware object + * router.all(new Middleware()); + * + * @param {Middleware|Function} middleware or fn + * @return {Router} for chaining + * + * @public + */ + all(...args) { if (args.length === 0) { throw new TypeError('use all method takes at least a middleware'); @@ -146,6 +254,31 @@ export default class Router { } for (const method of HTTP_METHODS) { + + + /** + * Use the given middleware function or object, with optional _uri_ on + * HTTP methods: get, post, put, delete... + * Default _uri_ is "/". + * + * // middleware function will be applied on path "/" + * router.get((req, res, next) => {console.log('Hello')}); + * + * // middleware object will be applied on path "/" and + * router.get(new Middleware()); + * + * // middleware function will be applied on path "/user" + * router.post('/user', (req, res, next) => {console.log('Hello')}); + * + * // middleware object will be applied on path "/user" and + * router.post('/user', new Middleware()); + * + * @param {String} uri or setting + * @param {Middleware|Function} middleware or fn + * @return {Router} for chaining + * @public + */ + const methodName = method.toLowerCase(); Router.prototype[methodName] = function(...args) { if (args.length === 0) { diff --git a/lib/settings.js b/lib/settings.js index e11e593..04c5d3f 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -1,6 +1,27 @@ +/** + * Module dependencies. + * @private + */ + import Requester from './requester'; + +/** + * Settings object. + * @private + */ + export default class { + + + /** + * Initialize the settings. + * + * - setup default configuration + * + * @private + */ + constructor() { // default settings this.settings = { @@ -47,6 +68,15 @@ export default class { }; } + + /** + * Assign `setting` to `val` + * + * @param {String} setting + * @param {*} [val] + * @private + */ + set(name, value) { const checkRules = this.rules[name]; if (checkRules) { @@ -55,6 +85,14 @@ export default class { this.settings[name] = value; } + + /** + * Return `setting`'s value. + * + * @param {String} setting + * @private + */ + get(name) { return this.settings[name]; } diff --git a/test/application-test.js b/test/application-test.js index ab68cd8..5de87f4 100755 --- a/test/application-test.js +++ b/test/application-test.js @@ -114,6 +114,7 @@ describe('Application', () => { const app = frontexpress(); app.set('http requester', requester); assert(app.get('http requester') === requester); + assert(app.set('http requester') === requester); }); it('bad core setting', () => {