From 6e01e23759600cf022da261fe3d8e1958bb27cc8 Mon Sep 17 00:00:00 2001 From: Kevin Deng Date: Thu, 20 Aug 2026 02:47:40 +0900 Subject: [PATCH] Validate Unicode scalar values before character lookup (#1) --- app/composables/chars.ts | 5 ++++- app/utils/unicode.ts | 6 ++++++ scripts/tests/unicode.test.ts | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 app/utils/unicode.ts create mode 100644 scripts/tests/unicode.test.ts diff --git a/app/composables/chars.ts b/app/composables/chars.ts index 13e99af..33e97c0 100644 --- a/app/composables/chars.ts +++ b/app/composables/chars.ts @@ -7,6 +7,7 @@ import { type CharsData, type Region, } from '~~/shared/types.ts' +import { isUnicodeScalarValue } from '~/utils/unicode.ts' import { asList, asOneOf, @@ -222,7 +223,9 @@ export function useChars() { const codepoint = CODEPOINT.exec(text)?.[1] if (codepoint) { - const char = String.fromCodePoint(Number.parseInt(codepoint, 16)) + const value = Number.parseInt(codepoint, 16) + if (!isUnicodeScalarValue(value)) return new Set() + const char = String.fromCodePoint(value) return new Set(charIndex.get(char)) } diff --git a/app/utils/unicode.ts b/app/utils/unicode.ts new file mode 100644 index 0000000..c0179ca --- /dev/null +++ b/app/utils/unicode.ts @@ -0,0 +1,6 @@ +/** Whether a number can be represented as a Unicode scalar value. */ +export const isUnicodeScalarValue = (codePoint: number): boolean => + Number.isInteger(codePoint) && + codePoint >= 0 && + codePoint <= 0x10ffff && + (codePoint < 0xd800 || codePoint > 0xdfff) diff --git a/scripts/tests/unicode.test.ts b/scripts/tests/unicode.test.ts new file mode 100644 index 0000000..2ca9f29 --- /dev/null +++ b/scripts/tests/unicode.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from 'vitest' +import { isUnicodeScalarValue } from '../../app/utils/unicode.ts' + +describe('Unicode scalar values', () => { + it.each([0, 0xd7ff, 0xe000, 0x10ffff])('accepts U+%s', (codePoint) => { + expect(isUnicodeScalarValue(codePoint)).toBe(true) + }) + + it.each([-1, 0xd800, 0xdfff, 0x110000, 0xffffff])( + 'rejects 0x%s', + (codePoint) => { + expect(isUnicodeScalarValue(codePoint)).toBe(false) + }, + ) +}) -- 2.51.2