Merge branch 'main' into next

This commit is contained in:
saltyaom
2026-01-14 11:23:12 +07:00
2 changed files with 170 additions and 8 deletions
+27 -8
View File
@@ -399,18 +399,37 @@ const hasReturn = (v: string | HookContainer<any> | Function) => {
? v.fn.toString()
: typeof v === 'string'
? v.toString()
: v
: v.toString()
const parenthesisEnd = fnLiteral.indexOf(')')
// Is direct arrow function return eg. () => 1
if (
fnLiteral.charCodeAt(parenthesisEnd + 2) === 61 &&
fnLiteral.charCodeAt(parenthesisEnd + 5) !== 123
) {
if (isObject) v.hasReturn = true
// Check for arrow function expression (direct return without braces)
// Handle both `) => x` and `)=>x` formats (with or without spaces)
const arrowIndex = fnLiteral.indexOf('=>', parenthesisEnd)
return true
if (arrowIndex !== -1) {
// Skip any whitespace after `=>` (space, tab, newline, carriage return)
let afterArrow = arrowIndex + 2
let charCode: number
while (
afterArrow < fnLiteral.length &&
((charCode = fnLiteral.charCodeAt(afterArrow)) === 32 || // space
charCode === 9 || // tab
charCode === 10 || // newline
charCode === 13) // carriage return
) {
afterArrow++
}
// If the first non-whitespace char after `=>` is not `{`, it's a direct return
if (
afterArrow < fnLiteral.length &&
fnLiteral.charCodeAt(afterArrow) !== 123
) {
if (isObject) v.hasReturn = true
return true
}
}
const result = fnLiteral.includes('return')
+143
View File
@@ -0,0 +1,143 @@
import { describe, expect, it } from 'bun:test'
import { Elysia } from '../../src'
describe('beforeHandle with arrow functions', () => {
it('should execute beforeHandle with arrow function expression', async () => {
let beforeHandleCalled = false
const app = new Elysia()
.get('/test', () => 'ok', {
// Arrow function expression (no braces) - this was broken with minified code
beforeHandle: () => {
beforeHandleCalled = true
}
})
const response = await app.handle(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(beforeHandleCalled).toBe(true)
})
it('should execute beforeHandle with arrow function returning value', async () => {
const app = new Elysia()
.get('/test', () => 'should not reach', {
// Arrow function expression that returns early
beforeHandle: () => 'intercepted'
})
const response = await app.handle(new Request('http://localhost/test'))
expect(await response.text()).toBe('intercepted')
})
it('should execute async beforeHandle with arrow function expression', async () => {
let beforeHandleCalled = false
const app = new Elysia()
.get('/test', () => 'ok', {
// Async arrow function expression
beforeHandle: async () => {
beforeHandleCalled = true
}
})
const response = await app.handle(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(beforeHandleCalled).toBe(true)
})
it('should execute beforeHandle with complex arrow expression', async () => {
let validatorCalled = false
const validator = () => {
validatorCalled = true
}
const app = new Elysia()
.get('/test', () => 'ok', {
// Complex arrow expression like: async ({status}) => requireSignature()({status})
// This pattern was broken when code is minified
beforeHandle: () => validator()
})
const response = await app.handle(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(validatorCalled).toBe(true)
})
it('should execute beforeHandle with arrow function block', async () => {
let beforeHandleCalled = false
const app = new Elysia()
.get('/test', () => 'ok', {
// Arrow function with block (this always worked)
beforeHandle: () => {
beforeHandleCalled = true
return
}
})
const response = await app.handle(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(beforeHandleCalled).toBe(true)
})
it('should handle multiple beforeHandle hooks with arrow expressions', async () => {
const callOrder: number[] = []
const app = new Elysia()
.get('/test', () => 'ok', {
beforeHandle: [
() => {
callOrder.push(1)
},
() => {
callOrder.push(2)
},
() => {
callOrder.push(3)
}
]
})
const response = await app.handle(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(callOrder).toEqual([1, 2, 3])
})
// Test with truly minified code (no spaces around arrow)
// This simulates what happens when code is bundled and minified
it('should execute beforeHandle with truly minified arrow function (no spaces)', async () => {
// Construct a function with no spaces: async()=>'intercepted'
// This is what real minifiers produce
const minifiedHandler = Function("return async()=>'intercepted'")()
const app = new Elysia().get('/test', () => 'should not reach', {
beforeHandle: minifiedHandler
})
const response = await app.handle(new Request('http://localhost/test'))
expect(await response.text()).toBe('intercepted')
})
// Test with actual HTTP server (not just app.handle)
it('should work with live server', async () => {
let beforeHandleCalled = false
const app = new Elysia()
.get('/test', () => 'ok', {
beforeHandle: () => {
beforeHandleCalled = true
}
})
.listen(0)
try {
const response = await fetch(
`http://localhost:${app.server?.port}/test`
)
expect(response.status).toBe(200)
expect(beforeHandleCalled).toBe(true)
} finally {
await app.stop()
}
})
})