From e0ded850228ca4038b5b088a919fef6d35d258cb Mon Sep 17 00:00:00 2001 From: "Rong Sen Ng (motss)" Date: Thu, 2 May 2019 20:54:39 +0800 Subject: [PATCH] =?UTF-8?q?=E2=8F=AA=20src:=20Revert=20change=20to=20use?= =?UTF-8?q?=20native=20String.prototype.normalize?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 32 ++++++++++------------- src/test/index.spec.ts | 58 ++++++++---------------------------------- 2 files changed, 25 insertions(+), 65 deletions(-) diff --git a/src/index.ts b/src/index.ts index 13b44d5..718f345 100644 --- a/src/index.ts +++ b/src/index.ts @@ -111,30 +111,26 @@ export const diacritics: Diacritics[] = [ ]; // tslint:enable:max-line-length -function nativeStringNormalize(s: string) { - /** - * NOTE: Normalizing accents/ diacritics in ES6. - * See https://bit.ly/2Cncgor for more info. - */ - return s.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); -} - -function stringNormalize(s: string) { - const normalized = diacritics.filter(n => n.diacritics.test(s)); - return !normalized.length ? s : normalized[0].letter; -} - export function normalizeSync(input?: string | null) { if ('string' !== typeof(input)) { throw new TypeError(`Expected 'input' to be of type string, but received '${input}'`); } - const replaceDiacritics = - 'function' === typeof(''.normalize) && 'aeo' === nativeStringNormalize('áèö') ? - (s: string) => nativeStringNormalize(s) : (s: string) => stringNormalize(s); - + /** + * NOTE(motss): Due to the fact that this module should do what we expect it to be - normalize + * accents/ diacritics. However, some characters are not accented such as those from + * [Latin-1 Supplement](https://bit.ly/2vz1l7m). Also see a relevant + * [GH issue](https://bit.ly/2JbAmH0). + * + * Hence, to match the mental module of the users, `String.prototype.normalize` should not be used + * as such. + */ return !input.length ? - input : input.replace(/(\S)/g, (_, p: string) => replaceDiacritics(p)); + input : + input.replace(/(\S)/g, (_, s: string) => { + const normalized = diacritics.find(n => n.diacritics.test(s)); + return null == normalized ? s : normalized.letter; + }); } export async function normalize(input?: string | null) { diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index 3d04006..7dd5bb6 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -11,19 +11,6 @@ describe('normalize-diacritics', () => { } }); - it(`throws error in 'replaceDiacritics'`, async () => { - const cachedFn = String.prototype.normalize; - String.prototype.normalize = () => { throw new Error('String#normalize is broken'); }; - - try { - await normalize('Réunion'); - } catch (e) { - expect(e).toStrictEqual(new Error('String#normalize is broken')); - } finally { - String.prototype.normalize = cachedFn; - } - }); - it(`throws when 'input' is 'undefined'`, async () => { try { await normalize(); @@ -36,13 +23,17 @@ describe('normalize-diacritics', () => { }); describe('ok', () => { - it('normalizes strings', async () => { + it(`skips normalization for empty character`, async () => { + expect(await normalize('')).toStrictEqual(''); + }); + + it('normalizes accented characters', async () => { try { const strs = [ 'Åland Islands', 'Saint Barthélemy', 'Cocos (Keeling) Islands', - 'Côte d\'Ivoire', + `Côte d'Ivoire`, 'Curaçao', 'Réunion', ]; @@ -50,7 +41,7 @@ describe('normalize-diacritics', () => { expect(await normalize(strs[0])).toStrictEqual('Aland Islands'); expect(await normalize(strs[1])).toStrictEqual('Saint Barthelemy'); expect(await normalize(strs[2])).toStrictEqual('Cocos (Keeling) Islands'); - expect(await normalize(strs[3])).toStrictEqual('Cote d\'Ivoire'); + expect(await normalize(strs[3])).toStrictEqual(`Cote d'Ivoire`); expect(await normalize(strs[4])).toStrictEqual('Curacao'); expect(await normalize(strs[5])).toStrictEqual('Reunion'); } catch (e) { @@ -58,7 +49,7 @@ describe('normalize-diacritics', () => { } }); - it('normalizes string without using native function', async () => { + it('normalizes accented characters without using native function', async () => { const cachedFn = String.prototype.normalize; String.prototype.normalize = null!; @@ -71,36 +62,9 @@ describe('normalize-diacritics', () => { } }); - it('returns original character when no match found', async () => { - const cachedFilter = Array.prototype.filter; - const cachedFn = String.prototype.normalize; - Array.prototype.filter = () => []; - String.prototype.normalize = null!; - - try { - expect(await normalize('Réunion')).toStrictEqual('Réunion'); - } catch (e) { - throw e; - } finally { - Array.prototype.filter = cachedFilter; - String.prototype.normalize = cachedFn; - } - }); - - it('normalizes single-character string', async () => { - try { - expect(await normalize('ô')).toStrictEqual('o'); - } catch (e) { - throw e; - } - }); - - it('returns empty string untouched', async () => { - try { - expect(await normalize('')).toStrictEqual(''); - } catch (e) { - throw e; - } + it(`normalizes non-accented characters (Latin-1 Supplement)`, async () => { + expect(await normalize('tromsø')).toStrictEqual('tromso'); + expect(await normalize('\u00d8')).toStrictEqual('O'); }); });