UNPKG

@yar.ua/numerals

Version:

Number to text - Inflector for Ukrainian numerals

67 lines (66 loc) 2.53 kB
import { DummySyntaxNode } from "./syntax/node.js"; import { NumeralLexeme } from "./lexeme/numeral/numeral.js"; import { Relation } from "./syntax/relation.js"; import { ensureInteger, RangeError } from "./errors.js"; import { get_relation_type, pop_triplet, triplet_into_lexemes } from "./utils.js"; export const MAX_DIGIT_COUNT = 27; export function inflect(whole, form, insert_ones = false, strict_range = false) { const root = new DummySyntaxNode(form); build_tree(root, whole, insert_ones, strict_range); root.agree(); return root.text(); } export function build_tree(root, whole, insert_ones = false, strict_range = false) { whole = ensureInteger(whole); whole = whole.replace(/^0*/, ""); if (whole.length === 0) { root.add_child(NumeralLexeme.cardinal("0"), Relation.nummod_govpl); return; } const digits = whole.split(""); build_tree_from_digits(root, digits, insert_ones, strict_range); } export function build_tree_from_digits(root, digits, insert_ones, strict_range) { if (digits.length > MAX_DIGIT_COUNT) { if (strict_range) { throw new RangeError(digits, MAX_DIGIT_COUNT); } else { return build_tree_digit_wise(root, digits); } } let is_first = true; let power = 0; while (digits.length > 0) { const [ones, tens, hundreds] = pop_triplet(digits); const lexemes = triplet_into_lexemes(hundreds, tens, ones); if (lexemes.length > 0) { var current_root = root; if (power > 0) { const countable_lexeme = NumeralLexeme.cardinal("1" + "0".repeat(power)); current_root = root.add_child(countable_lexeme, get_relation_type(countable_lexeme, is_first)); is_first = true; } if (!insert_ones && power > 0) { if (lexemes.length === 1 && lexemes[0].value == "1") { continue; } } lexemes.forEach((lexeme) => { current_root.add_child(lexeme, get_relation_type(lexeme, is_first)); is_first = false; }); } power += 3; } } function build_tree_digit_wise(root, digits) { const inflected_part = digits.pop(); root.add_child(NumeralLexeme.cardinal(inflected_part), Relation.nummod); digits .slice() .reverse() .forEach((digit) => { root.add_child(NumeralLexeme.cardinal(digit), Relation.num); }); }