Skip to content

Commit

Permalink
fix(query): decode unicode params (#1871)
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz committed Jan 31, 2023
1 parent 5ae5480 commit 2fb6596
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 21 deletions.
33 changes: 16 additions & 17 deletions src/runtime/utils/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,7 @@ export function jsonStringify (value: any) {
* This function is equivalent to `JSON.parse`, but it also handles RegExp objects.
*/
export function jsonParse (value: string) {
return JSON.parse(value, (key, value) => {
const withOperator = (typeof value === 'string' && value.match(/^--([A-Z]+) (.+)$/)) || []

// Transforms RegExp string representation back to RegExp objects.
if (withOperator[1] === 'REGEX') {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags
const regex = withOperator[2].match(/\/(.*)\/([dgimsuy]*)$/)
return regex ? new RegExp(regex[1], regex[2] || '') : value
}

// Decode URI encoded path
if (key === '_path') {
return decodeURI(value)
}

return value
})
return JSON.parse(value, regExpReviver)
}

/**
Expand All @@ -39,3 +23,18 @@ function regExpReplacer (_key: string, value: any) {
}
return value
}

/**
* A function that transforms RegExp string representation back to RegExp objects.
*/
function regExpReviver (_key: string, value: any) {
const withOperator = (typeof value === 'string' && value.match(/^--([A-Z]+) (.+)$/)) || []

if (withOperator[1] === 'REGEX') {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags
const regex = withOperator[2].match(/\/(.*)\/([dgimsuy]*)$/)
return regex ? new RegExp(regex[1], regex[2] || '') : value
}

return value
}
4 changes: 2 additions & 2 deletions src/runtime/utils/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const getContentQuery = (event: H3Event): QueryBuilderParams => {

// Using /api/_content/query/:qid?_params=....
if (qid && query._params) {
memory[qid] = parseJSONQueryParams(query._params)
memory[qid] = parseJSONQueryParams(decodeURIComponent(query._params))

if (memory[qid].where && !Array.isArray(memory[qid].where)) {
memory[qid].where = [memory[qid].where as any as QueryBuilderWhere]
Expand All @@ -58,7 +58,7 @@ export const getContentQuery = (event: H3Event): QueryBuilderParams => {

// Using /api/_content/query?_params={{JSON_FORMAT}}
if (query._params) {
return parseJSONQueryParams(query._params)
return parseJSONQueryParams(decodeURIComponent(query._params))
}

// Using /api/_content/query?path=...&only=...
Expand Down
2 changes: 1 addition & 1 deletion test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('Basic usage', async () => {
})

test('Japanese path', async () => {
const html = await $fetch('/こんにちは')
const html = await $fetch('/' + encodeURIComponent('こんにちは'))
expect(html).contains('🎨 こんにちは')
})

Expand Down
12 changes: 11 additions & 1 deletion test/features/content-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const testContentQuery = () => {
params: { _params: JSON.stringify(params) }
})

const ids = docs.map(doc => doc._id)
const ids = docs.map((doc: any) => doc._id)

assert(ids.length > 0)
assert(ids.includes('content:index.md'))
Expand Down Expand Up @@ -61,6 +61,16 @@ export const testContentQuery = () => {
expect(content).includes('$$$$')
})

test('find `_path` and explude `index`', async () => {
const content = await $fetch('/features/query-content?prefix=&path=/cats&where={"_path":{"$ne":"/cats"}}')

expect(content).not.includes('cats:index.md')
expect(content).includes('cats:_dir.yml')
expect(content).includes('cats:bombay.md')
expect(content).includes('cats:persian.md')
expect(content).includes('cats:ragdoll.md')
})

// test `queryContent( PREFIX ).findOne()`
test('exact match foo/bar found', async () => {
const content = await $fetch('/features/query-content?path=/prefix/foo/bar&findOne=1')
Expand Down

0 comments on commit 2fb6596

Please sign in to comment.