From ba8e149fc61875291768b9d8d1410e9a6d7fa428 Mon Sep 17 00:00:00 2001 From: Michael Angstadt Date: Fri, 1 Aug 2014 10:05:48 -0500 Subject: [PATCH 1/4] Modified generator to handle windowless requests by accepting a optional parameter host. --- lib/generator.js | 213 ++++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 103 deletions(-) diff --git a/lib/generator.js b/lib/generator.js index c886d0e..c9f6bd0 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -1,142 +1,149 @@ var _ = require('lodash'); var url = require('url'); var querystring = require('querystring'); +var BasePlugin = require('mixdown-app').Plugin; if (typeof(global) === 'undefined') { var global = typeof(window) === 'undefined' ? {} : window; } -var Generator = function() {}; +module.exports = BasePlugin.extend({ + _namespace_default: 'route_generator', -/** -* Attaches a router plugin to an application. -* -**/ -Generator.prototype.attach = function (options) { - var app = options.app; + init: function(options) { + this._super(options); + }, + + // this allow the manifest to be set if the plugin is used outside of mixdown router. + // mixdown-router extends this class and overrides this method. + manifest: function(route_table) { + if (route_table) { + this.__route_table__ = route_table; + } + return this.__route_table__ || {}; + }, /** - * Initializes the routes for this application - * - **/ - var router = this.router || {}; + * Gets a url object for the given route and parameters. This is where you put your custom route generation. + * http://nodejs.org/api/url.html#url_url + **/ + url: function(route, params, host) { + params = params || {}; + + var uri = url.parse(''); + var routeObject = this.manifest()[route]; - _.extend(router, { + if (!routeObject) { + return 'Route Not Found - ' + route; + } - /** - * Gets a url object for the given route and parameters. This is where you put your custom route generation. - * http://nodejs.org/api/url.html#url_url - **/ - url: function(route, params) { - params = params || {}; + // if these are set on the route, then attach them. This will allow injection of FQ urls. + // this will allow polyfill of window object when in a browser. + // allow for host to be past directly when windowless + var _host = host || null; + var _port = null; - var uri = url.parse(''); - var routeObject = router.routes[route]; + if (_host != null) { + var host_split = _host.split(":"); - if (!routeObject) { - throw new Error('Route not found: ' + route); + if (host_split.length > 1) { + _port = host_split[1]; + _host = host_split[0]; } + } - // if these are set on the route, then attach them. This will allow injection of FQ urls. - // this will allow polyfill of window object when in a browser. - var location = global.location || {}; - uri.protocol = routeObject.protocol || location.protocol; - uri.hostname = routeObject.hostname || location.hostname; - uri.port = routeObject.hasOwnProperty('port') ? routeObject.port : location.port; - uri.method = routeObject.method || null; - uri.auth = routeObject.auth || null; - - // map the param fields to querystring as defined in route. - var queryParams = {}; - var restParams = {}; - - // split params into rest/query - _.each(routeObject.params, function (param, key) { - if (param.kind === 'rest') { - restParams[key] = param; - } - else if (param.kind === 'query') { - queryParams[key] = param; - } - }); + var location = global.location || {}; + uri.protocol = routeObject.protocol || location.protocol; + uri.hostname = routeObject.hostname || location.hostname || _host; + uri.port = routeObject.hasOwnProperty('port') ? routeObject.port : (location.port || _port); + uri.method = routeObject.method || null; + uri.auth = routeObject.auth || null; + + // map the param fields to querystring as defined in route. + var queryParams = {}; + var restParams = {}; + + // split params into rest/query + _.each(routeObject.params, function(param, key) { + if (param.kind === 'rest') { + restParams[key] = param; + } else if (param.kind === 'query') { + queryParams[key] = param; + } + }); - if (!_.isEmpty(queryParams)) { + if (!_.isEmpty(queryParams)) { - _.each(queryParams, function (param, key) { + _.each(queryParams, function(param, key) { - if (params.hasOwnProperty(key) || param['default']) { - uri.query = uri.query || {}; + if (params.hasOwnProperty(key) || param['default']) { + uri.query = uri.query || {}; - // replace capturing group with value - var qval = (param.enabled && params.hasOwnProperty(key) && params[key] !== null) ? params[key] : param['default']; - if (qval) { - uri.query[key] = param.regex.replace(/\(.*\)/, qval); - } + // replace capturing group with value + var qval = (params.hasOwnProperty(key) && params[key] !== null) ? params[key] : param['default']; + if (qval) { + uri.query[key] = param.regex.source.replace(/\(.*\)/, qval); } + } - }); - } + }); + } - // build the pathname. - uri.pathname = ''; + // build the pathname. + uri.pathname = ''; - // get url segments - // drop first element in array, since a leading slash creates an empty segment - var urlSegments = routeObject.path.split('/'); - urlSegments = urlSegments.length > 0 ? urlSegments.slice(1) : urlSegments; + // get url segments + // drop first element in array, since a leading slash creates an empty segment + var urlSegments = routeObject.path.split('/'); + urlSegments = urlSegments.length > 0 ? urlSegments.slice(1) : urlSegments; - // replace named params with corresponding values and generate uri - _.each(urlSegments, function (segment, i) { + // replace named params with corresponding values and generate uri + _.each(urlSegments, function(segment, i) { - // is this a REST segment? - if (/^\??:/.test(segment)) { + // is this a REST segment? + if (/^\??:/.test(segment)) { - // replace with param value if available. - var pName = segment.replace(/^\??:/, ''); - var pConfig = restParams[pName]; + // replace with param value if available. + var pName = segment.replace(/^\??:/, ''); + var pConfig = restParams[pName]; - if (pConfig && pConfig.kind === 'rest') { + if (pConfig && pConfig.kind === 'rest') { - // this is a rest param. replace the capturing group with our value. - var pval = (pConfig.enabled && params[pName]) ? params[pName] : pConfig['default']; - if (pval) { - uri.pathname += '/' + encodeURIComponent(pConfig.regex.replace(/\(.*\)/, pval)).replace(/(%2f)/gi, '/'); - } + // this is a rest param. replace the capturing group with our value. + var pval = params[pName] ? params[pName] : pConfig['default']; + if (pval) { + uri.pathname += '/' + encodeURIComponent(pConfig.regex.replace(/\(.*\)/, pval)).replace(/(%2f)/gi, '/'); + } else if (segment[0] === '?') { + uri.pathname += '/'; } } - else { - - // just append - uri.pathname += '/' + segment; - } - }); - - uri.search = uri.query ? '?' + querystring.stringify(uri.query) : null; - uri.path = uri.pathname + (uri.search || ''); - uri.host = uri.hostname ? (uri.hostname + (uri.port && uri.port != 80 ? ':' + uri.port : '')) : null; + } else { - return uri; - } + // just append + uri.pathname += '/' + segment; + } + }); - /** - * Gets a url as a string for the given route and parameters. This calls url() and stringifies the route. - * - **/ - , format: function(route, params) { - var u = router.url(route, params); - var routeObject = router.routes[route]; + uri.search = uri.query ? '?' + querystring.stringify(uri.query) : null; + uri.path = uri.pathname + (uri.search || ''); + uri.host = uri.hostname ? (uri.hostname + (uri.port && uri.port != 80 ? ':' + uri.port : '')) : null; - if (routeObject.browser === true || routeObject.browser === 'true') { - return u.path; - } + return uri; + }, - return url.format(u); + /** + * Gets a url as a string for the given route and parameters. This calls url() and stringifies the route. + * + **/ + format: function(route, params) { + var u = this.url(route, params); + var routeObject = this.manifest()[route]; + + if (routeObject && (routeObject.browser === true || routeObject.browser === 'true')) { + return u.path; } - , routes: options.routes - , params: options.params - - }); -}; + return url.format(u); + } -module.exports = Generator; +}); \ No newline at end of file From 2f821ccf17fa3261d10d9c89e0e058e03c29d219 Mon Sep 17 00:00:00 2001 From: Michael Angstadt Date: Sun, 3 Aug 2014 11:57:13 -0500 Subject: [PATCH 2/4] removed BasePlugin references, updated to fix manifest() and regex bug. 8 out of 8 test passing. --- lib/generator.js | 226 ++++++++++++++++++++++++----------------------- 1 file changed, 117 insertions(+), 109 deletions(-) diff --git a/lib/generator.js b/lib/generator.js index c9f6bd0..6eb7f56 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -1,149 +1,157 @@ var _ = require('lodash'); var url = require('url'); var querystring = require('querystring'); -var BasePlugin = require('mixdown-app').Plugin; if (typeof(global) === 'undefined') { var global = typeof(window) === 'undefined' ? {} : window; } -module.exports = BasePlugin.extend({ - _namespace_default: 'route_generator', +var Generator = function() {}; - init: function(options) { - this._super(options); - }, - - // this allow the manifest to be set if the plugin is used outside of mixdown router. - // mixdown-router extends this class and overrides this method. - manifest: function(route_table) { - if (route_table) { - this.__route_table__ = route_table; - } - return this.__route_table__ || {}; - }, +/** + * Attaches a router plugin to an application. + * + **/ +Generator.prototype.attach = function(options) { + var app = options.app; /** - * Gets a url object for the given route and parameters. This is where you put your custom route generation. - * http://nodejs.org/api/url.html#url_url + * Initializes the routes for this application + * **/ - url: function(route, params, host) { - params = params || {}; - - var uri = url.parse(''); - var routeObject = this.manifest()[route]; + var router = this.router || {}; - if (!routeObject) { - return 'Route Not Found - ' + route; - } + _.extend(router, { - // if these are set on the route, then attach them. This will allow injection of FQ urls. - // this will allow polyfill of window object when in a browser. - // allow for host to be past directly when windowless - var _host = host || null; - var _port = null; + /** + * Gets a url object for the given route and parameters. This is where you put your custom route generation. + * http://nodejs.org/api/url.html#url_url + **/ + url: function(route, params, host) { + params = params || {}; - if (_host != null) { - var host_split = _host.split(":"); + var uri = url.parse(''); + debugger; + var routeObject = this.routes[route]; - if (host_split.length > 1) { - _port = host_split[1]; - _host = host_split[0]; + if (!routeObject) { + return 'Route Not Found - ' + route; } - } - - var location = global.location || {}; - uri.protocol = routeObject.protocol || location.protocol; - uri.hostname = routeObject.hostname || location.hostname || _host; - uri.port = routeObject.hasOwnProperty('port') ? routeObject.port : (location.port || _port); - uri.method = routeObject.method || null; - uri.auth = routeObject.auth || null; - - // map the param fields to querystring as defined in route. - var queryParams = {}; - var restParams = {}; - - // split params into rest/query - _.each(routeObject.params, function(param, key) { - if (param.kind === 'rest') { - restParams[key] = param; - } else if (param.kind === 'query') { - queryParams[key] = param; + + // if these are set on the route, then attach them. This will allow injection of FQ urls. + // this will allow polyfill of window object when in a browser. + // allow for host to be past directly when windowless + var _host = host || null; + var _port = null; + + if (_host != null) { + var host_split = _host.split(":"); + + if (host_split.length > 1) { + _port = host_split[1]; + _host = host_split[0]; + } } - }); - if (!_.isEmpty(queryParams)) { + var location = global.location || {}; + uri.protocol = routeObject.protocol || location.protocol; + uri.hostname = routeObject.hostname || location.hostname || _host; + uri.port = routeObject.hasOwnProperty('port') ? routeObject.port : (location.port || _port); + uri.method = routeObject.method || null; + uri.auth = routeObject.auth || null; + + // map the param fields to querystring as defined in route. + var queryParams = {}; + var restParams = {}; + + // split params into rest/query + _.each(routeObject.params, function(param, key) { + if (param.kind === 'rest') { + restParams[key] = param; + } else if (param.kind === 'query') { + queryParams[key] = param; + } + }); - _.each(queryParams, function(param, key) { + if (!_.isEmpty(queryParams)) { - if (params.hasOwnProperty(key) || param['default']) { - uri.query = uri.query || {}; + _.each(queryParams, function(param, key) { - // replace capturing group with value - var qval = (params.hasOwnProperty(key) && params[key] !== null) ? params[key] : param['default']; - if (qval) { - uri.query[key] = param.regex.source.replace(/\(.*\)/, qval); + if (params.hasOwnProperty(key) || param['default']) { + uri.query = uri.query || {}; + + // replace capturing group with value + var qval = (params.hasOwnProperty(key) && params[key] !== null) ? params[key] : param['default']; + if (qval && param.regex) { + debugger; + uri.query[key] = param.regex.replace(/\(.*\)/, qval); + } } - } - }); - } + }); + } - // build the pathname. - uri.pathname = ''; + // build the pathname. + uri.pathname = ''; - // get url segments - // drop first element in array, since a leading slash creates an empty segment - var urlSegments = routeObject.path.split('/'); - urlSegments = urlSegments.length > 0 ? urlSegments.slice(1) : urlSegments; + // get url segments + // drop first element in array, since a leading slash creates an empty segment + var urlSegments = routeObject.path.split('/'); + urlSegments = urlSegments.length > 0 ? urlSegments.slice(1) : urlSegments; - // replace named params with corresponding values and generate uri - _.each(urlSegments, function(segment, i) { + // replace named params with corresponding values and generate uri + _.each(urlSegments, function(segment, i) { - // is this a REST segment? - if (/^\??:/.test(segment)) { + // is this a REST segment? + if (/^\??:/.test(segment)) { - // replace with param value if available. - var pName = segment.replace(/^\??:/, ''); - var pConfig = restParams[pName]; + // replace with param value if available. + var pName = segment.replace(/^\??:/, ''); + var pConfig = restParams[pName]; - if (pConfig && pConfig.kind === 'rest') { + if (pConfig && pConfig.kind === 'rest') { - // this is a rest param. replace the capturing group with our value. - var pval = params[pName] ? params[pName] : pConfig['default']; - if (pval) { - uri.pathname += '/' + encodeURIComponent(pConfig.regex.replace(/\(.*\)/, pval)).replace(/(%2f)/gi, '/'); - } else if (segment[0] === '?') { - uri.pathname += '/'; + // this is a rest param. replace the capturing group with our value. + var pval = params[pName] ? params[pName] : pConfig['default']; + if (pval) { + uri.pathname += '/' + encodeURIComponent(pConfig.regex.replace(/\(.*\)/, pval)).replace(/(%2f)/gi, '/'); + } else if (segment[0] === '?') { + uri.pathname += '/'; + } } + } else { + + // just append + uri.pathname += '/' + segment; } - } else { + }); - // just append - uri.pathname += '/' + segment; - } - }); + uri.search = uri.query ? '?' + querystring.stringify(uri.query) : null; + uri.path = uri.pathname + (uri.search || ''); + uri.host = uri.hostname ? (uri.hostname + (uri.port && uri.port != 80 ? ':' + uri.port : '')) : null; - uri.search = uri.query ? '?' + querystring.stringify(uri.query) : null; - uri.path = uri.pathname + (uri.search || ''); - uri.host = uri.hostname ? (uri.hostname + (uri.port && uri.port != 80 ? ':' + uri.port : '')) : null; + return uri; + }, - return uri; - }, + /** + * Gets a url as a string for the given route and parameters. This calls url() and stringifies the route. + * + **/ + format: function(route, params) { + var u = router.url(route, params); + var routeObject = router.routes[route]; - /** - * Gets a url as a string for the given route and parameters. This calls url() and stringifies the route. - * - **/ - format: function(route, params) { - var u = this.url(route, params); - var routeObject = this.manifest()[route]; + if (routeObject.browser === true || routeObject.browser === 'true') { + return u.path; + } + + return url.format(u); + }, + routes: options.routes, + params: options.params - if (routeObject && (routeObject.browser === true || routeObject.browser === 'true')) { - return u.path; - } + }); - return url.format(u); - } +}; -}); \ No newline at end of file +module.exports = Generator; \ No newline at end of file From 4ef7f45eb18086761cb95a6e476a37f43490d062 Mon Sep 17 00:00:00 2001 From: Michael Angstadt Date: Mon, 11 Jan 2016 08:44:16 -0600 Subject: [PATCH 3/4] Updated so the query parameter value of zero is valid. --- lib/generator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/generator.js b/lib/generator.js index 24ca252..4b2e668 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -80,7 +80,7 @@ module.exports = BasePlugin.extend({ // replace capturing group with value var qval = (params.hasOwnProperty(key) && params[key] !== null) ? params[key] : param['default']; - if (qval) { + if (typeof(qval) !== "undefined") { uri.query[key] = param.regex.source.replace(/\(.*\)/, qval); } } @@ -152,4 +152,4 @@ module.exports = BasePlugin.extend({ return url.format(u); } -}); \ No newline at end of file +}); From 9c318dd5f775466223cb48d9b1d016ef1bdefdd0 Mon Sep 17 00:00:00 2001 From: Michael Angstadt Date: Mon, 11 Jan 2016 09:02:51 -0600 Subject: [PATCH 4/4] updates from PR feedback. --- lib/generator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/generator.js b/lib/generator.js index 4b2e668..ab060be 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -80,7 +80,7 @@ module.exports = BasePlugin.extend({ // replace capturing group with value var qval = (params.hasOwnProperty(key) && params[key] !== null) ? params[key] : param['default']; - if (typeof(qval) !== "undefined") { + if (qval != "") { uri.query[key] = param.regex.source.replace(/\(.*\)/, qval); } }