buffer and charCodeAt impl
This commit is contained in:
parent
2e1dadbdea
commit
f48d63038d
10 changed files with 2966 additions and 450 deletions
117
benchmark/set_arr.mjs
Normal file
117
benchmark/set_arr.mjs
Normal file
|
@ -0,0 +1,117 @@
|
|||
import { summary, run, bench } from 'mitata';
|
||||
|
||||
// Warmup (de-optimize `bench()` calls)
|
||||
bench('noop', () => { });
|
||||
bench('noop2', () => { });
|
||||
|
||||
function padStart(length) {
|
||||
return ''.padStart(length * 2)
|
||||
}
|
||||
|
||||
const data = [
|
||||
'/',
|
||||
'/api/articles',
|
||||
'/api/articles/:id/file',
|
||||
'/api/articles/:id',
|
||||
'/api/articles/public',
|
||||
'/api/articles/public/:id',
|
||||
'/api/categories',
|
||||
'/api/categories/:categoryId/products',
|
||||
'/api/categories/:categoryId/properties',
|
||||
'/api/categories/:categoryId/values/:props',
|
||||
'/api/categories/:categoryId',
|
||||
//'/api/categories/:categoryId/products/:productId',
|
||||
'/api/categories/:categoryId/products/:productId',
|
||||
'/api/customers',
|
||||
'/api/customers/:id',
|
||||
'/api/customers/kennitala/:kennitala',
|
||||
'/api/customers/public/kennitala/:kennitala',
|
||||
'/api/customers/search/:search',
|
||||
'/api/file',
|
||||
'/api/file/:id',
|
||||
'/api/media',
|
||||
'/api/media/:id',
|
||||
'/api/orderitem',
|
||||
'/api/orderitem/:id',
|
||||
'/api/orders',
|
||||
'/api/orders/:orderId',
|
||||
'/api/orders/:orderId/sell',
|
||||
'/api/pages',
|
||||
'/api/pages/:pageId',
|
||||
'/api/pages/:pageId/articles',
|
||||
'/api/pages/:pageId/articles/public',
|
||||
'/api/products',
|
||||
'/api/products/:id',
|
||||
'/api/products/:id/movement',
|
||||
'/api/products/:id/sub_products/:productId',
|
||||
//'/api/products/:id/sub_products/:productId',
|
||||
'/api/products/code/:code',
|
||||
'/api/products/property/:propertyId',
|
||||
'/api/properties',
|
||||
'/api/properties/:id',
|
||||
'/api/sales',
|
||||
'/api/sales/:id',
|
||||
'/api/stockitem',
|
||||
'/api/stockitem/:id',
|
||||
'/api/stocks',
|
||||
'/api/stocks/:id',
|
||||
'/api/stocks/:id/commit',
|
||||
'/api/test',
|
||||
'/api/test/auth',
|
||||
'/api/test/error',
|
||||
'/api/workentries',
|
||||
'/api/workentries/:id',
|
||||
'/api/works',
|
||||
'/api/works/:id',
|
||||
'/api/works/:id/lock',
|
||||
'/api/works/public',
|
||||
'/api/staff',
|
||||
'/api/staff/:id',
|
||||
'/::rest',
|
||||
]
|
||||
|
||||
function arrIncludes(data) {
|
||||
let out = new Array()
|
||||
for (let item of data) {
|
||||
if (out.includes(item)) { break }
|
||||
out.push(item)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function setAdd(data) {
|
||||
let s = new Set()
|
||||
for (let item of data) {
|
||||
let size = s.size
|
||||
if (s.add(item).size === size) { break }
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
let func = [arrIncludes, setAdd];
|
||||
for (let fun of func) {
|
||||
console.log(`--- warming up ${fun.name || 'mapl'} ---`)
|
||||
for (var i = 0; i < 100; i++) {
|
||||
fun(data)
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise(res => setTimeout(res, 3000))
|
||||
|
||||
summary(() => {
|
||||
for (let i = 20; i >= 0; i--) {
|
||||
const dataSet = data.slice(0, data.length - i)
|
||||
|
||||
func.forEach(function(fun) {
|
||||
bench(`${dataSet.length} items: ${fun.name}`, function() {
|
||||
return fun(dataSet)
|
||||
})
|
||||
})
|
||||
}
|
||||
// console.log(tests, fun, tests.map(fun))
|
||||
/*bench(fun.name, function() {
|
||||
return fun(data)
|
||||
})*/
|
||||
})
|
||||
|
||||
run();
|
528
flaska.mjs
528
flaska.mjs
|
@ -37,16 +37,6 @@ export const MimeTypeDb = getDb()
|
|||
* Router
|
||||
*/
|
||||
|
||||
class Branch {
|
||||
constructor() {
|
||||
this.children = new Map()
|
||||
this.paramName = null
|
||||
this.fullparamName = null
|
||||
this.handler = null
|
||||
this.middlewares = []
|
||||
}
|
||||
}
|
||||
|
||||
export const ErrorCodes = {
|
||||
ERR_CONNECTION_ABORTED: 'ERR_CON_ABORTED'
|
||||
}
|
||||
|
@ -114,9 +104,9 @@ export function JsonHandler(org = {}) {
|
|||
ctx.req.body = {}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const data = Buffer.concat(buffers).toString();
|
||||
|
||||
|
||||
try {
|
||||
ctx.req.body = JSON.parse(data)
|
||||
} catch (err) {
|
||||
|
@ -145,7 +135,7 @@ export function CorsHandler(opts = {}) {
|
|||
// Always add vary header on origin. Prevent caches from
|
||||
// accidentally caching wrong preflight request
|
||||
ctx.headers['Vary'] = 'Origin'
|
||||
|
||||
|
||||
// Set status to 204 if OPTIONS. Just handy for flaska and
|
||||
// other checking.
|
||||
if (ctx.method === 'OPTIONS') {
|
||||
|
@ -228,7 +218,7 @@ export function FormidableHandler(formidable, org = {}) {
|
|||
|
||||
// For testing/stubbing purposes
|
||||
let rename = formidable.fsRename || fs.rename
|
||||
|
||||
|
||||
return function(ctx) {
|
||||
let form = formidable.IncomingForm()
|
||||
form.uploadDir = opts.uploadDir
|
||||
|
@ -263,7 +253,7 @@ export function FormidableHandler(formidable, org = {}) {
|
|||
keys.map(key => {
|
||||
let filename
|
||||
let target
|
||||
|
||||
|
||||
try {
|
||||
filename = opts.filename(ctx.req.files[key]) || ctx.req.files[key].name
|
||||
target = path.join(opts.uploadDir, filename)
|
||||
|
@ -386,7 +376,7 @@ export class FileResponse {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let ext = path.extname(this.filepath).slice(1)
|
||||
let found = MimeTypeDb[ext]
|
||||
if (found) {
|
||||
|
@ -403,190 +393,312 @@ export class FileResponse {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* --- Router ---
|
||||
*/
|
||||
|
||||
class RouterError extends Error {
|
||||
constructor(route1, route2, ...params) {
|
||||
// Pass remaining arguments (including vendor specific ones) to parent constructor
|
||||
super(...params);
|
||||
|
||||
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, RouterError);
|
||||
}
|
||||
|
||||
this.name = "RouterError";
|
||||
this.routeA = route1
|
||||
this.routeB = route2
|
||||
}
|
||||
}
|
||||
|
||||
function Child(split, x, i) {
|
||||
this.path = null
|
||||
this.isParams = split[x].isParams ? split[x].word : null
|
||||
this.isFullParams = split[x].isFullParams ? split[x].word : null
|
||||
this.paramVarName = split[x].paramVarName ?? null
|
||||
this.char = !this.isParams && !this.isFullParams ? split[x].word[i] || '/' : null
|
||||
this.count = 0
|
||||
this.children = []
|
||||
}
|
||||
|
||||
const regParamPrefix = /^::?/
|
||||
const regCleanNonAschii = /(?![a-zA-Z_])./g
|
||||
const regCleanRest = /_+/g
|
||||
const regStarDoubleParam = /::[^:/]+/g
|
||||
const regStarSingleParam = /:[^:/]+/g
|
||||
const SlashCode = '/'.charCodeAt(0)
|
||||
const spaces = ' '
|
||||
|
||||
export class FlaskaRouter {
|
||||
constructor() {
|
||||
this.root = new Branch()
|
||||
this.paths = []
|
||||
this.registeredPaths = new Set()
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
assertIsHandler(handler, 'addRoute()')
|
||||
|
||||
let start = 1
|
||||
let end = 1
|
||||
let name = ''
|
||||
let param = ''
|
||||
let isParam = false
|
||||
let isFullParam = false
|
||||
let branch = this.root
|
||||
|
||||
if (route.indexOf(':') < 0 && false) {
|
||||
let name = route
|
||||
if (name.length > 1 && name[name.length - 1] === '/') {
|
||||
name = name.slice(0, -1)
|
||||
addRoute(path, middlewares, orgHandler) {
|
||||
if (path[0] !== '/')
|
||||
throw new RouterError(null, null, `addRoute("${path}") path must start with forward slash`)
|
||||
|
||||
let cleaned = path
|
||||
if (cleaned.indexOf('/:') >= 0) {
|
||||
cleaned = cleaned.replace(regStarDoubleParam, '**').replace(regStarSingleParam, '*')
|
||||
if (cleaned.indexOf(':') > 0) {
|
||||
throw new RouterError(null, null, `addRoute("${path}") path has missing name or word between two forward slashes`)
|
||||
}
|
||||
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++
|
||||
if (cleaned.indexOf('**/') > 0) {
|
||||
throw new RouterError(null, null, `addRoute("${path}") cannot add anything after a full param route`)
|
||||
}
|
||||
}
|
||||
if (cleaned.indexOf('//') >= 0) {
|
||||
throw new RouterError(null, null, `addRoute("${path}") path has missing name or word between two forward slashes`)
|
||||
}
|
||||
|
||||
let size = this.registeredPaths.size
|
||||
if (this.registeredPaths.add(cleaned).size === size) {
|
||||
throw new RouterError(null, null, `addRoute("${path}") found an existing route with same path of ${cleaned}`)
|
||||
}
|
||||
|
||||
let handlers = []
|
||||
if (Array.isArray(middlewares)) {
|
||||
handlers.push(...middlewares)
|
||||
if (typeof(orgHandler) !== 'function') {
|
||||
throw new RouterError(orgHandler, null, `addRoute("${path}") was called with a handler that was not a function`)
|
||||
}
|
||||
} else {
|
||||
handlers.push(middlewares)
|
||||
}
|
||||
if (orgHandler) {
|
||||
handlers.push(orgHandler)
|
||||
}
|
||||
for (let handler of handlers) {
|
||||
if (typeof(handler) !== 'function') {
|
||||
throw new RouterError(handler, null, `addRoute("${path}") was called with a handler that was not a function`)
|
||||
}
|
||||
}
|
||||
|
||||
this.paths.push({
|
||||
path,
|
||||
handlers
|
||||
})
|
||||
}
|
||||
|
||||
match(orgUrl) {
|
||||
let url = orgUrl
|
||||
if (url.length > 1 && url[url.length - 1] === '/') {
|
||||
url = url.slice(0, -1)
|
||||
__buildChild(x, i, splitPaths) {
|
||||
let splitPath = splitPaths[0]
|
||||
let letter = new Child(splitPath.split, x, i)
|
||||
|
||||
let consume = []
|
||||
if (splitPath.split.length === x + 1
|
||||
&& (splitPath.split[x].isParams
|
||||
|| splitPath.split[x].isFullParams
|
||||
|| splitPath.split[x].word.length === i + 1)) {
|
||||
letter.path = splitPath.entry
|
||||
letter.count += 1
|
||||
} else {
|
||||
consume = [splitPath]
|
||||
}
|
||||
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 y = 1; y < splitPaths.length; y++) {
|
||||
let checkPath = splitPaths[y]
|
||||
if (!checkPath.split[x]
|
||||
|| checkPath.split[x].isParams !== splitPath.split[x].isParams
|
||||
|| checkPath.split[x].isFullParams !== splitPath.split[x].isFullParams
|
||||
|| !checkPath.split[x].isParams
|
||||
&& !checkPath.split[x].isFullParams
|
||||
&& (checkPath.split[x].word[i] || '/') !== letter.char) break
|
||||
consume.push(checkPath)
|
||||
}
|
||||
|
||||
letter.count += consume.length
|
||||
if (splitPath.split[x].word.length === i || splitPath.split[x].isParams || splitPath.split[x].isFullParams) {
|
||||
x++
|
||||
i = -1
|
||||
}
|
||||
while (consume.length) {
|
||||
letter.children.push(this.__buildChild(x, i + 1, consume))
|
||||
consume.splice(0, letter.children[letter.children.length - 1].count)
|
||||
}
|
||||
return letter
|
||||
}
|
||||
|
||||
__buildTree(splitPaths) {
|
||||
let builder = []
|
||||
while (splitPaths.length) {
|
||||
builder.push(this.__buildChild(0, 0, splitPaths))
|
||||
splitPaths.splice(0, builder[builder.length - 1].count)
|
||||
}
|
||||
return builder
|
||||
}
|
||||
|
||||
__splitAndSortPaths(paths, separateStatic = true) {
|
||||
let staticPaths = new Map()
|
||||
let paramsPaths = []
|
||||
let collator = new Intl.Collator('en', { sensitivity: 'accent' });
|
||||
|
||||
paths.forEach(function(entry) {
|
||||
if (entry.path[0] !== '/') throw new RouterError(entry, null, 'Specified route was missing forward slash at start')
|
||||
|
||||
// Collect static paths separately
|
||||
if (entry.path.indexOf('/:') < 0 && separateStatic) {
|
||||
return staticPaths.set(entry.path, {
|
||||
path: entry,
|
||||
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 if (output = branch.children.get(__fullParamMapName)) {
|
||||
params[output.fullparamName] = url.slice(start)
|
||||
|
||||
// Collect params path separately
|
||||
paramsPaths.push({
|
||||
split: entry.path.slice(1).split(/\//g).map(function(word) {
|
||||
let actualWord = word.replace(regParamPrefix, '')
|
||||
return {
|
||||
handler: output.handler,
|
||||
middlewares: output.middlewares,
|
||||
params: params,
|
||||
word: actualWord,
|
||||
isParams: word[0] === ':' && word[1] !== ':',
|
||||
isFullParams: word[0] === ':' && word[1] === ':',
|
||||
paramVarName: word[0] === ':'
|
||||
? actualWord.replace(regCleanNonAschii, '_').replace(regCleanRest, '_')
|
||||
: null
|
||||
}
|
||||
}),
|
||||
entry,
|
||||
})
|
||||
})
|
||||
paramsPaths.sort(function(aGroup, bGroup) {
|
||||
let length = Math.max(aGroup.split.length, bGroup.split.length)
|
||||
for (let x = 0; x < length; x++) {
|
||||
let a = aGroup.split[x]
|
||||
let b = bGroup.split[x]
|
||||
if (!a) return -1
|
||||
if (!b) return 1
|
||||
// Full params go last
|
||||
if (a.isFullParams && b.isFullParams) throw new RouterError(aGroup.entry, bGroup.entry, 'Two full path routes found on same level')
|
||||
if (a.isFullParams) return 1
|
||||
if (b.isFullParams) return -1
|
||||
// Params go second last
|
||||
if (a.isParams && !b.isParams) return 1
|
||||
if (!a.isParams && b.isParams) return -1
|
||||
// otherwise sort alphabetically if not identical
|
||||
if (a.word !== b.word) return collator.compare(a.word, b.word)
|
||||
}
|
||||
throw new RouterError(aGroup, bGroup, 'Two identical paths were found')
|
||||
})
|
||||
|
||||
return {
|
||||
staticPaths,
|
||||
paramsPaths,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__getIndex(offset, additions, params) {
|
||||
return (offset + additions)
|
||||
+ (params.length
|
||||
? ' + ' + params.map(a => `offset${a[1]}`).join(' + ')
|
||||
: '')
|
||||
}
|
||||
|
||||
__treeIntoCompiledCodeReturnPath(indentString, paths, branch, params) {
|
||||
let pathIndex = paths.indexOf(branch.path)
|
||||
if (pathIndex < 0) {
|
||||
throw new RouterError(branch.path, null, 'InternalError: Specified path was not found in paths')
|
||||
}
|
||||
let output = '\n' + indentString + `return {`
|
||||
output += '\n' + indentString + ` path: paths[${pathIndex}],`
|
||||
if (params.length) {
|
||||
output += '\n' + indentString + ` params: {`
|
||||
for (let param of params) {
|
||||
output += '\n' + indentString + ` ${param[0]}: s${param[1]},`
|
||||
}
|
||||
output += '\n' + indentString + ` },`
|
||||
} else {
|
||||
output += '\n' + indentString + ` params: {},`
|
||||
}
|
||||
output += '\n' + indentString + `}`
|
||||
return output
|
||||
}
|
||||
|
||||
__treeIntoCompiledCodeBranch(paths, branches, indent = 0, params = []) {
|
||||
let output = ''
|
||||
let indentation = spaces.slice(0, (indent - params.length) * 2)
|
||||
let addEndBracket = true
|
||||
|
||||
for (let i = 0; i < branches.length; i++) {
|
||||
let branch = branches[i]
|
||||
if (i > 0) {
|
||||
if (!branch.isParams && !branch.isFullParams) {
|
||||
output += ' else '
|
||||
} else {
|
||||
if (output = this.root.children.get(__fullParamMapName)) {
|
||||
params = {
|
||||
[output.fullparamName]: url.slice(1)
|
||||
}
|
||||
return {
|
||||
handler: output.handler,
|
||||
middlewares: output.middlewares,
|
||||
params: params,
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
i++
|
||||
end = start = i
|
||||
char = url[i]
|
||||
}
|
||||
// Check branch.handler. This can happen if route /::path is added
|
||||
// and request is '/' it will attempt to match root which will fail
|
||||
if (i >= url.length && branch.handler) {
|
||||
return {
|
||||
handler: branch.handler,
|
||||
middlewares: branch.middlewares,
|
||||
params: params,
|
||||
// output += '} //'
|
||||
output += '\n' + indentation
|
||||
}
|
||||
}
|
||||
if (char === '/') {
|
||||
end = start = i + 1
|
||||
|
||||
if (!branch.isParams && !branch.isFullParams) {
|
||||
output += `if (str.charCodeAt(${this.__getIndex(indent, 0, params)}) === ${branch.char.charCodeAt(0)}) { // ${branch.char}`
|
||||
|
||||
if (branch.path) {
|
||||
output += '\n' + indentation + ` if (str.length === ${this.__getIndex(indent, 1, params)}) {`
|
||||
output += this.__treeIntoCompiledCodeReturnPath(indentation + ' ', paths, branch, params)
|
||||
output += '\n' + indentation + ` }`
|
||||
}
|
||||
} else {
|
||||
end++
|
||||
addEndBracket = false
|
||||
let paramVarName = (params.length + 1) + '_' + branch.paramVarName
|
||||
output += `let s${paramVarName} = str.slice(${this.__getIndex(indent, 0, params)}${branch.isFullParams ? '' : `, str.indexOf('/', ${this.__getIndex(indent, 0, params)}) >>> 0`})`
|
||||
output += '\n' + indentation + `let offset${paramVarName} = s${paramVarName}.length`
|
||||
output += '\n' + indentation
|
||||
params.push([branch.isParams || branch.isFullParams, paramVarName])
|
||||
|
||||
if (branch.isFullParams) {
|
||||
output += this.__treeIntoCompiledCodeReturnPath(indentation, paths, branch, params)
|
||||
} else if (branch.path) {
|
||||
output += '\n' + indentation + `if (str.length === ${this.__getIndex(indent, 0, params)}) {`
|
||||
output += this.__treeIntoCompiledCodeReturnPath(indentation + ' ', paths, branch, params)
|
||||
output += '\n' + indentation + `}`
|
||||
}
|
||||
}
|
||||
|
||||
if (branch.children.length) {
|
||||
if (branch.path) {
|
||||
output += ' else '
|
||||
} else {
|
||||
output += '\n' + indentation + ' '
|
||||
}
|
||||
output += this.__treeIntoCompiledCodeBranch(paths, branch.children, indent + 1, params.slice())
|
||||
}
|
||||
if (addEndBracket) {
|
||||
output += '\n' + indentation + '} '
|
||||
}
|
||||
}
|
||||
if (output = this.root.children.get(__fullParamMapName)) {
|
||||
params = {
|
||||
[output.fullparamName]: url.slice(1)
|
||||
}
|
||||
return {
|
||||
handler: output.handler,
|
||||
middlewares: output.middlewares,
|
||||
params: params,
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
__treeIntoCompiledCodeClosure(paths, tree, staticList) {
|
||||
let output = 'return function RBufferStrSliceClosure(str) {'
|
||||
if (staticList.size > 0) {
|
||||
output += '\n let checkStatic = staticList.get(str)'
|
||||
output += '\n if(checkStatic) {'
|
||||
output += '\n return checkStatic'
|
||||
output += '\n }'
|
||||
}
|
||||
return null
|
||||
if (tree.length) {
|
||||
output += '\n ' + this.__treeIntoCompiledCodeBranch(paths, tree, 1, [])
|
||||
}
|
||||
output += '\n return null'
|
||||
output += '\n}'
|
||||
//console.log(output)
|
||||
return new Function('paths', 'staticList', output)(paths, staticList)
|
||||
}
|
||||
|
||||
compile() {
|
||||
let splitPaths = this.__splitAndSortPaths(this.paths)
|
||||
let tree = this.__buildTree(splitPaths.paramsPaths.slice())
|
||||
this.match = this.__treeIntoCompiledCodeClosure(this.paths, tree, splitPaths.staticPaths)
|
||||
}
|
||||
|
||||
match(url) {
|
||||
this.compile()
|
||||
return this.match(url)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -682,7 +794,7 @@ export class Flaska {
|
|||
for (let i = 0; i < this._nonces.length; i++) {
|
||||
this._nonces[i] = crypto.randomBytes(16).toString('base64')
|
||||
}
|
||||
|
||||
|
||||
constructFunction += `
|
||||
let nonce = this._nonces[this._noncesIndex] || crypto.randomBytes(16).toString('base64');
|
||||
this._noncesIndex--;
|
||||
|
@ -692,7 +804,7 @@ ctx.state.nonce = nonce;
|
|||
|
||||
constructFunction += 'ctx.headers = {'
|
||||
constructFunction += `'Date': new Date().toUTCString(),`
|
||||
for (let key of headerKeys) {
|
||||
for (let key of headerKeys) {
|
||||
if (key === 'Content-Security-Policy' && options.nonce.length) {
|
||||
let groups = options.defaultHeaders[key].split(';')
|
||||
for (let ni = 0; ni < options.nonce.length; ni++) {
|
||||
|
@ -754,12 +866,6 @@ ctx.state.nonce = nonce;
|
|||
this.patch = this.routers.PATCH.addRoute.bind(this.routers.PATCH)
|
||||
}
|
||||
|
||||
_assertIsHandler(handler, name) {
|
||||
if (typeof(handler) !== 'function') {
|
||||
throw new Error(`${name} was called with a handler that was not a function`)
|
||||
}
|
||||
}
|
||||
|
||||
devMode() {
|
||||
this._backuperror = this._onerror = function(err, ctx) {
|
||||
ctx.log.error(err)
|
||||
|
@ -795,7 +901,7 @@ ctx.state.nonce = nonce;
|
|||
assertIsHandler(handler, 'onreqerror()')
|
||||
this._onreqerror = handler
|
||||
}
|
||||
|
||||
|
||||
onreserror(handler) {
|
||||
assertIsHandler(handler, 'onreserror()')
|
||||
this._onreserror = handler
|
||||
|
@ -810,7 +916,7 @@ ctx.state.nonce = nonce;
|
|||
assertIsHandler(handler, 'beforeAsync()')
|
||||
this._beforeAsync.push(handler)
|
||||
}
|
||||
|
||||
|
||||
after(handler) {
|
||||
assertIsHandler(handler, 'after()')
|
||||
this._after.push(handler)
|
||||
|
@ -820,7 +926,7 @@ ctx.state.nonce = nonce;
|
|||
assertIsHandler(handler, 'afterAsync()')
|
||||
this._afterAsync.push(handler)
|
||||
}
|
||||
|
||||
|
||||
requestStart(req, res) {
|
||||
let url = req.url
|
||||
let search = ''
|
||||
|
@ -894,37 +1000,25 @@ ctx.state.nonce = nonce;
|
|||
|
||||
ctx.params = route.params
|
||||
|
||||
if (route.middlewares.length) {
|
||||
let middle = this.handleMiddleware(ctx, route.middlewares, 0)
|
||||
let handlers = this.runHandlers(ctx, route.path.handlers, 0)
|
||||
|
||||
if (middle && middle.then) {
|
||||
return middle.then(() => {
|
||||
return route.handler(ctx)
|
||||
})
|
||||
.then(() => {
|
||||
this.requestEnd(null, ctx)
|
||||
}, err => {
|
||||
this.requestEnd(err, ctx)
|
||||
})
|
||||
}
|
||||
}
|
||||
let handler = route.handler(ctx)
|
||||
if (handler && handler.then) {
|
||||
return handler.then(() => {
|
||||
if (handlers && handlers.then) {
|
||||
return handlers.then(() => {
|
||||
this.requestEnd(null, ctx)
|
||||
}, err => {
|
||||
this.requestEnd(err, ctx)
|
||||
})
|
||||
}
|
||||
|
||||
this.requestEnd(null, ctx)
|
||||
}
|
||||
|
||||
handleMiddleware(ctx, middles, index) {
|
||||
runHandlers(ctx, middles, index) {
|
||||
for (let i = index; i < middles.length; i++) {
|
||||
let res = middles[i](ctx)
|
||||
if (res && res.then) {
|
||||
return res.then(() => {
|
||||
return this.handleMiddleware(ctx, middles, i + 1)
|
||||
return this.runHandlers(ctx, middles, i + 1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -952,7 +1046,7 @@ ctx.state.nonce = nonce;
|
|||
return
|
||||
}
|
||||
|
||||
if (ctx.body === null && !handleUsed && ctx.status === 200) {
|
||||
if (ctx.body == null && !handleUsed && ctx.status === 200) {
|
||||
ctx.status = 204
|
||||
}
|
||||
|
||||
|
@ -989,7 +1083,7 @@ ctx.state.nonce = nonce;
|
|||
}
|
||||
|
||||
let length = 0
|
||||
|
||||
|
||||
if (body instanceof Buffer) {
|
||||
length = body.byteLength
|
||||
ctx.type = ctx.type || 'application/octet-stream'
|
||||
|
@ -1060,6 +1154,12 @@ ctx.state.nonce = nonce;
|
|||
this[`_${type}AsyncCompiled`] = func.bind(this, ...this[`_${type}Async`])
|
||||
}
|
||||
}
|
||||
this.routers.GET.compile()
|
||||
this.routers.POST.compile()
|
||||
this.routers.PUT.compile()
|
||||
this.routers.DELETE.compile()
|
||||
this.routers.OPTIONS.compile()
|
||||
this.routers.PATCH.compile()
|
||||
}
|
||||
|
||||
create() {
|
||||
|
@ -1069,7 +1169,7 @@ ctx.state.nonce = nonce;
|
|||
this.server.on('connection', function (socket) {
|
||||
// Set socket idle timeout in milliseconds
|
||||
socket.setTimeout(1000 * 60 * 5) // 5 minutes
|
||||
|
||||
|
||||
// Wait for timeout event (socket will emit it when idle timeout elapses)
|
||||
socket.on('timeout', function () {
|
||||
// Call destroy again
|
||||
|
@ -1090,7 +1190,7 @@ ctx.state.nonce = nonce;
|
|||
}
|
||||
|
||||
this.create()
|
||||
|
||||
|
||||
this.server.listen(port, ip, cb)
|
||||
}
|
||||
|
||||
|
@ -1121,7 +1221,7 @@ ctx.state.nonce = nonce;
|
|||
if (err) { return rej(err) }
|
||||
|
||||
// Waiting 0.1 second for it to close down
|
||||
setTimeout(function() { res() }, 100)
|
||||
setTimeout(res, 100)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
1229
flaska_buffer.mjs
Normal file
1229
flaska_buffer.mjs
Normal file
File diff suppressed because one or more lines are too long
1128
flaska_old.mjs
Normal file
1128
flaska_old.mjs
Normal file
File diff suppressed because one or more lines are too long
12
test.mjs
12
test.mjs
|
@ -1,12 +1,22 @@
|
|||
import { Flaska } from './flaska.mjs'
|
||||
|
||||
const port = 51024
|
||||
const port = 51026
|
||||
const flaska = new Flaska({}, )
|
||||
|
||||
flaska.devMode()
|
||||
|
||||
flaska.get('/', function(ctx) {
|
||||
ctx.body = { status: true }
|
||||
})
|
||||
|
||||
flaska.get('/:item/asdf/herp/:derp/bla', function(ctx) {
|
||||
ctx.body = { item: ctx.params.item }
|
||||
})
|
||||
|
||||
flaska.get('/a', function(ctx) {
|
||||
ctx.body = { status: true }
|
||||
})
|
||||
|
||||
flaska.get('/error', function(ctx) {
|
||||
process.exit(1)
|
||||
})
|
||||
|
|
|
@ -5,11 +5,11 @@ import { createCtx, fakeHttp } from './helper.mjs'
|
|||
const faker = fakeHttp()
|
||||
|
||||
t.describe('#constructor', function() {
|
||||
t.test('should be able to override the http', function() {
|
||||
t.test('should be able to override the http', function() {
|
||||
let flaska = new Flaska({}, faker)
|
||||
assert.strictEqual(flaska.http, faker)
|
||||
})
|
||||
|
||||
|
||||
t.test('it should have all the common verbs', function() {
|
||||
let flaska = new Flaska({}, faker)
|
||||
assert.ok(flaska.get)
|
||||
|
@ -25,7 +25,7 @@ t.describe('#constructor', function() {
|
|||
assert.ok(flaska.patch)
|
||||
assert.strictEqual(typeof(flaska.patch), 'function')
|
||||
})
|
||||
|
||||
|
||||
t.test('the verbs GET and HEAD should be identical', function() {
|
||||
let flaska = new Flaska({}, faker)
|
||||
assert.ok(flaska.get)
|
||||
|
@ -38,7 +38,7 @@ t.describe('#constructor', function() {
|
|||
t.test('should have before default header generator', function() {
|
||||
let flaska = new Flaska({}, faker)
|
||||
assert.strictEqual(flaska._before.length, 1)
|
||||
|
||||
|
||||
let ctx = {}
|
||||
|
||||
flaska._before[0](ctx)
|
||||
|
@ -78,7 +78,7 @@ t.describe('#constructor', function() {
|
|||
let ctx = {}
|
||||
|
||||
flaska._before[0](ctx)
|
||||
|
||||
|
||||
let keys = Object.keys(defaultHeaders)
|
||||
|
||||
assert.strictEqual(Object.keys(ctx.headers).length, keys.length + 1)
|
||||
|
@ -103,7 +103,7 @@ t.describe('#constructor', function() {
|
|||
let ctx = {}
|
||||
|
||||
flaska._before[0](ctx)
|
||||
|
||||
|
||||
assert.deepEqual(
|
||||
Object.keys(ctx.headers).sort(),
|
||||
['Server', 'Herp', 'X-Content-Type-Options','Content-Security-Policy','Cross-Origin-Opener-Policy','Cross-Origin-Resource-Policy','Cross-Origin-Embedder-Policy','Date'].sort()
|
||||
|
@ -140,7 +140,7 @@ t.describe('#_nonce', function() {
|
|||
set.add(entry)
|
||||
})
|
||||
assert.strictEqual(set.size, flaska._nonces.length)
|
||||
|
||||
|
||||
let ctx = createCtx()
|
||||
|
||||
assert.notOk(ctx.state.nonce)
|
||||
|
@ -148,12 +148,12 @@ t.describe('#_nonce', function() {
|
|||
let oldIndex = flaska._noncesIndex
|
||||
|
||||
flaska._before[0](ctx)
|
||||
|
||||
|
||||
assert.ok(ctx.state.nonce)
|
||||
assert.strictEqual(flaska._noncesIndex, oldIndex - 1)
|
||||
assert.strictEqual(flaska._nonces[oldIndex], ctx.state.nonce)
|
||||
|
||||
|
||||
|
||||
assert.strictEqual(ctx.headers['Server'], 'Flaska')
|
||||
assert.strictEqual(ctx.headers['X-Content-Type-Options'], 'nosniff')
|
||||
assert.strictEqual(ctx.headers['Content-Security-Policy'], `default-src 'self'; style-src 'self' 'unsafe-inline' 'nonce-${ctx.state.nonce}'; img-src * data: blob:; font-src 'self' data:; object-src 'none'; frame-ancestors 'none'; script-src 'nonce-${ctx.state.nonce}'`)
|
||||
|
@ -162,7 +162,7 @@ t.describe('#_nonce', function() {
|
|||
assert.strictEqual(ctx.headers['Cross-Origin-Embedder-Policy'], 'require-corp')
|
||||
assert.ok(new Date(ctx.headers['Date']).getDate())
|
||||
})
|
||||
|
||||
|
||||
t.test('should always return nonce values even if it runs out in cache', function() {
|
||||
let flaska = new Flaska({
|
||||
nonce: ['script-src'],
|
||||
|
@ -178,9 +178,9 @@ t.describe('#_nonce', function() {
|
|||
}
|
||||
|
||||
assert.notOk(flaska._nonces[flaska._noncesIndex])
|
||||
|
||||
|
||||
flaska._before[0](ctx)
|
||||
|
||||
|
||||
assert.notOk(flaska._nonces[flaska._noncesIndex])
|
||||
assert.ok(ctx.state.nonce)
|
||||
|
||||
|
@ -206,13 +206,13 @@ t.describe('#_nonce', function() {
|
|||
set.add(entry)
|
||||
})
|
||||
assert.strictEqual(set.size, 5)
|
||||
|
||||
|
||||
flaska._before[0](ctx)
|
||||
flaska._before[0](ctx)
|
||||
flaska._before[0](ctx)
|
||||
|
||||
assert.strictEqual(flaska._noncesIndex, 1)
|
||||
|
||||
|
||||
flaska._after[0](ctx)
|
||||
assert.strictEqual(flaska._noncesIndex, 2)
|
||||
set.add(flaska._nonces[flaska._noncesIndex])
|
||||
|
@ -227,7 +227,7 @@ t.describe('#_nonce', function() {
|
|||
assert.strictEqual(flaska._noncesIndex, 4)
|
||||
set.add(flaska._nonces[flaska._noncesIndex])
|
||||
assert.strictEqual(set.size, 8)
|
||||
|
||||
|
||||
flaska._after[0](ctx)
|
||||
assert.strictEqual(flaska._noncesIndex, 4)
|
||||
set.add(flaska._nonces[flaska._noncesIndex])
|
||||
|
@ -249,12 +249,12 @@ t.describe('#_nonce', function() {
|
|||
set.add(entry)
|
||||
})
|
||||
assert.strictEqual(set.size, 2)
|
||||
|
||||
|
||||
flaska._before[0](ctx)
|
||||
flaska._before[0](ctx)
|
||||
|
||||
assert.strictEqual(flaska._noncesIndex, -1)
|
||||
|
||||
|
||||
flaska._before[0](ctx)
|
||||
assert.strictEqual(flaska._noncesIndex, -2)
|
||||
set.add(ctx.state.nonce)
|
||||
|
@ -271,19 +271,19 @@ t.describe('#_nonce', function() {
|
|||
assert.strictEqual(set.size, 5)
|
||||
|
||||
assert.strictEqual(Object.keys(flaska._nonces).length, 2)
|
||||
|
||||
|
||||
flaska._after[0](ctx)
|
||||
assert.strictEqual(flaska._noncesIndex, 0)
|
||||
set.add(flaska._nonces[flaska._noncesIndex])
|
||||
assert.strictEqual(set.size, 6)
|
||||
assert.strictEqual(Object.keys(flaska._nonces).length, 2)
|
||||
|
||||
|
||||
flaska._after[0](ctx)
|
||||
assert.strictEqual(flaska._noncesIndex, 1)
|
||||
set.add(flaska._nonces[flaska._noncesIndex])
|
||||
assert.strictEqual(set.size, 7)
|
||||
assert.strictEqual(Object.keys(flaska._nonces).length, 2)
|
||||
|
||||
|
||||
flaska._after[0](ctx)
|
||||
assert.strictEqual(flaska._noncesIndex, 1)
|
||||
set.add(flaska._nonces[flaska._noncesIndex])
|
||||
|
@ -299,7 +299,7 @@ t.describe('#log', function() {
|
|||
assert.strictEqual(typeof(flaska.log.info), 'function')
|
||||
assert.strictEqual(typeof(flaska.log.warn), 'function')
|
||||
})
|
||||
|
||||
|
||||
t.test('allow overwriting in options', function() {
|
||||
const assertFunction = function() { return 1 }
|
||||
let flaska = new Flaska({ log: {
|
||||
|
@ -323,7 +323,7 @@ specialHandlers.forEach(function(type) {
|
|||
let flaska = new Flaska({}, faker)
|
||||
assert.strictEqual(typeof(flaska[type]), 'function')
|
||||
})
|
||||
|
||||
|
||||
t.test('validate handler', function() {
|
||||
let flaska = new Flaska({}, faker)
|
||||
assert.throws(function() { flaska[type]() }, /[Ff]unction/)
|
||||
|
@ -424,7 +424,7 @@ t.describe('_onerror', function() {
|
|||
const assertStatus = 431
|
||||
const assertBody = { a: 1 }
|
||||
const assertError = new HttpError(assertStatus, 'should not be seen', assertBody)
|
||||
|
||||
|
||||
let ctx = createCtx()
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska._onerror(assertError, ctx)
|
||||
|
@ -437,7 +437,7 @@ t.describe('_onerror', function() {
|
|||
t.test('default valid handling of HttpError with no body', function() {
|
||||
const assertStatus = 413
|
||||
const assertError = new HttpError(assertStatus, 'should not be seen')
|
||||
|
||||
|
||||
let ctx = createCtx()
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska._onerror(assertError, ctx)
|
||||
|
@ -453,7 +453,7 @@ t.describe('_onerror', function() {
|
|||
t.test('default valid handling of HttpError with missing status message', function() {
|
||||
const assertStatus = 432
|
||||
const assertError = new HttpError(assertStatus, 'should not be seen')
|
||||
|
||||
|
||||
let ctx = createCtx()
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska._onerror(assertError, ctx)
|
||||
|
@ -531,7 +531,7 @@ t.describe('#devMode()', function() {
|
|||
const assertStatus = 431
|
||||
const assertBody = { a: 1 }
|
||||
const assertError = new HttpError(assertStatus, 'should not be seen', assertBody)
|
||||
|
||||
|
||||
let ctx = createCtx()
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.devMode()
|
||||
|
@ -546,7 +546,7 @@ t.describe('#devMode()', function() {
|
|||
const assertStatus = 413
|
||||
const assertErrorMessage = 'A day'
|
||||
const assertError = new HttpError(assertStatus, assertErrorMessage)
|
||||
|
||||
|
||||
let ctx = createCtx()
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.devMode()
|
||||
|
@ -563,7 +563,7 @@ t.describe('#devMode()', function() {
|
|||
const assertStatus = 432
|
||||
const assertErrorMessage = 'Jet Coaster Ride'
|
||||
const assertError = new HttpError(assertStatus, assertErrorMessage)
|
||||
|
||||
|
||||
let ctx = createCtx()
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.devMode()
|
||||
|
@ -735,16 +735,16 @@ t.describe('#compile()', function() {
|
|||
})
|
||||
})
|
||||
|
||||
t.describe('#handleMiddleware()', function() {
|
||||
t.describe('#runHandlers()', function() {
|
||||
t.test('should work with empty array', function() {
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.handleMiddleware({}, [], 0)
|
||||
flaska.runHandlers({}, [], 0)
|
||||
})
|
||||
|
||||
t.test('should work with correct index', function() {
|
||||
let checkIsTrue = false
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.handleMiddleware({}, [
|
||||
flaska.runHandlers({}, [
|
||||
function() { throw new Error('should not be thrown') },
|
||||
function() { throw new Error('should not be thrown') },
|
||||
function() { throw new Error('should not be thrown') },
|
||||
|
@ -757,7 +757,7 @@ t.describe('#handleMiddleware()', function() {
|
|||
const assertCtx = createCtx({ a: 1 })
|
||||
let checkCounter = 0
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.handleMiddleware(assertCtx, [
|
||||
flaska.runHandlers(assertCtx, [
|
||||
function(ctx) { assert.strictEqual(ctx, assertCtx); checkCounter++ },
|
||||
function(ctx) { assert.strictEqual(ctx, assertCtx); checkCounter++ },
|
||||
function(ctx) { assert.strictEqual(ctx, assertCtx); checkCounter++ },
|
||||
|
@ -771,7 +771,7 @@ t.describe('#handleMiddleware()', function() {
|
|||
const assertCtx = createCtx({ a: 1 })
|
||||
let checkCounter = 0
|
||||
let flaska = new Flaska({}, faker)
|
||||
let result = flaska.handleMiddleware(assertCtx, [
|
||||
let result = flaska.runHandlers(assertCtx, [
|
||||
function(ctx) { assert.strictEqual(ctx, assertCtx); assert.strictEqual(checkCounter, 0); checkCounter++ },
|
||||
function(ctx) { assert.strictEqual(ctx, assertCtx); assert.strictEqual(checkCounter, 1); checkCounter++ },
|
||||
function(ctx) { return new Promise(function(res) { assert.strictEqual(ctx, assertCtx); assert.strictEqual(checkCounter, 2); checkCounter++; res() }) },
|
||||
|
@ -793,19 +793,19 @@ t.describe('#handleMiddleware()', function() {
|
|||
const assertError = { a: 1 }
|
||||
let checkCounter = 0
|
||||
let flaska = new Flaska({}, faker)
|
||||
let err = await assert.isRejected(flaska.handleMiddleware({}, [
|
||||
let err = await assert.isRejected(flaska.runHandlers({}, [
|
||||
function() { },
|
||||
function() { return new Promise(function(res, rej) { rej(assertError) }) },
|
||||
function() { throw new Error('should not be seen') },
|
||||
], 0))
|
||||
assert.strictEqual(err, assertError)
|
||||
err = await assert.isRejected(flaska.handleMiddleware({}, [
|
||||
err = await assert.isRejected(flaska.runHandlers({}, [
|
||||
function() { },
|
||||
function() { return Promise.reject(assertError) },
|
||||
function() { throw new Error('should not be seen') },
|
||||
], 0))
|
||||
assert.strictEqual(err, assertError)
|
||||
err = await assert.isRejected(flaska.handleMiddleware({}, [
|
||||
err = await assert.isRejected(flaska.runHandlers({}, [
|
||||
function() { },
|
||||
function() { return Promise.resolve() },
|
||||
function() { throw assertError },
|
||||
|
@ -977,7 +977,7 @@ t.describe('#listenAsync()', function() {
|
|||
assert.strictEqual(checkPort, assertPort)
|
||||
assert.strictEqual(checkIp, '::')
|
||||
})
|
||||
|
||||
|
||||
t.test('call http and listenAsync correctly if supported', async function() {
|
||||
const assertPort = 4632
|
||||
const assertIp = 'asdf'
|
||||
|
@ -1002,7 +1002,7 @@ t.describe('#listenAsync()', function() {
|
|||
assert.strictEqual(stubListenAsync.firstCall[0], assertPort)
|
||||
assert.strictEqual(stubListenAsync.firstCall[1], assertIp)
|
||||
})
|
||||
|
||||
|
||||
t.test('call http and listenAsync correctly if supported and ip is null', async function() {
|
||||
const assertPort = 325897235
|
||||
const assertReturns = { a: 1 }
|
||||
|
|
|
@ -30,7 +30,7 @@ t.describe('#requestStart()', function() {
|
|||
assert.strictEqual(onResError.callCount, 1)
|
||||
assert.strictEqual(onResError.firstCall[0], assertErrorTwo)
|
||||
assert.strictEqual(onResError.firstCall[1], ctx)
|
||||
|
||||
|
||||
assert.strictEqual(assertRes.on.secondCall[0], 'finish')
|
||||
assert.strictEqual(typeof(assertRes.on.secondCall[1]), 'function')
|
||||
assert.strictEqual(onEnded.callCount, 0)
|
||||
|
@ -220,7 +220,7 @@ t.describe('#requestStart()', function() {
|
|||
}), createRes())
|
||||
})
|
||||
|
||||
t.test('calls handleMiddleware correctly', function(cb) {
|
||||
t.test('calls handlers correctly', function(cb) {
|
||||
const assertError = new Error('test')
|
||||
const assertMiddles = [1, 2]
|
||||
const assertParams = { a: 1, b: 2 }
|
||||
|
@ -231,12 +231,11 @@ t.describe('#requestStart()', function() {
|
|||
|
||||
flaska.routers.GET.match = function() {
|
||||
return {
|
||||
handler: function() {},
|
||||
middlewares: assertMiddles,
|
||||
path: { handlers: assertMiddles, },
|
||||
params: assertParams,
|
||||
}
|
||||
}
|
||||
flaska.handleMiddleware = function(ctx, middles, index) {
|
||||
flaska.runHandlers = function(ctx, middles, index) {
|
||||
assert.strictEqual(index, 0)
|
||||
assert.strictEqual(middles, assertMiddles)
|
||||
checkMiddleCtx = ctx
|
||||
|
@ -265,7 +264,7 @@ t.describe('#requestStart()', function() {
|
|||
checkHandlerCtx = ctx
|
||||
throw assertError
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.get('/:id', handler)
|
||||
flaska.compile()
|
||||
|
@ -289,7 +288,7 @@ t.describe('#requestStart()', function() {
|
|||
let handler = function() {
|
||||
throw new Error('should not be called')
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.on404(on404Error)
|
||||
flaska.get('/test', function() { throw new Error('should not be called') })
|
||||
|
@ -307,7 +306,7 @@ t.describe('#requestStart()', function() {
|
|||
method: 'GET',
|
||||
}), createRes())
|
||||
})
|
||||
|
||||
|
||||
t.test('calls 404 if route handler is not found and supports promise', function(cb) {
|
||||
let checkCtx = null
|
||||
const assertError = new Error('should be seen')
|
||||
|
@ -315,7 +314,7 @@ t.describe('#requestStart()', function() {
|
|||
checkCtx = ctx
|
||||
return Promise.resolve().then(function() { return Promise.reject(assertError) })
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.on404(on404Error)
|
||||
flaska.get('/test', function() { throw new Error('should not be called') })
|
||||
|
@ -336,7 +335,7 @@ t.describe('#requestStart()', function() {
|
|||
t.test(`should handle unexpected errors in on404 correctly`, function(cb) {
|
||||
const assertError = new Error('should be seen')
|
||||
let checkCtx = null
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.on404(function(ctx) {
|
||||
checkCtx = ctx
|
||||
|
@ -360,7 +359,7 @@ t.describe('#requestStart()', function() {
|
|||
t.test(`should handle unexpected errors in middleware correctly`, function(cb) {
|
||||
const assertError = new Error('should be seen')
|
||||
let checkCtx = null
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
let middles = [function(ctx) {
|
||||
checkCtx = ctx
|
||||
|
@ -387,13 +386,10 @@ t.describe('#requestStart()', function() {
|
|||
assert.strictEqual(ctx.params.path, 'test/something/here')
|
||||
ctx.body = assertBody
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.get('/::path', handler)
|
||||
flaska.compile()
|
||||
flaska.handleMiddleware = function() {
|
||||
throw new Error('should not be called')
|
||||
}
|
||||
|
||||
flaska.requestEnd = cb.finish(function(err, ctx) {
|
||||
assert.notOk(err)
|
||||
|
@ -407,7 +403,7 @@ t.describe('#requestStart()', function() {
|
|||
}), createRes())
|
||||
})
|
||||
|
||||
t.test('calls handleMiddleware correctly if is promise', function(cb) {
|
||||
t.test('calls runHandlers correctly if is promise', function(cb) {
|
||||
const assertError = new Error('test')
|
||||
const assertMiddles = [1]
|
||||
|
||||
|
@ -416,11 +412,11 @@ t.describe('#requestStart()', function() {
|
|||
|
||||
flaska.routers.GET.match = function() {
|
||||
return {
|
||||
handler: function() {},
|
||||
path: { handlers: function() {}, },
|
||||
middlewares: assertMiddles,
|
||||
}
|
||||
}
|
||||
flaska.handleMiddleware = function() {
|
||||
flaska.runHandlers = function() {
|
||||
return Promise.resolve().then(function() { return Promise.reject(assertError) })
|
||||
}
|
||||
|
||||
|
@ -444,7 +440,7 @@ t.describe('#requestStart()', function() {
|
|||
checkHandlerCtx = ctx
|
||||
throw assertError
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.get('/:id', [function() { return Promise.resolve() }], handler)
|
||||
flaska.compile()
|
||||
|
@ -470,7 +466,7 @@ t.describe('#requestStart()', function() {
|
|||
checkHandlerCtx = ctx
|
||||
return Promise.resolve().then(function() { return Promise.reject(assertError) })
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.get('/:id', [function() { return Promise.resolve() }], handler)
|
||||
flaska.compile()
|
||||
|
@ -504,7 +500,7 @@ t.describe('#requestStart()', function() {
|
|||
ctx.body = assertBody
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.get('/::path', [middle], handler)
|
||||
flaska.compile()
|
||||
|
@ -521,7 +517,7 @@ t.describe('#requestStart()', function() {
|
|||
method: 'GET',
|
||||
}), createRes())
|
||||
})
|
||||
|
||||
|
||||
t.test('calls route handler correctly if promise', function(cb) {
|
||||
const assertError = new Error('test')
|
||||
let checkHandlerCtx = null
|
||||
|
@ -532,7 +528,7 @@ t.describe('#requestStart()', function() {
|
|||
return Promise.reject(assertError)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.get('/:id', handler)
|
||||
flaska.compile()
|
||||
|
@ -558,15 +554,11 @@ t.describe('#requestStart()', function() {
|
|||
ctx.body = assertBody
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
let flaska = new Flaska({}, faker)
|
||||
flaska.get('/::path', [], handler)
|
||||
flaska.compile()
|
||||
|
||||
flaska.handleMiddleware = function() {
|
||||
throw new Error('should not be called')
|
||||
}
|
||||
|
||||
flaska.requestEnd = cb.finish(function(err, ctx) {
|
||||
assert.notOk(err)
|
||||
assert.ok(ctx)
|
||||
|
|
|
@ -7,7 +7,7 @@ import { setTimeout } from 'timers/promises'
|
|||
import { Flaska, FormidableHandler, FileResponse } from '../flaska.mjs'
|
||||
import Client from './client.mjs'
|
||||
|
||||
const port = 51024
|
||||
const port = 51025
|
||||
const log = {
|
||||
fatal: stub(),
|
||||
error: stub(),
|
||||
|
@ -111,7 +111,7 @@ t.describe('/file', function() {
|
|||
|
||||
assert.ok(target.closed)
|
||||
assert.ok(file.closed)
|
||||
|
||||
|
||||
let [statSource, statTarget] = await Promise.all([
|
||||
fs.stat('./test/test.png'),
|
||||
fs.stat('./test_tmp.png'),
|
||||
|
@ -136,11 +136,11 @@ t.describe('/file', function() {
|
|||
assert.notOk(file.closed)
|
||||
|
||||
req.destroy()
|
||||
|
||||
|
||||
while (!file.closed) {
|
||||
await setTimeout(10)
|
||||
}
|
||||
|
||||
|
||||
assert.strictEqual(log.error.callCount, 0)
|
||||
assert.strictEqual(log.info.callCount, 0)
|
||||
|
||||
|
@ -195,7 +195,7 @@ t.describe('/filehandle', function() {
|
|||
assert.strictEqual(res.data, 'llo ')
|
||||
assert.strictEqual(res.headers['content-length'], '4')
|
||||
|
||||
|
||||
|
||||
res = await client.customRequest('GET', '/filehandle', null, { getRaw: true, agent: agent,
|
||||
headers: {
|
||||
'Range': 'bytes=0-0'
|
||||
|
@ -311,15 +311,15 @@ t.describe('HEAD', function() {
|
|||
t.describe('/file', function() {
|
||||
t.test('server return HEAD for pipes', async function() {
|
||||
log.error.reset()
|
||||
|
||||
|
||||
let res = await client.customRequest('HEAD', '/file', null, { getRaw: true, agent: agent })
|
||||
|
||||
|
||||
while (!file.closed) {
|
||||
await setTimeout(10)
|
||||
}
|
||||
|
||||
assert.ok(file.closed)
|
||||
|
||||
|
||||
let statSource = await fs.stat('./test/test.png')
|
||||
|
||||
assert.strictEqual(res.data, '')
|
||||
|
@ -328,37 +328,37 @@ t.describe('HEAD', function() {
|
|||
})
|
||||
t.test('server should autoclose body file handles on errors', async function() {
|
||||
reset()
|
||||
|
||||
|
||||
file = null
|
||||
|
||||
|
||||
let req = await client.customRequest('HEAD', '/file/leak', null, { returnRequest: true })
|
||||
|
||||
|
||||
req.end()
|
||||
|
||||
|
||||
while (!file) {
|
||||
await setTimeout(10)
|
||||
}
|
||||
|
||||
|
||||
assert.ok(file)
|
||||
assert.notOk(file.closed)
|
||||
|
||||
|
||||
req.destroy()
|
||||
|
||||
|
||||
while (!file.closed) {
|
||||
await setTimeout(10)
|
||||
}
|
||||
|
||||
|
||||
assert.strictEqual(log.error.callCount, 0)
|
||||
assert.strictEqual(log.info.callCount, 0)
|
||||
|
||||
|
||||
assert.ok(file.closed)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
t.describe('/filehandle', function() {
|
||||
t.test('server should send correctly', async function() {
|
||||
log.error.reset()
|
||||
|
||||
|
||||
let res = await client.customRequest('HEAD', '/filehandle', null, { getRaw: true, agent: agent })
|
||||
assert.strictEqual(res.status, 200)
|
||||
assert.strictEqual(res.headers['content-length'], '11')
|
||||
|
@ -369,7 +369,7 @@ t.describe('HEAD', function() {
|
|||
let etag = res.headers['etag']
|
||||
assert.ok(d.getTime())
|
||||
assert.strictEqual(res.data, '')
|
||||
|
||||
|
||||
res = await client.customRequest('HEAD', '/filehandle', null, { getRaw: true, agent: agent,
|
||||
headers: {
|
||||
'If-Modified-Since': d.toUTCString()
|
||||
|
@ -378,7 +378,7 @@ t.describe('HEAD', function() {
|
|||
assert.strictEqual(res.status, 304)
|
||||
assert.strictEqual(res.data, '')
|
||||
assert.strictEqual(res.headers['etag'], etag)
|
||||
|
||||
|
||||
res = await client.customRequest('HEAD', '/filehandle', null, { getRaw: true, agent: agent,
|
||||
headers: {
|
||||
'If-None-Match': etag
|
||||
|
@ -387,7 +387,7 @@ t.describe('HEAD', function() {
|
|||
assert.strictEqual(res.status, 304)
|
||||
assert.strictEqual(res.data, '')
|
||||
assert.strictEqual(res.headers['etag'], etag)
|
||||
|
||||
|
||||
res = await client.customRequest('HEAD', '/filehandle', null, { getRaw: true, agent: agent,
|
||||
headers: {
|
||||
'Range': 'bytes=2-5'
|
||||
|
@ -396,8 +396,8 @@ t.describe('HEAD', function() {
|
|||
assert.strictEqual(res.status, 206)
|
||||
assert.strictEqual(res.data, '')
|
||||
assert.strictEqual(res.headers['content-length'], '4')
|
||||
|
||||
|
||||
|
||||
|
||||
res = await client.customRequest('HEAD', '/filehandle', null, { getRaw: true, agent: agent,
|
||||
headers: {
|
||||
'Range': 'bytes=0-0'
|
||||
|
@ -407,7 +407,7 @@ t.describe('HEAD', function() {
|
|||
assert.strictEqual(res.data, '')
|
||||
assert.strictEqual(res.headers['content-length'], '1')
|
||||
})
|
||||
|
||||
|
||||
t.after(function() {
|
||||
agent.destroy()
|
||||
})
|
||||
|
|
|
@ -9,7 +9,7 @@ t.describe('#addRoute()', function() {
|
|||
assert.throws(function() { router.addRoute(':test') }, /forward slash/)
|
||||
assert.throws(function() { router.addRoute('test/test2') }, /forward slash/)
|
||||
})
|
||||
|
||||
|
||||
t.test('fail if missing handler', function() {
|
||||
let router = new FlaskaRouter()
|
||||
assert.throws(function() { router.addRoute('/') }, /handler/)
|
||||
|
@ -45,8 +45,21 @@ t.describe('#addRoute()', function() {
|
|||
router.addRoute('/:test/bla', function() {})
|
||||
router.addRoute('/bla/bla', function() {})
|
||||
router.addRoute('/bla/bla/bla', function() {})
|
||||
assert.throws(function() { router.addRoute('/:asdf/', function() {}) }, /param/)
|
||||
assert.throws(function() { router.addRoute('/:test/asdf/:foobar', function() {}) }, /param/)
|
||||
assert.throws(function() { router.addRoute('/:asdf', function() {}) }, /existing/)
|
||||
assert.throws(function() { router.addRoute('/:test/asdf/:foobar', function() {}) }, /existing/)
|
||||
})
|
||||
|
||||
t.test('fail if adding anything after a fullparam', function() {
|
||||
let router = new FlaskaRouter()
|
||||
assert.throws(function() { router.addRoute('/::bla/:bla', function() {}) }, /after/)
|
||||
assert.throws(function() { router.addRoute('/:test/::bla/test', function() {}) }, /after/)
|
||||
assert.throws(function() { router.addRoute('/::test/bla', function() {}) }, /after/)
|
||||
})
|
||||
|
||||
t.test('should work with param and full param side by side', function() {
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/:bla', function() {})
|
||||
router.addRoute('/::bla', function() {})
|
||||
})
|
||||
|
||||
t.test('fail if adding multiple fullparam', function() {
|
||||
|
@ -56,10 +69,8 @@ t.describe('#addRoute()', function() {
|
|||
router.addRoute('/:test/bla', function() {})
|
||||
router.addRoute('/:test/::bla', function() {})
|
||||
router.addRoute('/bla/bla/bla', function() {})
|
||||
assert.throws(function() { router.addRoute('/:test/asdf/::bla/fail', function() {}) }, /full.+param/)
|
||||
assert.throws(function() { router.addRoute('/:test/::bla/test', function() {}) }, /full.+param/)
|
||||
assert.throws(function() { router.addRoute('/:test/:bla', function() {}) }, /full.+param/)
|
||||
assert.throws(function() { router.addRoute('/::test', function() {}) }, /partial.+param/)
|
||||
assert.throws(function() { router.addRoute('/:test/asdf/::bla', function() {}) }, /existing/)
|
||||
assert.throws(function() { router.addRoute('/:test/::bla', function() {}) }, /existing/)
|
||||
})
|
||||
|
||||
t.test('add route correctly', function() {
|
||||
|
@ -67,39 +78,7 @@ t.describe('#addRoute()', function() {
|
|||
let router = new FlaskaRouter()
|
||||
router.addRoute('/a/b/c', assertHandler)
|
||||
let result = router.match('/a/b/c')
|
||||
assert.strictEqual(result.handler, assertHandler)
|
||||
})
|
||||
|
||||
t.test('add param route correctly', function() {
|
||||
let assertHandler = function() { return 1 }
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/a/:b/c', assertHandler)
|
||||
assert.ok(router.root.children.get('a'))
|
||||
assert.ok(router.root.children.get('a').children.get('__param'))
|
||||
assert.strictEqual(router.root.children.get('a').children.get('__param').paramName, 'b')
|
||||
assert.ok(router.root.children.get('a').children.get('__param').children.get('c'))
|
||||
assert.strictEqual(router.root.children.get('a').children.get('__param').children.get('c').handler, assertHandler)
|
||||
})
|
||||
|
||||
t.test('add full param route correctly', function() {
|
||||
let assertHandler = function() { return 1 }
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/a/::b', assertHandler)
|
||||
assert.ok(router.root.children.get('a'))
|
||||
assert.ok(router.root.children.get('a').children.get('__fullparam'))
|
||||
assert.strictEqual(router.root.children.get('a').children.get('__fullparam').fullparamName, 'b')
|
||||
assert.strictEqual(router.root.children.get('a').children.get('__fullparam').handler, assertHandler)
|
||||
})
|
||||
|
||||
t.test('add param route correctly', function() {
|
||||
let assertHandler = function() { return 1 }
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/a/:b/c', assertHandler)
|
||||
assert.ok(router.root.children.get('a'))
|
||||
assert.ok(router.root.children.get('a').children.get('__param'))
|
||||
assert.strictEqual(router.root.children.get('a').children.get('__param').paramName, 'b')
|
||||
assert.ok(router.root.children.get('a').children.get('__param').children.get('c'))
|
||||
assert.strictEqual(router.root.children.get('a').children.get('__param').children.get('c').handler, assertHandler)
|
||||
assert.strictEqual(result.path.handlers[0], assertHandler)
|
||||
})
|
||||
|
||||
t.test('support single middlewares correctly', function() {
|
||||
|
@ -107,10 +86,10 @@ t.describe('#addRoute()', function() {
|
|||
let assertMiddleware = function() { return 1 }
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/a', assertMiddleware, assertHandler)
|
||||
assert.ok(router.root.children.get('a'))
|
||||
assert.strictEqual(router.root.children.get('a').handler, assertHandler)
|
||||
assert.strictEqual(router.root.children.get('a').middlewares.length, 1)
|
||||
assert.strictEqual(router.root.children.get('a').middlewares[0], assertMiddleware)
|
||||
let result = router.match('/a')
|
||||
assert.strictEqual(result.path.handlers.length, 2)
|
||||
assert.strictEqual(result.path.handlers[0], assertMiddleware)
|
||||
assert.strictEqual(result.path.handlers[1], assertHandler)
|
||||
})
|
||||
|
||||
t.test('support multi middlewares correctly', function() {
|
||||
|
@ -119,15 +98,15 @@ t.describe('#addRoute()', function() {
|
|||
let router = new FlaskaRouter()
|
||||
router.addRoute('/a', [assertMiddleware], assertHandler)
|
||||
router.addRoute('/b', [assertMiddleware, assertMiddleware], assertHandler)
|
||||
assert.ok(router.root.children.get('a'))
|
||||
assert.strictEqual(router.root.children.get('a').handler, assertHandler)
|
||||
assert.strictEqual(router.root.children.get('a').middlewares.length, 1)
|
||||
assert.strictEqual(router.root.children.get('a').middlewares[0], assertMiddleware)
|
||||
assert.ok(router.root.children.get('b'))
|
||||
assert.strictEqual(router.root.children.get('b').handler, assertHandler)
|
||||
assert.strictEqual(router.root.children.get('b').middlewares.length, 2)
|
||||
assert.strictEqual(router.root.children.get('b').middlewares[0], assertMiddleware)
|
||||
assert.strictEqual(router.root.children.get('b').middlewares[1], assertMiddleware)
|
||||
let resultA = router.match('/a')
|
||||
assert.strictEqual(resultA.path.handlers.length, 2)
|
||||
assert.strictEqual(resultA.path.handlers[0], assertMiddleware)
|
||||
assert.strictEqual(resultA.path.handlers[1], assertHandler)
|
||||
let resultB = router.match('/b')
|
||||
assert.strictEqual(resultB.path.handlers.length, 3)
|
||||
assert.strictEqual(resultB.path.handlers[0], assertMiddleware)
|
||||
assert.strictEqual(resultB.path.handlers[1], assertMiddleware)
|
||||
assert.strictEqual(resultB.path.handlers[2], assertHandler)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -136,94 +115,47 @@ t.describe('#match()', function() {
|
|||
let assertMatched = false
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/test', function() { assertMatched = true })
|
||||
let result = router.match('/test')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
|
||||
// Test with extra slash at the end
|
||||
assertMatched = false
|
||||
result = router.match('/test/')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
let result = router.match('/test').path
|
||||
assert.strictEqual(result.handlers.length, 1)
|
||||
result.handlers[0]()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
})
|
||||
|
||||
|
||||
t.test('return middlewares', function() {
|
||||
t.test('return middlewares in handlers', function() {
|
||||
let assertMatched = false
|
||||
let assertMiddleware = function() { assertMatched = true }
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/test', assertMiddleware, function() { })
|
||||
let result = router.match('/test')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 1)
|
||||
result.middlewares[0]()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
|
||||
// Test with extra slash at the end
|
||||
assertMatched = false
|
||||
result = router.match('/test/')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 1)
|
||||
result.middlewares[0]()
|
||||
let result = router.match('/test').path
|
||||
assert.strictEqual(result.handlers.length, 2)
|
||||
result.handlers[0]()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
})
|
||||
|
||||
|
||||
t.test('match variable paths', function() {
|
||||
const assertParameter = 'bla'
|
||||
let assertMatched = false
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/test/:id', function() { assertMatched = true })
|
||||
let result = router.match('/test/' + assertParameter)
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
assert.strictEqual(result.params.id, assertParameter)
|
||||
|
||||
// Test with extra slash at the end
|
||||
assertMatched = false
|
||||
result = router.match('/test/' + assertParameter + '/')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
assert.strictEqual(result.path.handlers.length, 1)
|
||||
result.path.handlers[0]()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
assert.strictEqual(result.params.id, assertParameter)
|
||||
})
|
||||
|
||||
|
||||
t.test('match full path variable paths', function() {
|
||||
const assertParameter = 'bla/bla/bla'
|
||||
let assertMatched = false
|
||||
let router = new FlaskaRouter()
|
||||
router.addRoute('/test/::id', function() { assertMatched = true })
|
||||
let result = router.match('/test/' + assertParameter)
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
assert.strictEqual(result.params.id, assertParameter)
|
||||
|
||||
// Test with extra slash at the end
|
||||
assertMatched = false
|
||||
result = router.match('/test/' + assertParameter + '/')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
assert.strictEqual(result.path.handlers.length, 1)
|
||||
result.path.handlers[0]()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
assert.strictEqual(result.params.id, assertParameter)
|
||||
})
|
||||
|
||||
|
||||
t.test('match full path root path properly', function() {
|
||||
const assertParamFunc = function() { }
|
||||
const assertFullFunc = function() { }
|
||||
|
@ -231,15 +163,13 @@ t.describe('#match()', function() {
|
|||
router.addRoute('/test/:bla', assertParamFunc)
|
||||
router.addRoute('/::id', assertFullFunc)
|
||||
let result = router.match('/test/123')
|
||||
assert.strictEqual(result.handler, assertParamFunc)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
assert.strictEqual(result.path.handlers.length, 1)
|
||||
assert.strictEqual(result.path.handlers[0], assertParamFunc)
|
||||
assert.strictEqual(result.params.bla, '123')
|
||||
|
||||
result = router.match('/test/123/asdf')
|
||||
assert.strictEqual(result.handler, assertFullFunc)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
assert.strictEqual(result.path.handlers.length, 1)
|
||||
assert.strictEqual(result.path.handlers[0], assertFullFunc)
|
||||
assert.strictEqual(result.params.id, 'test/123/asdf')
|
||||
assert.notOk(result.params.bla)
|
||||
})
|
||||
|
@ -250,19 +180,8 @@ t.describe('#match()', function() {
|
|||
router.addRoute('/test/:id', function() { assertMatched = false })
|
||||
router.addRoute('/test/:id/test1', function() { })
|
||||
let result = router.match('/test/asdf/test1')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
assert.strictEqual(result.params.id, 'asdf')
|
||||
|
||||
// Test with extra slash at the end
|
||||
result = router.match('/test/asdf/test1/')
|
||||
assert.ok(result.handler)
|
||||
assert.ok(result.middlewares)
|
||||
assert.strictEqual(result.middlewares.length, 0)
|
||||
result.handler()
|
||||
assert.strictEqual(result.path.handlers.length, 1)
|
||||
result.path.handlers[0]()
|
||||
assert.strictEqual(assertMatched, true)
|
||||
assert.strictEqual(result.params.id, 'asdf')
|
||||
})
|
||||
|
@ -277,24 +196,25 @@ t.describe('#match()', function() {
|
|||
router.addRoute('/foo/::path', assertFunction)
|
||||
router.addRoute('/::path', assertFailFunction)
|
||||
|
||||
assert.strictEqual(router.match('/test/123').handler, assertFunction)
|
||||
assert.strictEqual(router.match('/test/asdfasdg').handler, assertFunction)
|
||||
assert.strictEqual(router.match('/test/test/sdafsda').handler, assertFunction)
|
||||
assert.strictEqual(router.match('/test/test/sdafsda/gdfshe4/43y34/wtaw').handler, assertFunction)
|
||||
assert.strictEqual(router.match('/foo/123').handler, assertFunction)
|
||||
assert.strictEqual(router.match('/foo/bar/baz/test').handler, assertFunction)
|
||||
assert.strictEqual(router.match('/test/123').path.handlers[0], assertFunction)
|
||||
assert.strictEqual(router.match('/test/asdfasdg').path.handlers[0], assertFunction)
|
||||
assert.strictEqual(router.match('/test/test/sdafsda').path.handlers[0], assertFunction)
|
||||
assert.strictEqual(router.match('/test/test/sdafsda/gdfshe4/43y34/wtaw').path.handlers[0], assertFunction)
|
||||
assert.strictEqual(router.match('/foo/123').path.handlers[0], assertFunction)
|
||||
assert.strictEqual(router.match('/foo/bar/baz/test').path.handlers[0], assertFunction)
|
||||
assert.ok(router.match('/test/123/yweherher/reher/h34h34/'))
|
||||
assert.strictEqual(router.match('/test/123/yweherher/reher/h34h34/').handler, assertFailFunction)
|
||||
assert.strictEqual(router.match('/test/123/yweherher/reher/h34h34/').path.handlers[0], assertFailFunction)
|
||||
assert.ok(router.match('/test/foo/bar'))
|
||||
assert.strictEqual(router.match('/test/foo/bar').handler, assertFailFunction)
|
||||
assert.strictEqual(router.match('/test/foo/bar').path.handlers[0], assertFailFunction)
|
||||
assert.ok(router.match('/'))
|
||||
assert.strictEqual(router.match('/').handler, assertFailFunction)
|
||||
assert.strictEqual(router.match('/').path.handlers[0], assertFailFunction)
|
||||
assert.ok(router.match('/something/else/goes/here'))
|
||||
assert.strictEqual(router.match('/something/else/goes/here').handler, assertFailFunction)
|
||||
assert.strictEqual(router.match('/something/else/goes/here').path.handlers[0], assertFailFunction)
|
||||
|
||||
router.addRoute('/', assertRootFunction)
|
||||
router.compile()
|
||||
assert.ok(router.match('/'))
|
||||
assert.strictEqual(router.match('/').handler, assertRootFunction)
|
||||
assert.strictEqual(router.match('/').path.handlers[0], assertRootFunction)
|
||||
})
|
||||
|
||||
t.test('return null when no match is found', function() {
|
||||
|
|
20
test_old.mjs
Normal file
20
test_old.mjs
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { Flaska } from './flaska_buffer.mjs'
|
||||
|
||||
const port = 51027
|
||||
const flaska = new Flaska({}, )
|
||||
|
||||
flaska.get('/', function(ctx) {
|
||||
ctx.body = { status: true }
|
||||
})
|
||||
|
||||
flaska.get('/:item/asdf/herp/:derp/bla', function(ctx) {
|
||||
ctx.body = { item: ctx.params.item }
|
||||
})
|
||||
|
||||
flaska.get('/error', function(ctx) {
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
flaska.listen(port, function() {
|
||||
console.log('listening on port', port)
|
||||
})
|
Loading…
Reference in a new issue