2020-03-11 12:34:34 +00:00
|
|
|
/**
|
|
|
|
* Router
|
|
|
|
*/
|
|
|
|
|
2021-07-05 17:54:00 +00:00
|
|
|
class Branch {
|
|
|
|
constructor() {
|
|
|
|
this.children = new Map()
|
|
|
|
this.paramName = null
|
|
|
|
this.fullparamName = null
|
|
|
|
this.handler = null
|
|
|
|
this.middlewares = []
|
|
|
|
}
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const __paramMapName = '__param'
|
2021-07-05 17:54:00 +00:00
|
|
|
const __fullParamMapName = '__fullparam'
|
|
|
|
|
|
|
|
export class FlaskaRouter {
|
|
|
|
constructor() {
|
|
|
|
this.root = new Branch()
|
|
|
|
}
|
|
|
|
|
|
|
|
addRoute(route, orgMiddlewares, orgHandler) {
|
|
|
|
if (route[0] !== '/')
|
|
|
|
throw new Error(`route "${route}" must start with forward slash`)
|
|
|
|
|
|
|
|
let middlewares = orgMiddlewares
|
|
|
|
let handler = orgHandler
|
|
|
|
if (!orgHandler) {
|
|
|
|
handler = orgMiddlewares
|
|
|
|
middlewares = []
|
|
|
|
}
|
|
|
|
if (middlewares && typeof(middlewares) === 'function') {
|
|
|
|
middlewares = [middlewares]
|
|
|
|
}
|
|
|
|
if (typeof(handler) !== 'function') {
|
|
|
|
throw new Error(`route "${route}" was missing a handler`)
|
|
|
|
}
|
|
|
|
|
|
|
|
let start = 1
|
|
|
|
let end = 1
|
|
|
|
let name = ''
|
|
|
|
let param = ''
|
|
|
|
let isParam = false
|
|
|
|
let isFullParam = false
|
|
|
|
let branch = this.root
|
|
|
|
|
|
|
|
if (route.indexOf(':') < 0) {
|
|
|
|
let name = route
|
|
|
|
if (name.length > 1 && name[name.length - 1] === '/') {
|
|
|
|
name = name.slice(0, -1)
|
|
|
|
}
|
|
|
|
let child = new Branch()
|
|
|
|
branch.children.set(name, child)
|
|
|
|
child.handler = handler
|
|
|
|
child.middlewares = middlewares
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 1; i <= route.length; i++) {
|
|
|
|
if ((i === route.length || route[i] === '/') && end > start) {
|
|
|
|
if (branch.fullparamName) {
|
|
|
|
throw new Error(`route "${route}" conflicts with a sub-branch that has a full param child`)
|
|
|
|
}
|
|
|
|
let child
|
|
|
|
name = route.substring(start, end)
|
|
|
|
if (isFullParam) {
|
|
|
|
param = name
|
|
|
|
name = __fullParamMapName
|
|
|
|
} else if (isParam) {
|
|
|
|
param = name
|
|
|
|
name = __paramMapName
|
|
|
|
}
|
|
|
|
if (branch.children.has(name)) {
|
|
|
|
child = branch.children.get(name)
|
|
|
|
}
|
|
|
|
else if (isParam && !isFullParam && branch.children.has(__fullParamMapName)) {
|
|
|
|
throw new Error(`route "${route}" conflicts with a sub-branch that has a full param child`)
|
|
|
|
}
|
|
|
|
else if (isFullParam && branch.children.has(__paramMapName)) {
|
|
|
|
throw new Error(`route "${route}" conflicts with a sub-branch that has a partial param child`)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
child = new Branch()
|
|
|
|
branch.children.set(name, child)
|
|
|
|
}
|
|
|
|
branch = child
|
|
|
|
end = i
|
|
|
|
start = i
|
|
|
|
if (isParam) {
|
|
|
|
if (branch.paramName && branch.paramName !== param) {
|
|
|
|
throw new Error(`route "${route}" conflicts with pre-existing param name of ${branch.paramName} instead of ${param}`)
|
|
|
|
}
|
|
|
|
if (isFullParam) {
|
|
|
|
branch.fullparamName = param
|
|
|
|
} else {
|
|
|
|
branch.paramName = param
|
|
|
|
}
|
|
|
|
isParam = false
|
|
|
|
}
|
|
|
|
} else if (route[i] === '/' && end === start) {
|
|
|
|
throw new Error(`route "${route}" has missing path name inbetween slashes`)
|
|
|
|
}
|
|
|
|
if (i === route.length) {
|
|
|
|
branch.handler = handler
|
|
|
|
branch.middlewares = middlewares
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if (route[i] === ':') {
|
|
|
|
if (isParam) {
|
|
|
|
isFullParam = true
|
|
|
|
}
|
|
|
|
isParam = true
|
|
|
|
end = start = i + 1
|
|
|
|
}
|
|
|
|
else if (route[i] === '/') {
|
|
|
|
end = start = i + 1
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
end++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-11 12:34:34 +00:00
|
|
|
|
2021-07-05 17:54:00 +00:00
|
|
|
match(orgUrl) {
|
|
|
|
let url = orgUrl
|
|
|
|
if (url.length > 1 && url[url.length - 1] === '/') {
|
|
|
|
url = url.slice(0, -1)
|
|
|
|
}
|
|
|
|
let branch = this.root
|
|
|
|
let start = 1
|
|
|
|
let end = 1
|
|
|
|
let output
|
|
|
|
let name
|
|
|
|
let char
|
|
|
|
let params = {}
|
|
|
|
if (output = branch.children.get(url)) {
|
|
|
|
return {
|
|
|
|
handler: output.handler,
|
|
|
|
middlewares: output.middlewares,
|
|
|
|
params: params,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (let i = 1; i <= url.length; i++) {
|
|
|
|
char = url[i]
|
|
|
|
if ((i === url.length || char === '/') && end > start) {
|
|
|
|
name = url.slice(start, end)
|
|
|
|
if (output = branch.children.get(name)) {
|
|
|
|
branch = output
|
|
|
|
}
|
|
|
|
else if (output = branch.children.get(__paramMapName)) {
|
|
|
|
branch = output
|
|
|
|
params[branch.paramName] = name
|
|
|
|
} else {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
end = start = i
|
|
|
|
char = url[i]
|
|
|
|
}
|
|
|
|
if (i >= url.length) {
|
|
|
|
return {
|
|
|
|
handler: branch.handler,
|
|
|
|
middlewares: branch.middlewares,
|
|
|
|
params: params,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (char === '/') {
|
|
|
|
end = start = i + 1
|
|
|
|
} else {
|
|
|
|
end++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function FlaskaRouter() {
|
|
|
|
this.root = new Branch()
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 17:54:00 +00:00
|
|
|
FlaskaRouter.prototype.addRoute = function(route, orgMiddlewares, orgHandler) {
|
2020-03-11 12:34:34 +00:00
|
|
|
if (route[0] !== '/')
|
2021-07-05 17:54:00 +00:00
|
|
|
throw new Error(`route "${route}" must start with forward slash`)
|
|
|
|
|
|
|
|
let middlewares = orgMiddlewares
|
|
|
|
let handler = orgHandler
|
|
|
|
if (!orgHandler) {
|
|
|
|
handler = orgMiddlewares
|
|
|
|
middlewares = []
|
|
|
|
}
|
|
|
|
if (middlewares && typeof(middlewares) === 'function') {
|
|
|
|
middlewares = [middlewares]
|
|
|
|
}
|
|
|
|
if (typeof(handler) !== 'function') {
|
|
|
|
throw new Error(`route "${route}" was missing a handler`)
|
|
|
|
}
|
|
|
|
|
|
|
|
let start = 1
|
|
|
|
let end = 1
|
|
|
|
let name = ''
|
|
|
|
let param = ''
|
|
|
|
let isParam = false
|
|
|
|
let isFullParam = false
|
|
|
|
let branch = this.root
|
|
|
|
|
|
|
|
if (route.indexOf(':') < 0) {
|
|
|
|
let name = route
|
|
|
|
if (name.length > 1 && name[name.length - 1] === '/') {
|
|
|
|
name = name.slice(0, -1)
|
|
|
|
}
|
|
|
|
let child = new Branch()
|
|
|
|
branch.children.set(name, child)
|
|
|
|
child.handler = handler
|
|
|
|
child.middlewares = middlewares
|
|
|
|
}
|
2020-03-11 12:34:34 +00:00
|
|
|
|
|
|
|
for (let i = 1; i <= route.length; i++) {
|
|
|
|
if ((i === route.length || route[i] === '/') && end > start) {
|
2021-07-05 17:54:00 +00:00
|
|
|
if (branch.fullparamName) {
|
|
|
|
throw new Error(`route "${route}" conflicts with a sub-branch that has a full param child`)
|
|
|
|
}
|
|
|
|
let child
|
|
|
|
name = route.substring(start, end)
|
|
|
|
if (isFullParam) {
|
|
|
|
param = name
|
|
|
|
name = __fullParamMapName
|
|
|
|
} else if (isParam) {
|
|
|
|
param = name
|
|
|
|
name = __paramMapName
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
2021-07-05 17:54:00 +00:00
|
|
|
if (branch.children.has(name)) {
|
|
|
|
child = branch.children.get(name)
|
|
|
|
}
|
|
|
|
else if (isParam && !isFullParam && branch.children.has(__fullParamMapName)) {
|
|
|
|
throw new Error(`route "${route}" conflicts with a sub-branch that has a full param child`)
|
|
|
|
}
|
|
|
|
else if (isFullParam && branch.children.has(__paramMapName)) {
|
|
|
|
throw new Error(`route "${route}" conflicts with a sub-branch that has a partial param child`)
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
else {
|
2021-07-05 17:54:00 +00:00
|
|
|
child = new Branch()
|
|
|
|
branch.children.set(name, child)
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
2021-07-05 17:54:00 +00:00
|
|
|
branch = child
|
|
|
|
end = i
|
|
|
|
start = i
|
2020-03-11 12:34:34 +00:00
|
|
|
if (isParam) {
|
2021-07-05 17:54:00 +00:00
|
|
|
if (branch.paramName && branch.paramName !== param) {
|
|
|
|
throw new Error(`route "${route}" conflicts with pre-existing param name of ${branch.paramName} instead of ${param}`)
|
|
|
|
}
|
|
|
|
if (isFullParam) {
|
|
|
|
branch.fullparamName = param
|
|
|
|
} else {
|
|
|
|
branch.paramName = param
|
|
|
|
}
|
|
|
|
isParam = false
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
2021-07-05 17:54:00 +00:00
|
|
|
} else if (route[i] === '/' && end === start) {
|
|
|
|
throw new Error(`route "${route}" has missing path name inbetween slashes`)
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
if (i === route.length) {
|
2021-07-05 17:54:00 +00:00
|
|
|
branch.handler = handler
|
|
|
|
branch.middlewares = middlewares
|
|
|
|
continue
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
if (route[i] === ':') {
|
2021-07-05 17:54:00 +00:00
|
|
|
if (isParam) {
|
|
|
|
isFullParam = true
|
|
|
|
}
|
|
|
|
isParam = true
|
|
|
|
end = start = i + 1
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
else if (route[i] === '/') {
|
2021-07-05 17:54:00 +00:00
|
|
|
end = start = i + 1
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
else {
|
2021-07-05 17:54:00 +00:00
|
|
|
end++
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-05 17:54:00 +00:00
|
|
|
FlaskaRouter.prototype.match = function(orgUrl) {
|
|
|
|
let url = orgUrl
|
|
|
|
if (url.length > 1 && url[url.length - 1] === '/') {
|
|
|
|
url = url.slice(0, -1)
|
|
|
|
}
|
|
|
|
let branch = this.root
|
|
|
|
let start = 1
|
|
|
|
let end = 1
|
|
|
|
let output
|
|
|
|
let name
|
|
|
|
let char
|
|
|
|
let params = {}
|
|
|
|
if (output = branch.children.get(url)) {
|
|
|
|
return {
|
|
|
|
handler: output.handler,
|
|
|
|
middlewares: output.middlewares,
|
|
|
|
params: params,
|
|
|
|
}
|
|
|
|
}
|
2020-03-11 12:34:34 +00:00
|
|
|
for (let i = 1; i <= url.length; i++) {
|
2021-07-05 17:54:00 +00:00
|
|
|
char = url[i]
|
2020-03-11 12:34:34 +00:00
|
|
|
if ((i === url.length || char === '/') && end > start) {
|
2021-07-05 17:54:00 +00:00
|
|
|
name = url.slice(start, end)
|
|
|
|
if (output = branch.children.get(name)) {
|
|
|
|
branch = output
|
|
|
|
}
|
|
|
|
else if (output = branch.children.get(__paramMapName)) {
|
|
|
|
branch = output
|
|
|
|
params[branch.paramName] = name
|
2020-03-11 12:34:34 +00:00
|
|
|
} else {
|
|
|
|
return null
|
|
|
|
}
|
2021-07-05 17:54:00 +00:00
|
|
|
i++
|
|
|
|
end = start = i
|
|
|
|
char = url[i]
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
if (i >= url.length) {
|
|
|
|
return {
|
2021-07-05 17:54:00 +00:00
|
|
|
handler: branch.handler,
|
|
|
|
middlewares: branch.middlewares,
|
|
|
|
params: params,
|
|
|
|
}
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
if (char === '/') {
|
2021-07-05 17:54:00 +00:00
|
|
|
end = start = i + 1
|
|
|
|
} else {
|
|
|
|
end++
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-05 17:54:00 +00:00
|
|
|
return null
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 17:54:00 +00:00
|
|
|
export function Flaska() {
|
|
|
|
|
2020-03-11 12:34:34 +00:00
|
|
|
}
|