fix: refactor with unit test + better handle korean

This commit is contained in:
ShareVB 2024-05-15 22:08:06 +02:00
parent c434a5f3f0
commit 7a4310ad90
8 changed files with 1857 additions and 1589 deletions

1
components.d.ts vendored
View file

@ -159,6 +159,7 @@ declare module '@vue/runtime-core' {
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default']
SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default']
SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']
SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default']
SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default']

View file

@ -66,6 +66,7 @@
"ibantools": "^4.3.3", "ibantools": "^4.3.3",
"json5": "^2.2.3", "json5": "^2.2.3",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"korean-unpacker": "^1.0.3",
"libphonenumber-js": "^1.10.28", "libphonenumber-js": "^1.10.28",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "^10.0.0", "marked": "^10.0.0",

20
pnpm-lock.yaml generated
View file

@ -98,6 +98,9 @@ dependencies:
jwt-decode: jwt-decode:
specifier: ^3.1.2 specifier: ^3.1.2
version: 3.1.2 version: 3.1.2
korean-unpacker:
specifier: ^1.0.3
version: 1.0.3
libphonenumber-js: libphonenumber-js:
specifier: ^1.10.28 specifier: ^1.10.28
version: 1.10.28 version: 1.10.28
@ -3351,7 +3354,7 @@ packages:
dependencies: dependencies:
'@unhead/dom': 0.5.1 '@unhead/dom': 0.5.1
'@unhead/schema': 0.5.1 '@unhead/schema': 0.5.1
'@vueuse/shared': 10.7.2(vue@3.3.4) '@vueuse/shared': 10.9.0(vue@3.3.4)
unhead: 0.5.1 unhead: 0.5.1
vue: 3.3.4 vue: 3.3.4
transitivePeerDependencies: transitivePeerDependencies:
@ -3993,10 +3996,10 @@ packages:
- vue - vue
dev: false dev: false
/@vueuse/shared@10.7.2(vue@3.3.4): /@vueuse/shared@10.9.0(vue@3.3.4):
resolution: {integrity: sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==} resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
dependencies: dependencies:
vue-demi: 0.14.6(vue@3.3.4) vue-demi: 0.14.7(vue@3.3.4)
transitivePeerDependencies: transitivePeerDependencies:
- '@vue/composition-api' - '@vue/composition-api'
- vue - vue
@ -6624,6 +6627,10 @@ packages:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
dev: true dev: true
/korean-unpacker@1.0.3:
resolution: {integrity: sha512-s0VIyZOFOtalBSp51NECPvM1g9Af8M0Oxe1ZdMMGL7nvG/ecVNYkCAzPU+f52f0R83ytVCOd3fd14TTOFx2GXQ==}
dev: false
/less@4.1.3: /less@4.1.3:
resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==} resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -9151,8 +9158,8 @@ packages:
vue: 3.3.4 vue: 3.3.4
dev: false dev: false
/vue-demi@0.14.6(vue@3.3.4): /vue-demi@0.14.7(vue@3.3.4):
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
engines: {node: '>=12'} engines: {node: '>=12'}
hasBin: true hasBin: true
requiresBuild: true requiresBuild: true
@ -9442,6 +9449,7 @@ packages:
/workbox-google-analytics@7.0.0: /workbox-google-analytics@7.0.0:
resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==}
deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
dependencies: dependencies:
workbox-background-sync: 7.0.0 workbox-background-sync: 7.0.0
workbox-core: 7.0.0 workbox-core: 7.0.0

View file

