Skip to content

Commit

Permalink
fix: replace custom mappings as needed
Browse files Browse the repository at this point in the history
  • Loading branch information
DJTB committed Apr 15, 2022
1 parent 1b163dd commit 65b2d18
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 44 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@
"rollup-plugin-terser": "^7.0.2",
"shelljs": "^0.8.5",
"static-server": "^3.0.0"
},
"dependencies": {
"dequal": "^2.0.2",
"memoize-one": "^6.0.0"
},
"lint-staged": {
"src/**/*.js": [
Expand Down
61 changes: 39 additions & 22 deletions src/toKana.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
import memoizeOne from 'memoize-one';
import { dequal } from 'dequal';

import { TO_KANA_METHODS } from './constants';
import mergeWithDefaultOptions from './utils/mergeWithDefaultOptions';
import { getRomajiToKanaTree, IME_MODE_MAP, USE_OBSOLETE_KANA_MAP } from './utils/romajiToKanaMap';
import {
getRomajiToKanaTree,
IME_MODE_MAP,
USE_OBSOLETE_KANA_MAP,
} from './utils/romajiToKanaMap';
import { applyMapping, mergeCustomMapping } from './utils/kanaMapping';
import isCharUpperCase from './utils/isCharUpperCase';
import hiraganaToKatakana from './utils/hiraganaToKatakana';

// memoize and deeply compare args so we only recreate when necessary
export const createRomajiToKanaMap = memoizeOne(
(IMEMode, useObsoleteKana, customKanaMapping) => {
let map = getRomajiToKanaTree();

map = IMEMode ? IME_MODE_MAP(map) : map;
map = useObsoleteKana ? USE_OBSOLETE_KANA_MAP(map) : map;

if (customKanaMapping) {
map = mergeCustomMapping(map, customKanaMapping);
}

return map;
},
dequal
);

/**
* Convert [Romaji](https://en.wikipedia.org/wiki/Romaji) to [Kana](https://en.wikipedia.org/wiki/Kana), lowercase text will result in [Hiragana](https://en.wikipedia.org/wiki/Hiragana) and uppercase text will result in [Katakana](https://en.wikipedia.org/wiki/Katakana).
* @param {String} [input=''] text
Expand All @@ -30,7 +54,11 @@ export function toKana(input = '', options = {}, map) {
let config;
if (!map) {
config = mergeWithDefaultOptions(options);
map = createRomajiToKanaMap(config);
map = createRomajiToKanaMap(
config.IMEMode,
config.useObsoleteKana,
config.customKanaMapping
);
} else {
config = options;
}
Expand All @@ -48,7 +76,9 @@ export function toKana(input = '', options = {}, map) {
config.IMEMode === TO_KANA_METHODS.KATAKANA ||
[...input.slice(start, end)].every(isCharUpperCase);

return enforceHiragana || !enforceKatakana ? kana : hiraganaToKatakana(kana);
return enforceHiragana || !enforceKatakana
? kana
: hiraganaToKatakana(kana);
})
.join('');
}
Expand All @@ -57,34 +87,21 @@ export function toKana(input = '', options = {}, map) {
*
* @private
* @param {String} [input=''] input text
* @param {Object} [options={}] toKana options
* @param {DefaultOptions} [options=defaultOptions] toKana options
* @param {Object} [map] custom mapping
* @returns {Array[]} [[start, end, token]]
* @example
* splitIntoConvertedKana('buttsuuji')
* // => [[0, 2, 'ぶ'], [2, 6, 'っつ'], [6, 7, 'う'], [7, 9, 'じ']]
*/
export function splitIntoConvertedKana(input = '', options = {}, map) {
if (!map) {
map = createRomajiToKanaMap(options);
}
return applyMapping(input.toLowerCase(), map, !options.IMEMode);
}

let customMapping = null;
export function createRomajiToKanaMap(options = {}) {
let map = getRomajiToKanaTree();
const { IMEMode, useObsoleteKana, customKanaMapping } = options;

map = options.IMEMode ? IME_MODE_MAP(map) : map;
map = options.useObsoleteKana ? USE_OBSOLETE_KANA_MAP(map) : map;

if (options.customKanaMapping) {
if (customMapping == null) {
customMapping = mergeCustomMapping(map, options.customKanaMapping);
}
map = customMapping;
if (!map) {
map = createRomajiToKanaMap(IMEMode, useObsoleteKana, customKanaMapping);
}

return map;
return applyMapping(input.toLowerCase(), map, !IMEMode);
}

export default toKana;
58 changes: 43 additions & 15 deletions src/toRomaji.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
import memoizeOne from 'memoize-one';
import { dequal } from 'dequal';

import mergeWithDefaultOptions from './utils/mergeWithDefaultOptions';
import katakanaToHiragana from './utils/katakanaToHiragana';
import isKatakana from './isKatakana';
import { getKanaToRomajiTree } from './utils/kanaToRomajiMap';
import { applyMapping, mergeCustomMapping } from './utils/kanaMapping';

// memoize and deeply compare args so we only recreate when necessary
export const createKanaToRomajiMap = memoizeOne(
(romanization, customRomajiMapping) => {
let map = getKanaToRomajiTree(romanization);

if (customRomajiMapping) {
map = mergeCustomMapping(map, customRomajiMapping);
}

return map;
},
dequal
);

/**
* Convert kana to romaji
* @param {String} kana text input
* @param {DefaultOptions} [options=defaultOptions]
* @param {Object} map custom mapping
* @return {String} converted text
* @example
* toRomaji('ひらがな カタカナ')
Expand All @@ -19,30 +37,40 @@ import { applyMapping, mergeCustomMapping } from './utils/kanaMapping';
* toRomaji('つじぎり', { customRomajiMapping: { じ: 'zi', つ: 'tu', り: 'li' } });
* // => 'tuzigili'
*/
export function toRomaji(input = '', options = {}) {
const mergedOptions = mergeWithDefaultOptions(options);
// just throw away the substring index information and just concatenate all the kana
return splitIntoRomaji(input, mergedOptions)
export function toRomaji(input = '', options = {}, map) {
const config = mergeWithDefaultOptions(options);

if (!map) {
map = createKanaToRomajiMap(
config.romanization,
config.customRomajiMapping
);
}

// just throw away the substring index information and simply concatenate all the kana
return splitIntoRomaji(input, config, map)
.map((romajiToken) => {
const [start, end, romaji] = romajiToken;
const makeUpperCase = options.upcaseKatakana && isKatakana(input.slice(start, end));
const makeUpperCase =
config.upcaseKatakana && isKatakana(input.slice(start, end));
return makeUpperCase ? romaji.toUpperCase() : romaji;
})
.join('');
}

let customMapping = null;
function splitIntoRomaji(input, options) {
let map = getKanaToRomajiTree(options);

if (options.customRomajiMapping) {
if (customMapping == null) {
customMapping = mergeCustomMapping(map, options.customRomajiMapping);
}
map = customMapping;
function splitIntoRomaji(input, options, map) {
if (!map) {
map = createKanaToRomajiMap(
options.romanization,
options.customRomajiMapping
);
}

return applyMapping(katakanaToHiragana(input, toRomaji, true), map, !options.IMEMode);
return applyMapping(
katakanaToHiragana(input, toRomaji, true),
map,
!options.IMEMode
);
}

export default toRomaji;
28 changes: 21 additions & 7 deletions src/utils/kanaToRomajiMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,19 @@ const SMALL_AIUEO = {
: 'e',
: 'o',
};
const YOON_KANA = ['き', 'に', 'ひ', 'み', 'り', 'ぎ', 'び', 'ぴ', 'ゔ', 'く', 'ふ'];
const YOON_KANA = [
'き',
'に',
'ひ',
'み',
'り',
'ぎ',
'び',
'ぴ',
'ゔ',
'く',
'ふ',
];
const YOON_EXCEPTIONS = {
: 'sh',
: 'ch',
Expand Down Expand Up @@ -108,10 +120,10 @@ function getKanaToHepburnTree() {
return kanaToHepburnMap;
}

export function getKanaToRomajiTree(fullOptions) {
switch (fullOptions.romanization) {
export function getKanaToRomajiTree(romanization) {
switch (romanization) {
case ROMANIZATIONS.HEPBURN:
return getKanaToHepburnTree(fullOptions);
return getKanaToHepburnTree();
default:
return {};
}
Expand All @@ -129,9 +141,11 @@ function createKanaToHepburnMap() {
subtreeOf(jsymbol)[''] = symbol;
});

[...Object.entries(SMALL_Y), ...Object.entries(SMALL_AIUEO)].forEach(([roma, kana]) => {
setTrans(roma, kana);
});
[...Object.entries(SMALL_Y), ...Object.entries(SMALL_AIUEO)].forEach(
([roma, kana]) => {
setTrans(roma, kana);
}
);

// きゃ -> kya
YOON_KANA.forEach((kana) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,33 @@ describe('Test custom mappings options', () => {
).toBe('tuzigili');
});

it('will replace previous custom mappings', () => {
expect(
toRomaji('つじぎり', {
customRomajiMapping: createCustomMapping({ : 'zi', : 'tu', : 'li' }),
})
).toBe('tuzigili');

expect(
toRomaji('つじぎり', {
customRomajiMapping: createCustomMapping({ : 'bi', : 'bu', : 'bi' }),
})
).toBe('bubigibi');

expect(
toKana('wanakana', {
customKanaMapping: createCustomMapping({ na: 'に', ka: 'Bana' }),
})
).toBe('わにBanaに');

expect(
toKana('wanakana', {
customKanaMapping: createCustomMapping({ na: 'り', ka: 'Cabana' }),
})
).toBe('わりCabanaり');
});


it('will accept a plain object and merge it internally via createCustomMapping()', () => {
expect(
toKana('wanakana', {
Expand Down
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2679,6 +2679,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=

dequal@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d"
integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==

detect-file@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
Expand Down Expand Up @@ -5083,6 +5088,11 @@ mdurl@^1.0.1:
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=

memoize-one@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==

memorystream@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
Expand Down

0 comments on commit 65b2d18

Please sign in to comment.