diff --git a/packages/abjad-client/package.json b/packages/abjad-client/package.json index 43a0306..a9c2deb 100644 --- a/packages/abjad-client/package.json +++ b/packages/abjad-client/package.json @@ -1,7 +1,7 @@ { "name": "abjad-client", "private": true, - "version": "0.0.2", + "version": "0.0.3", "main": "dist/index.js", "scripts": { "prebuild": "rm -rf dist", @@ -13,6 +13,6 @@ "lint:fix": "npx eslint . --fix" }, "dependencies": { - "abjad-convert": "^0.1.0-next.0" + "abjad-convert": "0.2.0-next.0" } } diff --git a/packages/abjad-client/src/index.ts b/packages/abjad-client/src/index.ts index bcd718b..118b34d 100644 --- a/packages/abjad-client/src/index.ts +++ b/packages/abjad-client/src/index.ts @@ -32,9 +32,10 @@ log(calmConvert(ugaritic, Abjad.Ugaritic, Abjad.Arabic)) log(`convert Ugaritic text ${ugaritic} to Phoenician`) log(calmConvert(ugaritic, Abjad.Ugaritic, Abjad.Phoenician)) -log(calmConvert('مرحبا', Abjad.Arabic, Abjad.Phoenician)) log(calmConvert('مرحبا', Abjad.Arabic, Abjad.ImperialAramaic)) +log(calmConvert('مرحبا', Abjad.Arabic, Abjad.Phoenician)) log(calmConvert('مرحبا', Abjad.Arabic, Abjad.Syriac)) +log(calmConvert('مرحبا', Abjad.Arabic, Abjad.Tifinagh)) log(calmConvert('مرحبا', Abjad.Arabic, Abjad.Ugaritic)) log('Done') diff --git a/packages/abjad-convert/CHANGELOG.md b/packages/abjad-convert/CHANGELOG.md index 78b6669..768373c 100644 --- a/packages/abjad-convert/CHANGELOG.md +++ b/packages/abjad-convert/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog +## [0.2.0] 2024-01-10 +### Added +- Support Tifinagh + ## [0.1.0] 2024-01-06 ### Added - Support Syriac diff --git a/packages/abjad-convert/README.md b/packages/abjad-convert/README.md index e533464..a41060c 100644 --- a/packages/abjad-convert/README.md +++ b/packages/abjad-convert/README.md @@ -1,8 +1,8 @@ # Abjad Convert -[![Version](https://img.shields.io/badge/version-0.1.0-blue.svg)](https://github.com/amerharb/abjad/tree/version/0.1.0) +[![Version](https://img.shields.io/badge/version-0.2.0-blue.svg)](https://github.com/amerharb/abjad/tree/version/0.2.0) [![License: GPLv3](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC) -![Coverage](https://raw.githubusercontent.com/amerharb/abjad/version/0.1.0/packages/abjad-convert/badges/coverage.svg) -![Github workflow](https://github.com/amerharb/abjad/actions/workflows/lint-test.yaml/badge.svg?branch=version/0.1.0) +![Coverage](https://raw.githubusercontent.com/amerharb/abjad/version/0.2.0/packages/abjad-convert/badges/coverage.svg) +![Github workflow](https://github.com/amerharb/abjad/actions/workflows/lint-test.yaml/badge.svg?branch=version/0.2.0) **abjad-convert** is a package for converting Abjad alphabets phonetically. @@ -11,6 +11,7 @@ current supported alphabets: - Imperial Aramaic - Phoenician - Syriac +- Tifinagh - Uguritic ## How to use @@ -29,15 +30,121 @@ import { convert, Abjad } from 'abjad-convert'; const arabicWord = 'مرحبا'; +const imperialAramaicWord = convert(arabicWord, Abjad.Arabic, Abjad.ImperialAramaic); +console.log(imperialAramaicWord); // 𐡌𐡓𐡇𐡁𐡀 + const phoenicianWord = convert(arabicWord, Abjad.Arabic, Abjad.Phoenician); console.log(phoenicianWord); // 𐤌𐤓𐤇𐤁𐤀 +const syriacWord = convert(arabicWord, Abjad.Arabic, Abjad.Syriac); +console.log(syriacWord); // ܡܪܚܒܐ + +const tifinaghWord = convert(arabicWord, Abjad.Arabic, Abjad.Tifinagh); +console.log(tifinaghWord); // ⵎⵔⵃⴱⴰ + const ugariticWord = convert(arabicWord, Abjad.Arabic, Abjad.Ugaritic); console.log(ugariticWord); // 𐎎𐎗𐎈𐎁𐎀 +``` +## Contributing +### Adding new script +Pull requests are welcome. For adding new script. let's say that we want to add a new script "Foo" +- Step #1: create a feature branch from `main` named `abjad-convert/version/0.[x].0` where `x` is the next minor of current version number. +- Step #2: create a new branch that will the previous feature branch when creating the PR. +- Step #3: create a new folder named `foo` in `src`. +- Step #4: add pdf documentation for the script we want to add from www.unicode.org. for example for Ugaritic the file is `U10380.pdf`. this file will be used as a reference +- Step #5: add a new file named `letters.ts` in `foo` folder this file will export +- - `letters` an array of letters written using unicode values with jsdoc each line will contain +the value of the letter using UTF-16 BE using escape \u followed by 4 hex digits. +notice that UTF16BE value is not always the same as the unicode value. +for example for letter Alpa in Ugaritic the unicode value is `0x10380` but the UTF16BE encode value is `0xD800DF80` +follow the value with jsdoc that contain array index, letter itself, unicode value, and the name of the letter. +for example for ugaritic looks like this: -const imperialAramaicWord = convert(arabicWord, Abjad.Arabic, Abjad.ImperialAramaic); -console.log(imperialAramaicWord); // 𐡌𐡓𐡇𐡁𐡀 +```ts +export const letters = [ + '\uD800\uDF80', /** #0 𐎀 U+10380 UGARITIC LETTER ALPA */ + '\uD800\uDF81', /** #1 𐎁 U+10381 UGARITIC LETTER BETA */ + //... +]; +``` +- - 'Fo' an alias object called `Fo` short of Foo. this will give an alias for all letters mentioned in the letters array. -const syriacWord = convert(arabicWord, Abjad.Arabic, Abjad.Syriac); -console.log(syriacWord); // ܡܪܚܒܐ +for example for ugaritic looks like this: +```ts +export const Ug = { + Alpa: letters[0], // 𐎀 + Beta: letters[1], // 𐎁 + //... +}; +``` + +- Step #6: Add the script to the enum `Abjad` in `src/types.ts` file. +at this point we have finished adding the script, but it is an island script. Meaning that it can't be converted to or from any other script. + +- Step #7: To make it convertable we need at least to have one from and one to converter to another script. +the preferred way is to add a converter to and from Arabic script, as it is currently act as a de facto hub script for all abjad scripts. +The algorithm for converting will look first for 1-step converter (direct converter) the one that convert from the source to the target, in case there isn't any it will look for 2-steps approach where it can find a middle script, +after that it won't look for 3 or more steps, it will basically throw an error. +That is why Arabic is used as preferred hub, so if all script add converter to Arabic and Arabic add converter to all other scripts then all conversion is possible. +However, there is a plan in the future to add IPA to be a canonical hub script. + +- - Adding to Arabic: Add file to `foo` folder with name `toArabic.ts` that include a class called FooToArabicConverter that implements `IConverter` interface. +it should look like this: +```ts +import { IConverter } from '../types'; +import { Fo } from './letters' +import { Ar } from '../arabic/letters' +import { IConverter } from '../IConverter' +import { Abjad } from '../types' + +export class FooToArabicConverter implements IConverter { + public readonly from = Abjad.Foo + public readonly to = Abjad.Arabic + public convert(fooText: string): string { + // convert logic here + // return (araic text) + } +} +``` +- - Add toArabic converter to `converterFactory.ts` +- - - import the new converter in alphabetical order +```ts +//... +import { FooToArabicConverter } from './foo/toArabic' +//... ``` +- - - add the converter to converters array in alphabetical order +```ts +const converters: IConverter[] = [ + //... + new TifinaghToArabicConverter(), + //... +]; +``` +- - Add toFoo converter to `arabic` folder with name `toFoo.ts` that include a class called ArabicToFooConverter that implements `IConverter` interface. +it should look like this: +```ts +import {Ar} from './letters' +import {Fo} from '../foo/letters' +import {IConverter} from '../IConverter' +import {Abjad} from '../types' + +export class ArabicToFooConverter implements IConverter { + public readonly from = Abjad.Arabic + public readonly to = Abjad.Foo + public convert(arabicText: string): string { + // convert logic here + // return (foo text) + } +} +``` +- - Add toFoo converter to `converterFactory.ts` + +- Step #8 add unit test to`test/index.test.ts`. + +- Step #9: update for new version +- - update `CHANGELOG.md` with the new version number and the changes. +- - Step #10 update `README.md` links and badges. +- - Update version in `package.json` file. +- - run yarn to update yarn.lock files +- - run test to update coverage badges diff --git a/packages/abjad-convert/badges/coverage.svg b/packages/abjad-convert/badges/coverage.svg index 8d58334..f2daea8 100644 --- a/packages/abjad-convert/badges/coverage.svg +++ b/packages/abjad-convert/badges/coverage.svg @@ -1 +1 @@ -Coverage: 99.37%Coverage99.37% \ No newline at end of file +Coverage: 99.5%Coverage99.5% \ No newline at end of file diff --git a/packages/abjad-convert/package.json b/packages/abjad-convert/package.json index 02a09c9..1131b06 100644 --- a/packages/abjad-convert/package.json +++ b/packages/abjad-convert/package.json @@ -1,6 +1,6 @@ { "name": "abjad-convert", - "version": "0.1.0", + "version": "0.2.0", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", "files": [ @@ -10,8 +10,13 @@ "CHANGELOG.md", "README.md" ], - "repository": "git@github.com:amerharb/abjad.git", "author": "Amer Harb", + "repository": { + "type": "git", + "url": "git+https://github.com/amerharb/abjad.git" + }, + "homepage": "https://github.com/amerharb/abjad#readme", + "url": "https://github.com/amerharb/abjad/issues", "email": "abjad@amerharb.com", "keywords": [ "abjad", diff --git a/packages/abjad-convert/src/arabic/toTifinagh.ts b/packages/abjad-convert/src/arabic/toTifinagh.ts new file mode 100644 index 0000000..1edd934 --- /dev/null +++ b/packages/abjad-convert/src/arabic/toTifinagh.ts @@ -0,0 +1,59 @@ +import { Ar } from './letters' +import { Ti } from '../tifinagh/letters' +import { IConverter } from '../IConverter' +import { Abjad } from '../types' + +export class ArabicToTifinaghConverter implements IConverter { + public readonly from = Abjad.Arabic + public readonly to = Abjad.Tifinagh + + private map = new Map( + [ + [' ', ' '], + [Ar.Hamza, Ti.Ya], /** ء -> ⴰ */ + [Ar.AlefMadda, Ti.Ya], /** ا -> ⴰ */ + [Ar.AlefHamza, Ti.Ya], /** أ -> ⴰ*/ + [Ar.WawHamza, Ti.Yu], /** ؤ -> ⵓ */ + [Ar.AlefHamzaMaksura, Ti.Ya], /** ى -> ⴰ */ + [Ar.Alef, Ti.Ya], /** ا -> ⴰ */ + [Ar.Ba, Ti.Yab], /** ب -> ⴱ */ + [Ar.TaMarbuta, Ti.Ya], /** ة -> ⴰ */ + [Ar.Ta, Ti.Yat], /** ت -> ⵜ */ + [Ar.Tha, Ti.Yath], /** ث -> ⵝ */ + [Ar.Jeem, Ti.Yazh], /** ج -> ⵊ */ + [Ar.H7aa, Ti.Yahh], /** ح -> ⵃ */ + [Ar.Khaa, Ti.Yakh], /** خ -> ⵅ */ + [Ar.Dal, Ti.Yad], /** د -> ⴷ */ + [Ar.Thal, Ti.Yadh], /** ذ -> ⴸ */ + [Ar.Ra, Ti.Yar], /** ر -> ⵔ */ + [Ar.Zay, Ti.Ya], /** ز -> ⴰ */ + [Ar.Seen, Ti.Yas], /** س -> ⵙ */ + [Ar.Sheen, Ti.Yash], /** ش -> ⵛ */ + [Ar.Sad, Ti.Yat], /** ص -> ⵜ */ + [Ar.Dad, Ti.Yadd], /** ض -> ⴹ */ + [Ar.TTa, Ti.Yatt], /** ط -> ⵟ */ + [Ar.THa, Ti.Yaddh], /** ظ -> ⴺ */ + [Ar.Ayn, Ti.Yaa], /** ع -> ⵄ */ + [Ar.Ghayn, Ti.Yagh], /** غ -> ⵖ */ + [Ar.Fa, Ti.Yaf], /** ف -> ⴼ */ + [Ar.Qaf, Ti.Yaq], /** ق -> ⵇ */ + [Ar.Kaf, Ti.Yak], /** ك -> ⴽ */ + [Ar.Lam, Ti.Yal], /** ل -> ⵍ */ + [Ar.Meem, Ti.Yam], /** م -> ⵎ */ + [Ar.Noon, Ti.Yan], /** ن -> ⵏ */ + [Ar.Ha, Ti.Yey], /** ه -> ⴻ */ + [Ar.Waw, Ti.Yu], /** و -> ⵓ */ + [Ar.AlefMaksura, Ti.Ya], /** ى -> ⴰ */ + [Ar.Yaa, Ti.Yi], /** ي -> ⵉ */ + ] + ) + + public convert(text: string): string { + let result = '' + for (const letter of text) { + const u = this.map.get(letter) ?? '' + result += u + } + return result + } +} diff --git a/packages/abjad-convert/src/ConverterFactory.ts b/packages/abjad-convert/src/converterFactory.ts similarity index 92% rename from packages/abjad-convert/src/ConverterFactory.ts rename to packages/abjad-convert/src/converterFactory.ts index fa9dc0b..6f32467 100644 --- a/packages/abjad-convert/src/ConverterFactory.ts +++ b/packages/abjad-convert/src/converterFactory.ts @@ -3,6 +3,7 @@ import { IConverter } from './IConverter' import { ArabicToImperialAramaicConverter } from './arabic/toImperialAramaic' import { ArabicToPhoenicianConverter } from './arabic/toPhoenician' import { ArabicToSyriacConverter } from './arabic/toSyriac' +import { ArabicToTifinaghConverter } from './arabic/toTifinagh' import { ArabicToUgariticConverter } from './arabic/toUgaritic' import { ImperialAramaicToArabicConverter } from './imperialAramaic/toArabic' import { ImperialAramaicToPhoenicianConverter } from './imperialAramaic/toPhoenician' @@ -11,6 +12,7 @@ import { PhoenicianToArabicConverter } from './phoenician/toArabic' import { PhoenicianToImperialAramaicConverter } from './phoenician/toImperialAramaic' import { PhoenicianToUgariticConverter } from './phoenician/toUgaritic' import { SyriacToArabicConverter } from './syriac/toArabic' +import { TifinaghToArabicConverter } from './tifinagh/toArabic' import { UgariticToArabicConverter } from './ugaritic/toArabic' import { UgariticToImperialAramaicConverter } from './ugaritic/toImperialAramaic' import { UgariticToPhoenicianConverter } from './ugaritic/toPhoenician' @@ -19,6 +21,7 @@ const converters: IConverter[] = [ new ArabicToImperialAramaicConverter(), new ArabicToPhoenicianConverter(), new ArabicToSyriacConverter(), + new ArabicToTifinaghConverter(), new ArabicToUgariticConverter(), new ImperialAramaicToArabicConverter(), new ImperialAramaicToPhoenicianConverter(), @@ -27,6 +30,7 @@ const converters: IConverter[] = [ new PhoenicianToImperialAramaicConverter(), new PhoenicianToUgariticConverter(), new SyriacToArabicConverter(), + new TifinaghToArabicConverter(), new UgariticToArabicConverter(), new UgariticToImperialAramaicConverter(), new UgariticToPhoenicianConverter(), diff --git a/packages/abjad-convert/src/index.ts b/packages/abjad-convert/src/index.ts index 2552b11..8e79319 100644 --- a/packages/abjad-convert/src/index.ts +++ b/packages/abjad-convert/src/index.ts @@ -1,4 +1,4 @@ -import { getConverter } from './ConverterFactory' +import { getConverter } from './converterFactory' import { Abjad } from './types' export function convert(source: string, from: Abjad, to: Abjad): string { diff --git a/packages/abjad-convert/src/phoenician/letters.ts b/packages/abjad-convert/src/phoenician/letters.ts index ff2ade6..97b8c33 100644 --- a/packages/abjad-convert/src/phoenician/letters.ts +++ b/packages/abjad-convert/src/phoenician/letters.ts @@ -41,7 +41,6 @@ export const Ph = { Waw: letters[5], // 𐤅 Zayin: letters[6], // 𐤆 Het: letters[7], // 𐤇 - Tet: letters[8], // 𐤈 Yod: letters[9], // 𐤉 Kap: letters[10], // 𐤊 @@ -50,20 +49,17 @@ export const Ph = { Nun: letters[13], // 𐤍 Semk: letters[14], // 𐤎 Ain: letters[15], // 𐤏 - Pe: letters[16], // 𐤐 Sade: letters[17], // 𐤑 Qof: letters[18], // 𐤒 Ros: letters[19], // 𐤓 Shin: letters[20], // 𐤔 Tau: letters[21], // 𐤕 - One: letters[22], // 𐤖 Ten: letters[23], // 𐤗 Twenty: letters[24], // 𐤘 OneHundred: letters[25], // 𐤙 Two: letters[26], // 𐤚 Three: letters[27], // 𐤛 - WordSeparator: letters[28], // 𐤟 } diff --git a/packages/abjad-convert/src/tifinagh/U2D30.pdf b/packages/abjad-convert/src/tifinagh/U2D30.pdf new file mode 100644 index 0000000..51f6afa Binary files /dev/null and b/packages/abjad-convert/src/tifinagh/U2D30.pdf differ diff --git a/packages/abjad-convert/src/tifinagh/letters.ts b/packages/abjad-convert/src/tifinagh/letters.ts new file mode 100644 index 0000000..71e88ec --- /dev/null +++ b/packages/abjad-convert/src/tifinagh/letters.ts @@ -0,0 +1,123 @@ +export const letters = [ + '\u2d30', /** #0 ⴰ U+2D30 TIFINAGH LETTER YA */ + '\u2d31', /** #1 ⴱ U+2D31 TIFINAGH LETTER YAB */ + '\u2d32', /** #2 ⴲ U+2D32 TIFINAGH LETTER YABH */ + '\u2d33', /** #3 ⴳ U+2D33 TIFINAGH LETTER YAG */ + '\u2d34', /** #4 ⴴ U+2D34 TIFINAGH LETTER YAGHH */ + '\u2d35', /** #5 ⴵ U+2D35 TIFINAGH LETTER BERBER ACADEMY YAJ */ + '\u2d36', /** #6 ⴶ U+2D36 TIFINAGH LETTER YAJ */ + '\u2d37', /** #7 ⴷ U+2D37 TIFINAGH LETTER YAD */ + '\u2d38', /** #8 ⴸ U+2D38 TIFINAGH LETTER YADH */ + '\u2d39', /** #9 ⴹ U+2D39 TIFINAGH LETTER YADD */ + '\u2d3a', /** #10 ⴺ U+2D3A TIFINAGH LETTER YADDH */ + '\u2d3b', /** #11 ⴻ U+2D3B TIFINAGH LETTER YEY */ + '\u2d3c', /** #12 ⴼ U+2D3C TIFINAGH LETTER YAF */ + '\u2d3d', /** #13 ⴽ U+2D3D TIFINAGH LETTER YAK */ + '\u2d3e', /** #14 ⴾ U+2D3E TIFINAGH LETTER TUAREG YAK */ + '\u2d3f', /** #15 ⴿ U+2D3F TIFINAGH LETTER YAKHH */ + '\u2d40', /** #16 ⵀ U+2D40 TIFINAGH LETTER YAH */ + '\u2d41', /** #17 ⵁ U+2D41 TIFINAGH LETTER BERBER ACADEMY YAH */ + '\u2d42', /** #18 ⵂ U+2D42 TIFINAGH LETTER TUAREG YAH */ + '\u2d43', /** #19 ⵃ U+2D43 TIFINAGH LETTER YAHH */ + '\u2d44', /** #20 ⵄ U+2D44 TIFINAGH LETTER YAA */ + '\u2d45', /** #21 ⵅ U+2D45 TIFINAGH LETTER YAKH */ + '\u2d46', /** #22 ⵆ U+2D46 TIFINAGH LETTER TUAREG YAKH */ + '\u2d47', /** #23 ⵇ U+2D47 TIFINAGH LETTER YAQ */ + '\u2d48', /** #24 ⵈ U+2D48 TIFINAGH LETTER TUAREG YAQ */ + '\u2d49', /** #25 ⵉ U+2D49 TIFINAGH LETTER YI */ + '\u2d4a', /** #26 ⵊ U+2D4A TIFINAGH LETTER YAZH */ + '\u2d4b', /** #27 ⵋ U+2D4B TIFINAGH LETTER AHAGGAR YAZH */ + '\u2d4c', /** #28 ⵌ U+2D4C TIFINAGH LETTER TUAREG YAZH */ + '\u2d4d', /** #29 ⵍ U+2D4D TIFINAGH LETTER YAL */ + '\u2d4e', /** #30 ⵎ U+2D4E TIFINAGH LETTER YAM */ + '\u2d4f', /** #31 ⵏ U+2D4F TIFINAGH LETTER YAN */ + '\u2d50', /** #32 ⵐ U+2D50 TIFINAGH LETTER TUAREG YAGN */ + '\u2d51', /** #33 ⵑ U+2D51 TIFINAGH LETTER TUAREG YANG */ + '\u2d52', /** #34 ⵒ U+2D52 TIFINAGH LETTER YAP */ + '\u2d53', /** #35 ⵓ U+2D53 TIFINAGH LETTER YU */ + '\u2d54', /** #36 ⵔ U+2D54 TIFINAGH LETTER YAR */ + '\u2d55', /** #37 ⵕ U+2D55 TIFINAGH LETTER YARR */ + '\u2d56', /** #38 ⵖ U+2D56 TIFINAGH LETTER YAGH */ + '\u2d57', /** #39 ⵗ U+2D57 TIFINAGH LETTER TUAREG YAGH */ + '\u2d58', /** #40 ⵘ U+2D58 TIFINAGH LETTER AYER YAGH */ + '\u2d59', /** #41 ⵙ U+2D59 TIFINAGH LETTER YAS */ + '\u2d5a', /** #42 ⵚ U+2D5A TIFINAGH LETTER YASS */ + '\u2d5b', /** #43 ⵛ U+2D5B TIFINAGH LETTER YASH */ + '\u2d5c', /** #44 ⵜ U+2D5C TIFINAGH LETTER YAT */ + '\u2d5d', /** #45 ⵝ U+2D5D TIFINAGH LETTER YATH */ + '\u2d5e', /** #46 ⵞ U+2D5E TIFINAGH LETTER YACH */ + '\u2d5f', /** #47 ⵟ U+2D5F TIFINAGH LETTER YATT */ + '\u2d60', /** #48 ⵠ U+2D60 TIFINAGH LETTER YAV */ + '\u2d61', /** #49 ⵡ U+2D61 TIFINAGH LETTER YAW */ + '\u2d62', /** #50 ⵢ U+2D62 TIFINAGH LETTER YAY */ + '\u2d63', /** #51 ⵣ U+2D63 TIFINAGH LETTER YAZ */ + '\u2d64', /** #52 ⵤ U+2D64 TIFINAGH LETTER TAWELLEMET YAZ */ + '\u2d65', /** #53 ⵥ U+2D65 TIFINAGH LETTER YAZZ */ + '\u2d66', /** #54 ⵦ U+2D66 TIFINAGH LETTER YE */ + '\u2d67', /** #55 ⵧ U+2D67 TIFINAGH LETTER YO */ + '\u2d6f', /** #56 ⵯ U+2D6F TIFINAGH MODIFIER LETTER LABIALIZATION MARK */ + '\u2d70', /** #54 ⵯ U+2D70 TIFINAGH SEPARATOR MARK */ + '\u2d7f', /** #55 ⵯ U+2D7F TIFINAGH CONSONANT JOINER */ +] + +export const Ti = { + Ya: letters[0], // ⴰ + Yab: letters[1], // ⴱ + Yabh: letters[2], // ⴲ + Yag: letters[3], // ⴳ + Yaghh: letters[4], // ⴴ + BerberAcademyYaj: letters[5], // ⴵ + Yaj: letters[6], // ⴶ + Yad: letters[7], // ⴷ + Yadh: letters[8], // ⴸ + Yadd: letters[9], // ⴹ + Yaddh: letters[10], // ⴺ + Yey: letters[11], // ⴻ + Yaf: letters[12], // ⴼ + Yak: letters[13], // ⴽ + TuaregYak: letters[14], // ⴾ + Yakhh: letters[15], // ⴿ + Yah: letters[16], // ⵀ + BerberAcademyYah: letters[17], // ⵁ + TuaregYah: letters[18], // ⵂ + Yahh: letters[19], // ⵃ + Yaa: letters[20], // ⵄ + Yakh: letters[21], // ⵅ + TuaregYakh: letters[22], // ⵆ + Yaq: letters[23], // ⵇ + TuaregYaq: letters[24], // ⵈ + Yi: letters[25], // ⵉ + Yazh: letters[26], // ⵊ + AhaggarYazh: letters[27], // ⵋ + TuaregYazh: letters[28], // ⵌ + Yal: letters[29], // ⵍ + Yam: letters[30], // ⵎ + Yan: letters[31], // ⵏ + TuaregYagn: letters[32], // ⵐ + TuaregYang: letters[33], // ⵑ + Yap: letters[34], // ⵒ + Yu: letters[35], // ⵓ + Yar: letters[36], // ⵔ + Yarr: letters[37], // ⵕ + Yagh: letters[38], // ⵖ + TuaregYagh: letters[39], // ⵗ + AyerYagh: letters[40], // ⵘ + Yas: letters[41], // ⵙ + Yass: letters[42], // ⵚ + Yash: letters[43], // ⵛ + Yat: letters[44], // ⵜ + Yath: letters[45], // ⵝ + Yach: letters[46], // ⵞ + Yatt: letters[47], // ⵟ + Yav: letters[48], // ⵠ + Yaw: letters[49], // ⵡ + Yay: letters[50], // ⵢ + Yaz: letters[51], // ⵣ + TawellemetYaz: letters[52], // ⵤ + Yazz: letters[53], // ⵥ + Ye: letters[54], // ⵦ + Yo: letters[55], // ⵧ + ModifierLetterLabializationMark: letters[56], // ⵯ + SeparatorMark: letters[57], // ⵯ + ConsonantJoiner: letters[58], // ⵯ +} diff --git a/packages/abjad-convert/src/tifinagh/toArabic.ts b/packages/abjad-convert/src/tifinagh/toArabic.ts new file mode 100644 index 0000000..99190ce --- /dev/null +++ b/packages/abjad-convert/src/tifinagh/toArabic.ts @@ -0,0 +1,80 @@ +import { Ti } from './letters' +import { Ar } from '../arabic/letters' +import { IConverter } from '../IConverter' +import { Abjad } from '../types' + +export class TifinaghToArabicConverter implements IConverter { + public readonly from = Abjad.Tifinagh + public readonly to = Abjad.Arabic + + private map = new Map( + [ + [' ', ' '], + [Ti.Ya, Ar.Alef], // ⴰ -> ا + [Ti.Yab, Ar.Ba], // ⴱ -> ب + [Ti.Yabh, Ar.Ba], // ⴲ -> ب P + [Ti.Yag, Ar.Jeem], // ⴳ -> ج G + [Ti.Yagh, Ar.Jeem], // ⴴ -> ج G + [Ti.Yad, Ar.Dal], // ⴷ -> د + [Ti.Yadh, Ar.Thal], // ⴸ -> ذ + [Ti.Yadd, Ar.Dad], // ⴹ -> ض + [Ti.Yaddh, Ar.THa], // ⴺ -> ظ + [Ti.Yey, Ar.Ha], // ⴻ -> ه + [Ti.Yaf, Ar.Fa], // ⴼ -> ف + [Ti.Yak, Ar.Kaf], // ⴽ -> ك + [Ti.TuaregYak, Ar.Kaf], // ⴾ -> ك + [Ti.Yakhh, Ar.Kaf], // ⴿ -> ك + [Ti.Yah, Ar.Ha], // ⵀ -> هـ , TODO: also it can be B ب + [Ti.BerberAcademyYah, Ar.Ha], // ⵁ -> هـ + [Ti.TuaregYah, Ar.Ha], // ⵂ -> هـ + [Ti.Yahh, Ar.H7aa], // ⵃ -> ح + [Ti.Yaa, Ar.Ayn], // ⵄ -> ع + [Ti.Yakh, Ar.Khaa], // ⵅ -> خ + [Ti.TuaregYakh, Ar.Khaa], // ⵆ -> خ + [Ti.Yaq, Ar.Qaf], // ⵇ -> ق + [Ti.TuaregYaq, Ar.Qaf], // ⵈ -> ق + [Ti.Yi, Ar.Yaa], // ⵉ -> ي + [Ti.Yazh, Ar.Jeem], // ⵊ -> ج + [Ti.AhaggarYazh, Ar.Jeem], // ⵋ -> ج + [Ti.TuaregYazh, Ar.Jeem], // ⵌ -> ج + [Ti.Yal, Ar.Lam], // ⵍ -> ل + [Ti.Yam, Ar.Meem], // ⵎ -> م + [Ti.Yan, Ar.Noon], // ⵏ -> ن + [Ti.TuaregYagn, Ar.Noon], // ⵐ -> ن IPA: ɲ TODO: this is 2 letters of ني + [Ti.TuaregYang, Ar.Noon], // ⵑ -> ن IPA: ŋ + [Ti.Yap, Ar.Ba], // ⵒ -> ب + [Ti.Yu, Ar.Waw], // ⵓ -> و + [Ti.Yar, Ar.Ra], // ⵔ -> ر + [Ti.Yarr, Ar.Ra], // ⵕ -> ر + [Ti.Yagh, Ar.Ghayn], // ⵖ -> غ + [Ti.TuaregYagh, Ar.Ghayn], // ⵗ -> غ + [Ti.AyerYagh, Ar.Ghayn], // ⵘ -> غ TODO: this can be ج + [Ti.Yas, Ar.Seen], // ⵙ -> س + [Ti.Yass, Ar.Seen], // ⵚ -> ص + [Ti.Yash, Ar.Sheen], // ⵛ -> ش + [Ti.Yat, Ar.Ta], // ⵜ -> ت + [Ti.Yath, Ar.Tha], // ⵝ -> ث + [Ti.Yach, Ar.Jeem], // ⵞ -> ج + [Ti.Yatt, Ar.Ta], // ⵟ -> ت + [Ti.Yav, Ar.Fa], // ⵠ -> ف + [Ti.Yaw, Ar.Waw], // ⵡ -> و + [Ti.Yay, Ar.Yaa], // ⵢ -> ي + [Ti.Yaz, Ar.Zay], // ⵣ -> ز + [Ti.TawellemetYaz, Ar.Zay], // ⵤ -> ز + [Ti.Yazz, Ar.Zay], // ⵥ -> ز + [Ti.Ye, Ar.Yaa], // ⵦ -> ي + [Ti.Yo, Ar.Waw], // ⵧ -> و + [Ti.ModifierLetterLabializationMark, ''], // ⵯ -> nothing + [Ti.SeparatorMark, ''], // ⵯ -> nothing + [Ti.ConsonantJoiner, ''], // ⵯ -> nothing + ] + ) + + public convert(text: string): string { + let result = '' + for (const letter of text) { + result += this.map.get(letter) ?? '' + } + return result + } +} diff --git a/packages/abjad-convert/src/types.ts b/packages/abjad-convert/src/types.ts index 8b24d15..dd083ba 100644 --- a/packages/abjad-convert/src/types.ts +++ b/packages/abjad-convert/src/types.ts @@ -3,5 +3,6 @@ export enum Abjad { ImperialAramaic = 'imperial-aramaic', Phoenician = 'phoenician', Syriac = 'syriac', + Tifinagh = 'tifinagh', Ugaritic = 'ugaritic', } diff --git a/packages/abjad-convert/src/ugaritic/letters.ts b/packages/abjad-convert/src/ugaritic/letters.ts index d564d32..dd940cb 100644 --- a/packages/abjad-convert/src/ugaritic/letters.ts +++ b/packages/abjad-convert/src/ugaritic/letters.ts @@ -1,65 +1,65 @@ export const letters = [ - '\uD800\uDF80', // 𐎀 U+10380 UGARITIC LETTER ALPA - '\uD800\uDF81', // 𐎁 U+10381 UGARITIC LETTER BETA - '\uD800\uDF82', // 𐎂 U+10382 UGARITIC LETTER GAMLA - '\uD800\uDF83', // 𐎃 U+10383 UGARITIC LETTER KHA - '\uD800\uDF84', // 𐎄 U+10384 UGARITIC LETTER DELTA - '\uD800\uDF85', // 𐎅 U+10385 UGARITIC LETTER HO - '\uD800\uDF86', // 𐎆 U+10386 UGARITIC LETTER WO - '\uD800\uDF87', // 𐎇 U+10387 UGARITIC LETTER ZETA - '\uD800\uDF88', // 𐎈 U+10388 UGARITIC LETTER HOTA - '\uD800\uDF89', // 𐎉 U+10389 UGARITIC LETTER TET - '\uD800\uDF8A', // 𐎊 U+1038A UGARITIC LETTER YOD - '\uD800\uDF8B', // 𐎋 U+1038B UGARITIC LETTER KAF - '\uD800\uDF8C', // 𐎌 U+1038C UGARITIC LETTER SHIN - '\uD800\uDF8D', // 𐎍 U+1038D UGARITIC LETTER LAMDA - '\uD800\uDF8E', // 𐎎 U+1038E UGARITIC LETTER MEM - '\uD800\uDF8F', // 𐎏 U+1038F UGARITIC LETTER DHAL - '\uD800\uDF90', // 𐎐 U+10390 UGARITIC LETTER NUN - '\uD800\uDF91', // 𐎑 U+10391 UGARITIC LETTER ZU - '\uD800\uDF92', // 𐎒 U+10392 UGARITIC LETTER SAMKA - '\uD800\uDF93', // 𐎓 U+10393 UGARITIC LETTER AIN - '\uD800\uDF94', // 𐎔 U+10394 UGARITIC LETTER PU - '\uD800\uDF95', // 𐎕 U+10395 UGARITIC LETTER SADE - '\uD800\uDF96', // 𐎖 U+10396 UGARITIC LETTER QOPA - '\uD800\uDF97', // 𐎗 U+10397 UGARITIC LETTER RASHA - '\uD800\uDF98', // 𐎘 U+10398 UGARITIC LETTER THANNA - '\uD800\uDF99', // 𐎙 U+10399 UGARITIC LETTER GHAIN - '\uD800\uDF9A', // 𐎚 U+1039A UGARITIC LETTER TO - '\uD800\uDF9B', // 𐎛 U+1039B UGARITIC LETTER I - '\uD800\uDF9C', // 𐎜 U+1039C UGARITIC LETTER U - '\uD800\uDF9D', // 𐎝 U+1039D UGARITIC LETTER SSU + '\uD800\uDF80', /** #0 𐎀 U+10380 UGARITIC LETTER ALPA */ + '\uD800\uDF81', /** #1 𐎁 U+10381 UGARITIC LETTER BETA */ + '\uD800\uDF82', /** #2 𐎂 U+10382 UGARITIC LETTER GAMLA */ + '\uD800\uDF83', /** #3 𐎃 U+10383 UGARITIC LETTER KHA */ + '\uD800\uDF84', /** #4 𐎄 U+10384 UGARITIC LETTER DELTA */ + '\uD800\uDF85', /** #5 𐎅 U+10385 UGARITIC LETTER HO */ + '\uD800\uDF86', /** #6 𐎆 U+10386 UGARITIC LETTER WO */ + '\uD800\uDF87', /** #7 𐎇 U+10387 UGARITIC LETTER ZETA */ + '\uD800\uDF88', /** #8 𐎈 U+10388 UGARITIC LETTER HOTA */ + '\uD800\uDF89', /** #9 𐎉 U+10389 UGARITIC LETTER TET */ + '\uD800\uDF8A', /** #10 𐎊 U+1038A UGARITIC LETTER YOD */ + '\uD800\uDF8B', /** #11 𐎋 U+1038B UGARITIC LETTER KAF */ + '\uD800\uDF8C', /** #12 𐎌 U+1038C UGARITIC LETTER SHIN */ + '\uD800\uDF8D', /** #13 𐎍 U+1038D UGARITIC LETTER LAMDA */ + '\uD800\uDF8E', /** #14 𐎎 U+1038E UGARITIC LETTER MEM */ + '\uD800\uDF8F', /** #15 𐎏 U+1038F UGARITIC LETTER DHAL */ + '\uD800\uDF90', /** #16 𐎐 U+10390 UGARITIC LETTER NUN */ + '\uD800\uDF91', /** #17 𐎑 U+10391 UGARITIC LETTER ZU */ + '\uD800\uDF92', /** #18 𐎒 U+10392 UGARITIC LETTER SAMKA */ + '\uD800\uDF93', /** #19 𐎓 U+10393 UGARITIC LETTER AIN */ + '\uD800\uDF94', /** #20 𐎔 U+10394 UGARITIC LETTER PU */ + '\uD800\uDF95', /** #21 𐎕 U+10395 UGARITIC LETTER SADE */ + '\uD800\uDF96', /** #22 𐎖 U+10396 UGARITIC LETTER QOPA */ + '\uD800\uDF97', /** #23 𐎗 U+10397 UGARITIC LETTER RASHA */ + '\uD800\uDF98', /** #24 𐎘 U+10398 UGARITIC LETTER THANNA */ + '\uD800\uDF99', /** #25 𐎙 U+10399 UGARITIC LETTER GHAIN */ + '\uD800\uDF9A', /** #26 𐎚 U+1039A UGARITIC LETTER TO */ + '\uD800\uDF9B', /** #27 𐎛 U+1039B UGARITIC LETTER I */ + '\uD800\uDF9C', /** #28 𐎜 U+1039C UGARITIC LETTER U */ + '\uD800\uDF9D', /** #29 𐎝 U+1039D UGARITIC LETTER SSU */ ] export const Ug = { - Alpa: '\uD800\uDF80', - Beta: '\uD800\uDF81', - Gamla: '\uD800\uDF82', - Kha: '\uD800\uDF83', - Delta: '\uD800\uDF84', - Ho: '\uD800\uDF85', - Wo: '\uD800\uDF86', - Zeta: '\uD800\uDF87', - Hota: '\uD800\uDF88', - Tet: '\uD800\uDF89', - Yod: '\uD800\uDF8A', - Kaf: '\uD800\uDF8B', - Shin: '\uD800\uDF8C', - Lamda: '\uD800\uDF8D', - Mem: '\uD800\uDF8E', - Dhal: '\uD800\uDF8F', - Nun: '\uD800\uDF90', - Zu: '\uD800\uDF91', - Samka: '\uD800\uDF92', - Ain: '\uD800\uDF93', - Pu: '\uD800\uDF94', - Sade: '\uD800\uDF95', - Qopa: '\uD800\uDF96', - Rasha: '\uD800\uDF97', - Thanna: '\uD800\uDF98', - Ghain: '\uD800\uDF99', - To: '\uD800\uDF9A', - I: '\uD800\uDF9B', - U: '\uD800\uDF9C', - Ssu: '\uD800\uDF9D', + Alpa: letters[0], // 𐎀 + Beta: letters[1], // 𐎁 + Gamla: letters[2], // 𐎂 + Kha: letters[3], // 𐎃 + Delta: letters[4], // 𐎄 + Ho: letters[5], // 𐎅 + Wo: letters[6], // 𐎆 + Zeta: letters[7], // 𐎇 + Hota: letters[8], // 𐎈 + Tet: letters[9], // 𐎉 + Yod: letters[10], // 𐎊 + Kaf: letters[11], // 𐎋 + Shin: letters[12], // 𐎌 + Lamda: letters[13], // 𐎍 + Mem: letters[14], // 𐎎 + Dhal: letters[15], // 𐎏 + Nun: letters[16], // 𐎐 + Zu: letters[17], // 𐎑 + Samka: letters[18], // 𐎒 + Ain: letters[19], // 𐎓 + Pu: letters[20], // 𐎔 + Sade: letters[21], // 𐎕 + Qopa: letters[22], // 𐎖 + Rasha: letters[23], // 𐎗 + Thanna: letters[24], // 𐎘 + Ghain: letters[25], // 𐎙 + To: letters[26], // 𐎚 + I: letters[27], // 𐎛 + U: letters[28], // 𐎜 + Ssu: letters[29], // 𐎝 } diff --git a/packages/abjad-convert/test/index.test.ts b/packages/abjad-convert/test/index.test.ts index 022abf0..9ba2886 100644 --- a/packages/abjad-convert/test/index.test.ts +++ b/packages/abjad-convert/test/index.test.ts @@ -21,6 +21,12 @@ describe('convert()', () => { expect(actual).toEqual('ܐ ܒ ܓ') }) }) + describe('to Tifinagh', () => { + it('convert ا ب ج into ⴰ ⴱ ⵊ', () => { + const actual = convert('ا ب ج', Abjad.Arabic, Abjad.Tifinagh) + expect(actual).toEqual('ⴰ ⴱ ⵊ') + }) + }) describe('to Ugaritic', () => { it('convert ا ب ج into 𐎀 𐎁 𐎂', () => { const actual = convert('ا ب ج', Abjad.Arabic, Abjad.Ugaritic) @@ -47,6 +53,12 @@ describe('convert()', () => { expect(actual).toEqual('ܐ ܒ ܓ') }) }) + describe('to Tifinagh', () => { + it('convert 𐡀 𐡁 𐡂 into ⴰ ⴱ ⵊ', () => { + const actual = convert('𐡀 𐡁 𐡂', Abjad.ImperialAramaic, Abjad.Tifinagh) + expect(actual).toEqual('ⴰ ⴱ ⵊ') + }) + }) describe('to Ugaritic', () => { it('convert 𐡀 𐡁 𐡂 into 𐎀 𐎁 𐎂', () => { const actual = convert('𐡀 𐡁 𐡂', Abjad.ImperialAramaic, Abjad.Ugaritic) @@ -73,6 +85,12 @@ describe('convert()', () => { expect(actual).toEqual('ܐ ܒ ܓ') }) }) + describe('to Tifinagh', () => { + it('convert 𐤀𐤟𐤁𐤟𐤂 into ⴰ ⴱ ⵊ', () => { + const actual = convert('𐤀𐤟𐤁𐤟𐤂', Abjad.Phoenician, Abjad.Tifinagh) + expect(actual).toEqual('ⴰ ⴱ ⵊ') + }) + }) describe('to Ugaritic', () => { it('convert 𐤀𐤟𐤁𐤟𐤂 into 𐎀𐎁𐎂', () => { const actual = convert('𐤀𐤟𐤁𐤟𐤂', Abjad.Phoenician, Abjad.Ugaritic) @@ -99,6 +117,12 @@ describe('convert()', () => { expect(actual).toEqual('𐤀𐤟𐤁𐤟𐤂') }) }) + describe('to Tifinagh', () => { + it('convert ܐ ܒ ܓ into ⴰ ⴱ ⵊ', () => { + const actual = convert('ܐ ܒ ܓ', Abjad.Syriac, Abjad.Tifinagh) + expect(actual).toEqual('ⴰ ⴱ ⵊ') + }) + }) describe('to Ugaritic', () => { it('convert ܐ ܒ ܓ into 𐎀 𐎁 𐎂', () => { const actual = convert('ܐ ܒ ܓ', Abjad.Syriac, Abjad.Ugaritic) @@ -106,6 +130,38 @@ describe('convert()', () => { }) }) }) + describe('from Tifinagh', () => { + describe('to Arabic', () => { + it('convert ⴰ ⴱ ⵊ into ا ب ج', () => { + const actual = convert('ⴰ ⴱ ⵊ', Abjad.Tifinagh, Abjad.Arabic) + expect(actual).toEqual('ا ب ج') + }) + }) + describe('to ImperialAramaic', () => { + it('convert ⴰ ⴱ ⵊ into 𐡀 𐡁 𐡂', () => { + const actual = convert('ⴰ ⴱ ⵊ', Abjad.Tifinagh, Abjad.ImperialAramaic) + expect(actual).toEqual('𐡀 𐡁 𐡂') + }) + }) + describe('to Phoenician', () => { + it('convert ⴰ ⴱ ⵊ into 𐤀𐤟𐤁𐤟𐤂', () => { + const actual = convert('ⴰ ⴱ ⵊ', Abjad.Tifinagh, Abjad.Phoenician) + expect(actual).toEqual('𐤀𐤟𐤁𐤟𐤂') + }) + }) + describe('to Syriac', () => { + it('convert ⴰ ⴱ ⵊ into ܐ ܒ ܓ', () => { + const actual = convert('ⴰ ⴱ ⵊ', Abjad.Tifinagh, Abjad.Syriac) + expect(actual).toEqual('ܐ ܒ ܓ') + }) + }) + describe('to Ugaritic', () => { + it('convert ⴰ ⴱ ⵊ into 𐎀 𐎁 𐎂', () => { + const actual = convert('ⴰ ⴱ ⵊ', Abjad.Tifinagh, Abjad.Ugaritic) + expect(actual).toEqual('𐎀 𐎁 𐎂') + }) + }) + }) describe('from Ugaritic', () => { describe('to Arabic', () => { it('convert 𐎀 𐎁 𐎂 into ا ب ج', () => { @@ -131,5 +187,11 @@ describe('convert()', () => { expect(actual).toEqual('ܐ ܒ ܓ') }) }) + describe('to Tifinagh', () => { + it('convert 𐎀 𐎁 𐎂 into ⴰ ⴱ ⵊ', () => { + const actual = convert('𐎀 𐎁 𐎂', Abjad.Ugaritic, Abjad.Tifinagh) + expect(actual).toEqual('ⴰ ⴱ ⵊ') + }) + }) }) })