From 21b507cb27368d2fb65ef6b748d3ec12bf9c4871 Mon Sep 17 00:00:00 2001 From: Evan Shortiss Date: Wed, 14 Mar 2018 14:06:11 -0700 Subject: [PATCH] add support for phoentics. update formatting. allow empty string arguments --- CHANGELOG.md | 11 ++++++ README.md | 50 +++++++++++++++++++++------ __test__/index.test.ts | 64 +++++++++++++++++++++++++---------- package.json | 12 ++++--- src/ogham-symbols.ts | 58 ++++++++++++++++---------------- src/ogham.ts | 76 +++++++++++++++++++++++++++++++++++++++--- 6 files changed, 205 insertions(+), 66 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4c82025 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# CHANGELOG + +Dates are YYYY-MM-DD. + +## 0.2.0 / 2018-03-14 +* Improve README +* Added `usePhonetics` flag to support phonetic replacements for characters/letters +missing from the [Irish Alphabet](https://en.wikipedia.org/wiki/Irish_orthography#Alphabet) +and [Ogham Symbols](https://en.wikipedia.org/wiki/Ogham) +* Fix typings in published module +* Support passing of an empty string diff --git a/README.md b/README.md index 0f29b29..cb5a759 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,25 @@ # Ogham -![https://travis-ci.org/evanshortiss/ogham](https://travis-ci.org/evanshortiss/ogham.svg) [![npm version](https://badge.fury.io/js/%40evanshortiss%2Fogham.svg)](https://badge.fury.io/js/%40evanshortiss%2Fogham.svg) [![https://coveralls.io/repos/github/evanshortiss/ogham](https://coveralls.io/repos/github/evanshortiss/ogham/badge.svg?branch=master)](https://coveralls.io/github/evanshortiss/ogham?branch=master) +![https://travis-ci.org/evanshortiss/ogham](https://travis-ci.org/evanshortiss/ogham.svg) [![npm version](https://badge.fury.io/js/ogham.svg)](https://badge.fury.io/js/ogham) [![https://coveralls.io/repos/github/evanshortiss/ogham](https://coveralls.io/repos/github/evanshortiss/ogham/badge.svg?branch=master)](https://coveralls.io/github/evanshortiss/ogham?branch=master) [![TypeScript](https://badges.frapsoft.com/typescript/version/typescript-next.svg?v=101)](https://github.com/ellerbrock/typescript-badges/) Converts a given input string to its Ogham equivalent. If you're interested in -learning more about Ogham check out these articles: +learning more about Ogham check out these articles: * [Ogham on Wikipedia](https://en.wikipedia.org/wiki/Ogham) * [Ogham by Balldrich Ballbarian](http://www.housebarra.com/EP/ep02/05ogham.html) As an example, the string `hello` will become `᚛ᚆᚓᚂᚂᚑ᚜` if converted to Ogham. -Typically Ogham is read from bottom to top so our hello example above would be -rotated 90 degrees counter clockwise. +Typically Ogham is read from bottom to top so our hello example above would +normally be rotated 90 degrees counterclockwise. + +The best results are obtained by passing words in their Irish Gaelic form since +the Irish alphabet is missing letters that occur in English and other alphabets. +For example the English word "key" contains the letters 'k' and 'y' which don't +appear in the Irish alphabet so no Ogham character exists for these; instead you +could pass the Irish word "eochair" or pass the `usePhonetics` option to replace +'k' with 'q' and 'y' with 'i'. *Disclaimer: This module is still in development and results should be checked against with an Ogham reference such as those on Wikipedia and other @@ -43,8 +50,10 @@ console.log(ogham.convert('ireland')) ### convert(input: string, options: OghamOptions) Converts the given input string to its ogham representation. Inputs must be A-Z -characters without accents, e.g pass `a` instead of `á`. The letters `j`, `k`, -`v`, `w`, `x`, and `y` are not supported. +characters without accents, e.g pass `a` instead of `á`. Pssing the letters `j`, +`k`, `v`, `w`, `x`, and `y` will cause an error to be thrown unless the +`replaceMissingLetters` option is passed - this is because these letters aren't +present in the Irish alphabet. Supported keys in the options Object are: @@ -53,9 +62,18 @@ characters should be added. * `useForfeda: Boolean` - This enables use of the [Forfeda](https://en.wikipedia.org/wiki/Forfeda) characters. For example, instead of `ea` being printed as `ᚓᚐ` it will be printed as `ᚕ`. - -Here's an example: - +* `usePhonetics` - This setting will replace the following letters with +phonetic equivalents since they don't occur in the Irish alphabet: + * J => G + * K => Q + * V => F + * W => UU + * X => Z + * Y => I + +Below are some examples. + +#### options.addBoundary ```js const convertedText = ogham.convert('ireland', { addBoundary: false @@ -63,5 +81,17 @@ const convertedText = ogham.convert('ireland', { console.log(convertedText) -// prints "ᚔᚏᚓᚂᚐᚅᚇ" +// prints "ᚔᚏᚓᚂᚐᚅᚇ" instead of the default "᚛ᚔᚏᚓᚂᚐᚅᚇ᚜" +``` + +#### options.usePhonetics +```js +console.log( + ogham.convert('keys', { + usePhonetics: true + }) +) +// prints "᚛ᚊᚓᚔᚄ᚜" which is actually "qeis" since 'k' and 'y' need to be +// replaced with phonetically similar characters as they don't appear in the +// irish alphabet https://en.wikipedia.org/wiki/Irish_orthography#Alphabet ``` diff --git a/__test__/index.test.ts b/__test__/index.test.ts index 981c133..a6d557e 100644 --- a/__test__/index.test.ts +++ b/__test__/index.test.ts @@ -1,36 +1,64 @@ -import * as ogham from "../src/ogham"; +import * as ogham from '../src/ogham'; -describe("#convert", () => { - it("should reject input containing characters not in [a-z] range", () => { - expect(() => { - ogham.convert("Hey there 123 -"); - }).toThrowError(/input can only contain alphabetic characters/gi); +describe('#convert', () => { + it('should reject input containing characters not in [a-z] range', () => { + expect(() => ogham.convert('Hey there 123 -')).toThrowError( + /input can only contain alphabetic characters/gi + ); }); - it("should convert text and add head and tail characters", () => { - expect(ogham.convert("eire")).toEqual("᚛ᚓᚔᚏᚓ᚜"); + it('should convert text and add head and tail characters', () => { + expect(ogham.convert('eire')).toEqual('᚛ᚓᚔᚏᚓ᚜'); }); - it("should convert text and not add head and tail characters", () => { - expect(ogham.convert("eire", { addBoundary: false })).toEqual("ᚓᚔᚏᚓ"); + it('should convert text and not add head and tail characters', () => { + expect(ogham.convert('eire', { addBoundary: false })).toEqual('ᚓᚔᚏᚓ'); }); - it("should convert text without using forfeda characters and include head/tail", () => { - expect(ogham.convert("is maith liom tae")).toEqual("᚛ᚔᚄ ᚋᚐᚔᚈᚆ ᚂᚔᚑᚋ ᚈᚐᚓ᚜"); + it('should convert text without using forfeda characters and include head/tail', () => { + expect(ogham.convert('is maith liom tae')).toEqual('᚛ᚔᚄ ᚋᚐᚔᚈᚆ ᚂᚔᚑᚋ ᚈᚐᚓ᚜'); }); - it("should convert text using forfeda characters and include head/tail", () => { - expect(ogham.convert("is maith liom tae", { useForfeda: true })).toEqual( - "᚛ᚔᚄ ᚋᚐᚔᚈᚆ ᚂᚔᚑᚋ ᚈᚙ᚜" + it('should convert text using forfeda characters and include head/tail', () => { + expect(ogham.convert('is maith liom tae', { useForfeda: true })).toEqual( + '᚛ᚔᚄ ᚋᚐᚔᚈᚆ ᚂᚔᚑᚋ ᚈᚙ᚜' ); }); - it("should convert text using forfeda characters and not include head/tail", () => { + it('should convert text using forfeda characters and not include head/tail', () => { expect( - ogham.convert("is maith liom tae", { + ogham.convert('is maith liom tae', { useForfeda: true, addBoundary: false }) - ).toEqual("ᚔᚄ ᚋᚐᚔᚈᚆ ᚂᚔᚑᚋ ᚈᚙ"); + ).toEqual('ᚔᚄ ᚋᚐᚔᚈᚆ ᚂᚔᚑᚋ ᚈᚙ'); + }); + + it('should flag invalid characters', () => { + expect(() => ogham.convert('keys')).toThrowError( + 'input cannot contain j, k, v, w, x, y unless "usePhonetics" option is passed' + ); + }); + + it('should convert string containing invalid characters with "usePhonetics"', () => { + expect(ogham.convert('jkvwxy', { usePhonetics: true })).toEqual( + '᚛ᚌᚊᚃᚒᚒᚎᚔ᚜' + ); + }); + + it('should convert string containing invalid characters with "usePhonetics"', () => { + const input = 'abcdefghijklmnopqrstuvwxyz'; + const output = ogham.convert(input, { + usePhonetics: true, + addBoundary: false + }); + + // 'W' becomes 'UU' so it adds padding + expect(output.length).toEqual(27); + expect(output).toEqual('ᚐᚁᚉᚇᚓᚃᚌᚆᚔᚌᚊᚂᚋᚅᚑᚚᚊᚏᚄᚈᚒᚃᚒᚒᚎᚔᚎ'); + }); + + it('should support passing an empty string', () => { + expect(ogham.convert('')).toEqual('᚛᚜'); }); }); diff --git a/package.json b/package.json index 1884db5..36fee8d 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,29 @@ { "name": "ogham", - "version": "0.1.0", + "version": "0.2.0", "description": "convert an input string to its Ogham equivalent", "main": "src/ogham.js", + "typings": "src/ogham.d.ts", "scripts": { "precommit": "npm run format && npm test", - "format": "prettier --write src/*.js src/*.ts __test__/*.ts", + "format": "prettier --write --single-quote src/*.js src/*.ts __test__/*.ts", "prepublish": "tsc && npm run format ", - "test": "jest", + "test": "tsc && jest", "coveralls": "cat coverage/lcov.info | coveralls" }, "keywords": [ "ogham", "irish", "gaelic", - "ogam" + "ogam", + "convert", + "transliterate" ], "author": "Evan Shortiss (http://evanshortiss.com/)", "license": "MIT", "devDependencies": { "@types/jest": "~22.2.0", + "@types/node": "~9.4.7", "coveralls": "~3.0.0", "husky": "~0.14.3", "jest": "~22.4.2", diff --git a/src/ogham-symbols.ts b/src/ogham-symbols.ts index ee7c462..7928f07 100644 --- a/src/ogham-symbols.ts +++ b/src/ogham-symbols.ts @@ -1,88 +1,88 @@ export default { // These are the standard 20 characters in ogham individual: { - " ": { - char: " ", + ' ': { + char: ' ', code: 5760 }, b: { - char: "ᚁ", + char: 'ᚁ', code: 5761 }, l: { - char: "ᚂ", + char: 'ᚂ', code: 5762 }, f: { - char: "ᚃ", + char: 'ᚃ', code: 5763 }, s: { - char: "ᚄ", + char: 'ᚄ', code: 5764 }, n: { - char: "ᚅ", + char: 'ᚅ', code: 5765 }, h: { - char: "ᚆ", + char: 'ᚆ', code: 5766 }, d: { - char: "ᚇ", + char: 'ᚇ', code: 5767 }, t: { - char: "ᚈ", + char: 'ᚈ', code: 5768 }, c: { - char: "ᚉ", + char: 'ᚉ', code: 5769 }, q: { - char: "ᚊ", + char: 'ᚊ', code: 5770 }, m: { - char: "ᚋ", + char: 'ᚋ', code: 5771 }, g: { - char: "ᚌ", + char: 'ᚌ', code: 5772 }, z: { - char: "ᚎ", + char: 'ᚎ', code: 5774 }, r: { - char: "ᚏ", + char: 'ᚏ', code: 5775 }, a: { - char: "ᚐ", + char: 'ᚐ', code: 5776 }, o: { - char: "ᚑ", + char: 'ᚑ', code: 5777 }, u: { - char: "ᚒ", + char: 'ᚒ', code: 5778 }, e: { - char: "ᚓ", + char: 'ᚓ', code: 5779 }, i: { - char: "ᚔ", + char: 'ᚔ', code: 5780 }, p: { - char: "ᚚ", + char: 'ᚚ', code: 5786 } }, @@ -90,15 +90,15 @@ export default { // https://en.wikipedia.org/wiki/Forfeda#The_aicme_forfeda combination: { ea: { - char: "ᚕ", + char: 'ᚕ', code: 5781 }, oi: { - char: "ᚖ", + char: 'ᚖ', code: 5782 }, ui: { - char: "ᚗ", + char: 'ᚗ', code: 5783 }, // ng: { @@ -106,20 +106,20 @@ export default { // code: 5773 // }, ia: { - char: "ᚘ", + char: 'ᚘ', code: 5784 }, ae: { - char: "ᚙ", + char: 'ᚙ', code: 5785 } }, head: { - char: "᚛", + char: '᚛', code: 5787 }, tail: { - char: "᚜", + char: '᚜', code: 5788 } }; diff --git a/src/ogham.ts b/src/ogham.ts index 742ec81..cc861e1 100644 --- a/src/ogham.ts +++ b/src/ogham.ts @@ -1,8 +1,36 @@ // Our mapping of alphabetical characters to ogham -import ogham from "./ogham-symbols"; +import ogham from './ogham-symbols'; // Inputs can only contain alphabetical characters and spaces -const validateInputRgx = /^(?!.*[jwy])[a-z ]+$/; +const validateInputRgx = /[a-z ]+$/g; + +// These characters are not supported by default +const phoneticReplacements = [ + { + original: 'j', + replacement: 'g' + }, + { + original: 'k', + replacement: 'q' + }, + { + original: 'v', + replacement: 'f' + }, + { + original: 'w', + replacement: 'uu' + }, + { + original: 'x', + replacement: 'z' + }, + { + original: 'y', + replacement: 'i' + } +]; /** * Interface representing options that can be passed to the convert @@ -10,6 +38,7 @@ const validateInputRgx = /^(?!.*[jwy])[a-z ]+$/; export interface OghamOptions { addBoundary?: boolean; useForfeda?: boolean; + usePhonetics?: boolean; } /** @@ -28,9 +57,15 @@ export function convert(input: string, opts?: OghamOptions) { let text = input.toLowerCase(); - if (!text.match(validateInputRgx)) { + if (text.length !== 0 && !text.match(validateInputRgx)) { + throw new Error('input can only contain alphabetic characters'); + } + + if (!options.usePhonetics && containsInvalidCharacters(text)) { throw new Error( - "Input can only contain alphabetic characters, excluding J, K, V, W, X, and Y" + `input cannot contain ${phoneticReplacements + .map(ch => ch.original) + .join(', ')} unless "usePhonetics" option is passed` ); } @@ -38,6 +73,10 @@ export function convert(input: string, opts?: OghamOptions) { text = replaceCharacters(text, ogham.combination); } + if (options.usePhonetics) { + text = replaceInvalidCharactersWithPhonetics(text); + } + if (options.addBoundary) { text = `${ogham.head.char}${text}${ogham.tail.char}`; } @@ -45,6 +84,33 @@ export function convert(input: string, opts?: OghamOptions) { return replaceCharacters(text, ogham.individual); } +/** + * Replaces occurences of invalid characters with phonetics equivalents + * @param text + */ +function replaceInvalidCharactersWithPhonetics(text: string) { + phoneticReplacements.forEach(ch => { + text = text.replace(new RegExp(ch.original, 'gi'), ch.replacement); + }); + + return text; +} + +/** + * Determines if the given input contains letters that are missing from ogham + * or the irish alphabet + * @param text + */ +function containsInvalidCharacters(text: string) { + for (let i = 0; i < phoneticReplacements.length; i++) { + if (text.indexOf(phoneticReplacements[i].original) !== -1) { + return true; + } + } + + return false; +} + /** * Replaces characters that match ogham forfeda patterns, e.g "ng" becomes "ᚍ" * @param text @@ -53,7 +119,7 @@ function replaceCharacters(text: string, patterns: any) { Object.keys(patterns).forEach(letter => { // This is the object containing the ogham char and char code const charInfo = patterns[letter]; - const rgx = new RegExp(`${letter}`, "ig"); + const rgx = new RegExp(`${letter}`, 'ig'); text = text.replace(rgx, charInfo.char); });