From c7499338ea979327cec1b559fca2dd3fa1ec7632 Mon Sep 17 00:00:00 2001 From: a0666660 <69061030+a0666660@users.noreply.github.com> Date: Thu, 1 Oct 2026 15:16:46 +0800 Subject: [PATCH] fix(url-tools): keep duplicate params, show fragment, add strict encoding --- src/tools/url-encoder/url-encoder.vue | 11 ++++++++++- src/tools/url-parser/url-parser.vue | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/tools/url-encoder/url-encoder.vue b/src/tools/url-encoder/url-encoder.vue index 19025190..48054b49 100644 --- a/src/tools/url-encoder/url-encoder.vue +++ b/src/tools/url-encoder/url-encoder.vue @@ -5,7 +5,16 @@ import { isNotThrowing } from '@/utils/boolean'; import { withDefaultOnError } from '@/utils/defaults'; const encodeInput = ref('Hello world :)'); -const encodeOutput = computed(() => withDefaultOnError(() => encodeURIComponent(encodeInput.value), '')); +// RFC 3986 also reserves !, ', (, ) and * which encodeURIComponent leaves as-is (#1445) +const encodeStrict = useStorage('url-encoder:strict', false); + +function strictEncode(value: string) { + return encodeURIComponent(value).replace(/[!'()*]/g, ch => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`); +} + +const encodeOutput = computed(() => + withDefaultOnError(() => (encodeStrict.value ? strictEncode(encodeInput.value) : encodeURIComponent(encodeInput.value)), ''), +); const encodedValidation = useValidation({ source: encodeInput, diff --git a/src/tools/url-parser/url-parser.vue b/src/tools/url-parser/url-parser.vue index 0799682f..12a0e980 100644 --- a/src/tools/url-parser/url-parser.vue +++ b/src/tools/url-parser/url-parser.vue @@ -21,6 +21,7 @@ const properties: { title: string; key: keyof URL }[] = [ { title: 'Port', key: 'port' }, { title: 'Path', key: 'pathname' }, { title: 'Params', key: 'search' }, + { title: 'Fragment', key: 'hash' }, ]; @@ -49,8 +50,8 @@ const properties: { title: string; key: keyof URL }[] = [ />