From 2b1c2cdb5a8c5a069d7ab0dc4a67d50238282bd5 Mon Sep 17 00:00:00 2001
From: macabeus <bruno.macabeus@gmail.com>
Date: Sun, 22 Dec 2024 03:48:36 +0000
Subject: [PATCH 1/4] chore: avoid ts syntax highlighting issue in vscode

---
 src/compose.ts | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/src/compose.ts b/src/compose.ts
index e8cf2f56..5c11fd56 100644
--- a/src/compose.ts
+++ b/src/compose.ts
@@ -678,15 +678,13 @@ export const composeHandler = ({
 	}
 
 	if (hasQuery) {
-		const destructured = <
-			{
-				key: string
-				isArray: boolean
-				isNestedObjectArray: boolean
-				isObject: boolean
-				anyOf: boolean
-			}[]
-		>[]
+		const destructured = [] as {
+			key: string
+			isArray: boolean
+			isNestedObjectArray: boolean
+			isObject: boolean
+			anyOf: boolean
+		}[]
 
 		// @ts-ignore
 		if (validator.query && validator.query.schema.type === 'object') {

From 4f6086baa61880388952300408fa126f94dca463 Mon Sep 17 00:00:00 2001
From: macabeus <bruno.macabeus@gmail.com>
Date: Sun, 22 Dec 2024 03:49:04 +0000
Subject: [PATCH 2/4] chore: remove wrong `// @ts-expect-error`

---
 test/validator/query.test.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/test/validator/query.test.ts b/test/validator/query.test.ts
index 5c384b8f..7ff7f5d3 100644
--- a/test/validator/query.test.ts
+++ b/test/validator/query.test.ts
@@ -332,7 +332,6 @@ describe('Query Validator', () => {
 					check() {
 						const { state } = ctx.query
 
-						// @ts-expect-error
 						if (!checker.check(ctx, name, state ?? ctx.query.state))
 							throw new Error('State mismatch')
 					}

From 36e2b83f9e6a697b4335ded31b13d2e3d29fe648 Mon Sep 17 00:00:00 2001
From: macabeus <bruno.macabeus@gmail.com>
Date: Sun, 22 Dec 2024 03:49:27 +0000
Subject: [PATCH 3/4] fix: should not replace literal `+` with ` ` in the query
 string (#943)

---
 src/compose.ts               | 22 +++++++++++-----------
 test/validator/query.test.ts | 28 ++++++++++++++++++++++++----
 2 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/src/compose.ts b/src/compose.ts
index 5c11fd56..c621ab1f 100644
--- a/src/compose.ts
+++ b/src/compose.ts
@@ -746,7 +746,7 @@ export const composeHandler = ({
 		} else {
 			fnLiteral +=
 				'if(c.qi!==-1){' +
-				`let url = '&' + decodeURIComponent(c.url.slice(c.qi + 1))\n`
+				`let url = '&' + decodeURIComponent(c.url.slice(c.qi + 1).replaceAll('+', ' '))\n`
 
 			let index = 0
 			for (const {
@@ -774,8 +774,8 @@ export const composeHandler = ({
 							`else\n` +
 							`a${index}+=','\n` +
 							`let temp\n` +
-							`if(memory===-1)temp=decodeURIComponent(url.slice(start).replace(/\\+/g,' '))\n` +
-							`else temp=decodeURIComponent(url.slice(start, memory).replace(/\\+/g,' '))\n` +
+							`if(memory===-1)temp=decodeURIComponent(url.slice(start))\n` +
+							`else temp=decodeURIComponent(url.slice(start, memory))\n` +
 							`const charCode = temp.charCodeAt(0)\n` +
 							`if(charCode !== 91 && charCode !== 123)\n` +
 							`temp='"'+temp+'"'\n` +
@@ -798,10 +798,10 @@ export const composeHandler = ({
 							`if(a${index}===undefined)` +
 							`a${index}=[]\n` +
 							`if(memory===-1){` +
-							`a${index}.push(decodeURIComponent(url.slice(start)).replace(/\\+/g,' '))\n` +
+							`a${index}.push(decodeURIComponent(url.slice(start)))\n` +
 							`break` +
 							`}` +
-							`else a${index}.push(decodeURIComponent(url.slice(start, memory)).replace(/\\+/g,' '))\n` +
+							`else a${index}.push(decodeURIComponent(url.slice(start, memory)))\n` +
 							`memory=url.indexOf('&${key}=',memory)\n` +
 							`if(memory===-1) break\n` +
 							`}`
@@ -811,8 +811,8 @@ export const composeHandler = ({
 						`if(memory!==-1){` +
 						`const start=memory+${key.length + 2}\n` +
 						`memory=url.indexOf('&',start)\n` +
-						`if(memory===-1)a${index}=decodeURIComponent(url.slice(start).replace(/\\+/g,' '))` +
-						`else a${index}=decodeURIComponent(url.slice(start,memory).replace(/\\+/g,' '))` +
+						`if(memory===-1)a${index}=decodeURIComponent(url.slice(start))` +
+						`else a${index}=decodeURIComponent(url.slice(start,memory))` +
 						`if(a${index}!==undefined)` +
 						`try{` +
 						`a${index}=JSON.parse(a${index})` +
@@ -825,9 +825,9 @@ export const composeHandler = ({
 						`if(memory!==-1){` +
 						`const start=memory+${key.length + 2}\n` +
 						`memory=url.indexOf('&',start)\n` +
-						`if(memory===-1)a${index}=decodeURIComponent(url.slice(start).replace(/\\+/g,' '))\n` +
+						`if(memory===-1)a${index}=decodeURIComponent(url.slice(start))\n` +
 						`else{` +
-						`a${index}=decodeURIComponent(url.slice(start,memory).replace(/\\+/g,' '))`
+						`a${index}=decodeURIComponent(url.slice(start,memory))`
 
 					if (anyOf)
 						fnLiteral +=
@@ -840,8 +840,8 @@ export const composeHandler = ({
 							`if(first)first=false\n` +
 							`else deepMemory = url.indexOf('&', start)\n` +
 							`let value\n` +
-							`if(deepMemory===-1)value=decodeURIComponent(url.slice(start).replace(/\\+/g,' '))\n` +
-							`else value=decodeURIComponent(url.slice(start, deepMemory).replace(/\\+/g,' '))\n` +
+							`if(deepMemory===-1)value=decodeURIComponent(url.slice(start))\n` +
+							`else value=decodeURIComponent(url.slice(start, deepMemory))\n` +
 							`const vStart=value.charCodeAt(0)\n` +
 							`const vEnd=value.charCodeAt(value.length - 1)\n` +
 							`if((vStart===91&&vEnd===93)||(vStart===123&&vEnd===125))\n` +
diff --git a/test/validator/query.test.ts b/test/validator/query.test.ts
index 7ff7f5d3..73042b8d 100644
--- a/test/validator/query.test.ts
+++ b/test/validator/query.test.ts
@@ -703,7 +703,7 @@ describe('Query Validator', () => {
 		})
 	})
 
-	it('parse + in query', async () => {
+	it('parse query with space', async () => {
 		const api = new Elysia().get('', ({ query }) => query, {
 			query: t.Object({
 				keyword: t.String()
@@ -711,15 +711,35 @@ describe('Query Validator', () => {
 		})
 
 		const url = new URL('http://localhost:3000/')
-		url.searchParams.append('keyword', 'hello world')
-		console.log(url.href) //http://localhost:3000/?keyword=hello+world
+		url.searchParams.append('keyword', 'with space')
+		console.log(url.href) // http://localhost:3000/?keyword=with+space
 
 		const result = await api
 			.handle(new Request(url.href))
 			.then((response) => response.json())
 
 		expect(result).toEqual({
-			keyword: 'hello world'
+			keyword: 'with space'
+		})
+	})
+
+	it('parse query with +', async () => {
+		const api = new Elysia().get('', ({ query }) => query, {
+			query: t.Object({
+				keyword: t.String()
+			})
+		})
+
+		const url = new URL("http://localhost:3000/");
+		url.searchParams.append("keyword", "with+plus");
+		console.log(url.href) // http://localhost:3000/?keyword=with%2Bplus
+	
+		const result = await api
+			.handle(new Request(url.href))
+			.then((response) => response.json())
+
+		expect(result).toEqual({
+			keyword: 'with+plus'
 		})
 	})
 

From 188857279ecaadb64a089aa77523dc2c98e01bcb Mon Sep 17 00:00:00 2001
From: macabeus <bruno.macabeus@gmail.com>
Date: Mon, 6 Jan 2025 10:26:12 +0000
Subject: [PATCH 4/4] use replace instead replaceAll

---
 src/compose.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/compose.ts b/src/compose.ts
index c621ab1f..1dd6be6b 100644
--- a/src/compose.ts
+++ b/src/compose.ts
@@ -746,7 +746,7 @@ export const composeHandler = ({
 		} else {
 			fnLiteral +=
 				'if(c.qi!==-1){' +
-				`let url = '&' + decodeURIComponent(c.url.slice(c.qi + 1).replaceAll('+', ' '))\n`
+				`let url = '&' + decodeURIComponent(c.url.slice(c.qi + 1).replace(/\\+/g,' '))\n`
 
 			let index = 0
 			for (const {