fyrejet
Version:
Web Framework for node.js that strives to provide (almost) perfect compatibility with Express, while providing better performance, where you need it.
119 lines (94 loc) • 3.56 kB
JavaScript
/**
* @see: https://github.com/jkyberneees/0http#0http---sequential-default-router
*/
const sequential = require('./sequential')
const methods = require('./methods')
const pathToRegexp = require('path-to-regexp')
const deprecate = require('depd')('fyrejet')
module.exports = (options, service = {}) => {
const routes = new Set()
const router = sequential(options)
router.paramHandlers = {}
router.availableMethodsForRoute = {} // needed to store data for potential OPTIONS request
// attach router id
service.id = router.id
// attach use method
router.useMiddleware = (path, ...fns) => {
if (!Array.isArray(path)) path = [path]
path.forEach(item => {
router.use(item, ...fns)
})
return service
}
function addMethodsToRouteMethodsList (urlPath, method) {
const urlPaths = [urlPath]
if (!service.get('strict routing')) {
if (urlPath[urlPath.length - 1] === '/') {
urlPaths.push(urlPath.slice(0, urlPath.length - 1))
} else {
urlPaths.push(urlPath + '/')
}
}
for (let n = 0; n < urlPaths.length; n++) {
const urlPath = urlPaths[n]
if (!router.availableMethodsForRoute[urlPath]) router.availableMethodsForRoute[urlPath] = []
if (!router.availableMethodsForRoute[urlPath].includes(method.toUpperCase()) && method !== 'all') router.availableMethodsForRoute[urlPath].push(method.toUpperCase())
if (router.availableMethodsForRoute[urlPath].length === 1) router.availableMethodsForRoute[urlPath].push('HEAD')
}
}
// attach routes registration shortcuts
methods.forEach((method) => {
service[method] = (...args) => {
if (args.length === 1) {
if (method === 'get') { // little hack
return service.set(args[0])
} else {
return service // no sense to create a route without handlers.
}
}
if (!Array.isArray(args[0])) {
args[0] = [args[0]]
}
// support multiple paths registration
const argsExceptPath = args.slice(1)
// for arch path
args[0].forEach(urlPath => {
let indRouteArgs = []
let keys = []
pathToRegexp(urlPath, keys)
keys = keys.map(x => x.name)
keys.forEach(key => {
if (router.paramHandlers.FYREJET_GLOBAL_PARAM) {
indRouteArgs = indRouteArgs.concat(router.paramHandlers.FYREJET_GLOBAL_PARAM)
}
if (router.paramHandlers[key]) {
indRouteArgs = indRouteArgs.concat(router.paramHandlers[key])
}
})
indRouteArgs = indRouteArgs.concat(argsExceptPath)
indRouteArgs.forEach(arg => {
if (typeof arg !== 'function' && arg !== 'api' && arg !== 'propsAsFns' && arg !== 'noEtag') {
throw new Error(capitalizeFirstLetter(typeof arg))
}
})
indRouteArgs.unshift(urlPath)
addMethodsToRouteMethodsList(urlPath, method)
routes.add(`${method.toUpperCase()}${indRouteArgs[0]}`)
router[method].apply(router, indRouteArgs)
})
return service
}
})
service.del = deprecate.function(service.delete, 'app.del: Use app.delete instead')
// attach router
service.getRouter = () => router
// attach routes
service.routes = () => [...routes]
service.lookup = (...args) => router.lookup.apply(router, args)
service.find = (...args) => router.find.apply(router, args)
return service
}
function capitalizeFirstLetter (string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}