@ -0,0 +1,3 @@
declare module 'korean-unpacker' {
function unpack(text: string): string;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,137 @@
[
{
"lang": "(International)",
"input": "TesYW 123 ? = !@",
"output": "TANGO echo sierra YANKEE WHISKEY (SPACE) ONE TWO THREE (SPACE) (?) (SPACE) (=) (SPACE) (!) (@)"
},
{
"lang": "(France)",
"input": "TesYW 123 ? = !@",
"output": "THÉRÈSE eugène suzanne YVONNE WILLIAM (ESPACE) UN DEUX TROIS (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
},
{
"lang": "(Belgium)",
"input": "TesYW 123 ? = !@",
"output": "TELEFOON emiel sofie YVONNE WATERLOO (ESPACE) (1) (2) (3) (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
},
{
"lang": "(Switzerland)",
"input": "TesYW 123 ? = !@",
"output": "THÉRÈSE émile suzanne (Y) WILLIAM (ESPACE) (1) (2) (3) (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
},
{
"lang": "(Québec)",
"input": "TesYW 123 ? = !@",
"output": "THOMAS édouard samuel (Y) WILLIAM (ESPACE) (1) (2) (3) (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
},
{
"lang": "(Germany, 2022)",
"input": "TesYü 123 ? = !@",
"output": "TÜBINGEN essen salzwedel YPSILON umlaut-unna (LEERZEICHEN) (1) (2) (3) (LEERZEICHEN) (?) (LEERZEICHEN) (=) (LEERZEICHEN) (!) (@)"
},
{
"lang": "(Austria)",
"input": "TesYW 123 ? = !@",
"output": "THEODOR emil samuel/siegfried YPSILON WILHELM (LEERZEICHEN) (1) (2) (3) (LEERZEICHEN) (?) (LEERZEICHEN) (=) (LEERZEICHEN) (!) (@)"
},
{
"lang": "(Germany, informal, 2022)",
"input": "TesYü 123 ? = !@",
"output": "THEODOR emil samuel YPSILON überfluss (LEERZEICHEN) (1) (2) (3) (LEERZEICHEN) (?) (LEERZEICHEN) (=) (LEERZEICHEN) (!) (@)"
},
{
"lang": "(Netherlands)",
"input": "TesY huis rij 123 ? = !@",
"output": "THEODOR eduard simon YPSILON (SPATIE) hendrik utrecht izaak simon (SPATIE) richard/rudolf ijmuiden/ijsbrand (SPATIE) (1) (2) (3) (SPATIE) (?) (SPATIE) (=) (SPATIE) (!) (@)"
},
{
"lang": "Italian",
"input": "TesYj 123 ? = !@",
"output": "TORINO empoli savona YORK, YOGURT jolly/juventus (SPAZIO) (1) (2) (3) (SPAZIO) (?) (SPAZIO) (=) (SPAZIO) (!) (@)"
},
{
"lang": "Spanish",
"input": "TesYñj 123 ? = !@",
"output": "TOLEDO españa sábado YOLANDA ñoño josé (ESPACIO) (1) (2) (3) (ESPACIO) (?) (ESPACIO) (=) (ESPACIO) (!) (@)"
},
{
"lang": "(Brazil)",
"input": "TesYÇj 123 ? = !@",
"output": "TATU estrela saci YOLANDA (Ç) josé (ESPAÇO) (1) (2) (3) (ESPAÇO) (?) (ESPAÇO) (=) (ESPAÇO) (!) (@)"
},
{
"lang": "(Portugal)",
"input": "TesYúj 123 ? = !@",
"output": "TAVIRA évora setúbal YORK (ú) josé (ESPAÇO) (1) (2) (3) (ESPAÇO) (?) (ESPAÇO) (=) (ESPAÇO) (!) (@)"
},
{
"lang": "Swedish",
"input": "TesYj 123 ? = !@",
"output": "TORE erik sigurd YNGVE johan (UTRYMME) (1) (2) (3) (UTRYMME) (?) (UTRYMME) (=) (UTRYMME) (!) (@)"
},
{
"lang": "Danish",
"input": "TesÆYj 123 ? = !@",
"output": "THEODOR erik søren ÆGIR YRSA johan (MELLEMRUMSTEGN) (1) (2) (3) (MELLEMRUMSTEGN) (?) (MELLEMRUMSTEGN) (=) (MELLEMRUMSTEGN) (!) (@)"
},
{
"lang": "Norwegian",
"input": "TesYÅj 123 ? = !@",
"output": "TEODOR edith sigrid YNGLING ÅSE johan (MELLOMROMSTEGN) (1) (2) (3) (MELLOMROMSTEGN) (?) (MELLOMROMSTEGN) (=) (MELLOMROMSTEGN) (!) (@)"
},
{
"lang": "Finnish",
"input": "TesYj 123 ? = !@",
"output": "TYYNE eemeli sakari YRJÖ jussi (VÄLILYÖNTI) (1) (2) (3) (VÄLILYÖNTI) (?) (VÄLILYÖNTI) (=) (VÄLILYÖNTI) (!) (@)"
},
{
"lang": "Turkish",
"input": "TesYj 123 ? = !@",
"output": "TOKAT edirne sinop YOZGAT jandarma (BOŞLUK) (1) (2) (3) (BOŞLUK) (?) (BOŞLUK) (=) (BOŞLUK) (!) (@)"
},
{
"lang": "Romanian",
"input": "TesYj 123 ? = !@",
"output": "TUDOR elena sandu I-GREC jean (SPAȚIU) (1) (2) (3) (SPAȚIU) (?) (SPAȚIU) (=) (SPAȚIU) (!) (@)"
},
{
"lang": "Czech",
"input": "TesYj 123 ? = !@",
"output": "TOMÁŠ emil svatopluk YPSILON josef (PROSTOROVÝ) (1) (2) (3) (PROSTOROVÝ) (?) (PROSTOROVÝ) (=) (PROSTOROVÝ) (!) (@)"
},
{
"lang": "Yugoslav",
"input": "TesYČj 123 ? = !@",
"output": "TUZLA evropa skopje IPSILON ČAČAK jadran (PRIESTOROVÝ) (1) (2) (3) (PRIESTOROVÝ) (?) (PRIESTOROVÝ) (=) (PRIESTOROVÝ) (!) (@)"
},
{
"lang": "Serbian",
"input": "TesYČj 123 ? = !@",
"output": "TIMOK evropa sava IPSILON ČAČAK jadran (PROSTORNI) (1) (2) (3) (PROSTORNI) (?) (PROSTORNI) (=) (PROSTORNI) (!) (@)"
},
{
"lang": "Slovene",
"input": "TesYČj 123 ? = !@",
"output": "TRIGLAV evropa soča IPSILON ČATEŽ jadran (PRESLEDKA) (1) (2) (3) (PRESLEDKA) (?) (PRESLEDKA) (=) (PRESLEDKA) (!) (@)"
},
{
"lang": "Russian",
"input": "Зинаида !.?",
"output": "ЗИНАИДА иван николай анна иван дмитрий анна ( ) (!) (.) (?)"
},
{
"lang": "Korean",
"input": "안녕하세요 여러분",
"output": "잉어 아버지 나폴리 나폴리 연못 잉어 한강 아버지 서울 엑스레이 잉어 요지경 ( ) 잉어 연못 로마 어머니 바가지 우편 나폴리"
},
{
"lang": "Greek",
"input": "τίγρης !?",
"output": "τίγρης (ί) γαλή ρήγας ηρώ σοφός ( ) (!) (?)"
},
{
"lang": "Japanese",
"input": "数字のひと おしまいのン ?:",
"output": "(数) (字) 野原のノ 飛行機のヒ 東京のト ( ) 大阪のオ 新聞のシ マッチのマ いろはのイ 野原のノ おしまいのン ( ) (?) (:)"
}
]

View file

@ -0,0 +1,12 @@
import { describe, expect, it } from 'vitest';
import { textToNatoAlphabet } from './text-to-nato-alphabet.service';
import natoTests from './nato.test.data.json';
describe('text-to-nato', () => {
it('Convert text to NATO', async () => {
for (const nato of natoTests) {
const { lang, input, output } = nato;
expect(textToNatoAlphabet({ text: input, langOrCountry: lang })).to.equal(output);
}
});
});

View file

@ -1,3 +1,4 @@
import hangul from 'korean-unpacker';
import allAlphabets from './nato.alphabets.json'; import allAlphabets from './nato.alphabets.json';
type AllALphabetsKeys = keyof typeof allAlphabets[0]; type AllALphabetsKeys = keyof typeof allAlphabets[0];
@ -14,8 +15,8 @@ function textToNatoAlphabet({ text, langOrCountry = '(International)' }: { text:
.join('|') .join('|')
}|.)`, }|.)`,
'gi'); 'gi');
return text return hangul.unpack(text)
.replace(/\s/g, ' ') .replace(/\s+/g, ' ')
.replace( .replace(
charRegex, charRegex,
(character) => { (character) => {
@ -24,9 +25,10 @@ function textToNatoAlphabet({ text, langOrCountry = '(International)' }: { text:
const alphabetLetter = allAlphabets.find(letter => letter.Letter === searchChar); const alphabetLetter = allAlphabets.find(letter => letter.Letter === searchChar);
if (alphabetLetter && alphabetLetter[langOrCountry as AllALphabetsKeys]) { if (alphabetLetter && alphabetLetter[langOrCountry as AllALphabetsKeys]) {
const natoWord = alphabetLetter[langOrCountry as AllALphabetsKeys] || ''; const natoWord = alphabetLetter[langOrCountry as AllALphabetsKeys] || '';
return ` ${isUpper ? natoWord.toUpperCase() : natoWord.toLowerCase()} `; return ` ${isUpper ? natoWord.toUpperCase() : natoWord.toLowerCase()}`;
} }
return ` (${character}) `; return ` (${character})`;
}); })
.trim();
} }