UNPKG

@zsnout/ithkuil

Version:

A set of tools which can generate and parse romanized Ithkuil text and which can generate Ithkuil script from text and JSON data.

167 lines (166 loc) 7.29 kB
import { deepFreezeAndNullPrototype } from "../../generate/index.js"; import { AtomicRegexPart, RegexPart, any, charIn, seq, start, transformWordButLeaveStressMarkings, } from "../../parse/index.js"; const STRESSED_TO_UNSTRESSED_VOWEL_MAP = /* @__PURE__ */ deepFreezeAndNullPrototype({ á: "a", é: "e", í: "i", ó: "o", ú: "u", â: "ä", ê: "ë", ô: "ö", û: "ü", }); const UNSTRESSED_VOWEL = "aeiouäëöü"; const unstressedVowel = /* @__PURE__ */ charIn(UNSTRESSED_VOWEL); const ANY_VOWEL = "aeiouäëöüáéíóúâêôû"; const anyVowel = /* @__PURE__ */ charIn(ANY_VOWEL); const CORE = "_pbtdkgfvţḑszšžçxhļcżčjmnňrlř"; const core = /* @__PURE__ */ charIn(CORE); const EXT = "_pbtdkgfvţḑszšžçxhļcżčjmnňrlwyř'\"¿"; const ext = /* @__PURE__ */ charIn(EXT); const extensionOnlyCore = /* @__PURE__ */ seq(ext, /* @__PURE__ */ ext.optional()); const letterCore = /* @__PURE__ */ any( /* @__PURE__ */ seq( /* @__PURE__ */ ext.optional(), core, /* @__PURE__ */ ext.optional()), extensionOnlyCore); const secondary = /* @__PURE__ */ seq(start, any(seq(ext, unstressedVowel, ext).asGroup(), any(seq(letterCore, unstressedVowel, unstressedVowel), seq(unstressedVowel, unstressedVowel, letterCore), seq(unstressedVowel.optional(), letterCore, unstressedVowel.optional())).asGroup(), seq(unstressedVowel, unstressedVowel).asGroup(), anyVowel.asGroup())).compile(); const extensionOnlySecondary = /* @__PURE__ */ seq(start, any(seq(ext, unstressedVowel, ext).asGroup(), any(seq(extensionOnlyCore, unstressedVowel, unstressedVowel), seq(unstressedVowel, unstressedVowel, extensionOnlyCore), seq(unstressedVowel.optional(), extensionOnlyCore, unstressedVowel.optional())).asGroup(), seq(unstressedVowel, unstressedVowel).asGroup(), anyVowel.asGroup())).compile(); const secondaryWithoutRightDiacritics = /* @__PURE__ */ seq(start, new AtomicRegexPart("()"), any(seq(unstressedVowel.optional(), letterCore, unstressedVowel.optional()).asGroup(), seq(unstressedVowel, unstressedVowel).asGroup(), anyVowel.asGroup())).compile(); const extensionOnlySecondaryWithoutRightDiacritics = /* @__PURE__ */ seq(start, new AtomicRegexPart("()"), any(seq(unstressedVowel.optional(), extensionOnlyCore, unstressedVowel.optional()).asGroup(), seq(unstressedVowel, unstressedVowel).asGroup(), anyVowel.asGroup())).compile(); /** * Converts text into secondary character templates. * * @param text The text to be converted. Use spaces to force character breaks, * and use underscore to force placeholders and extension locations. * @param options Options that modify how the secondary characters are * translated. * @returns An array of secondary characters parsed from the text. */ export function textToSecondaries(text, options) { const hadInitialGlottalStop = /^'(?![aeiouäëöüáéíóúâêôû])/.test(text); ({ word: text } = transformWordButLeaveStressMarkings(text)); if (hadInitialGlottalStop) { text = "'" + text; } text = text .replace(/[^aeiouäëöüáéíóúâêôûpbtdkgfvţḑszšžçxhļcżčjmnňrlwyř'"¿_]+/g, " ") .trim(); const output = []; let match; let regex = options?.useRightDiacritics === false ? secondaryWithoutRightDiacritics : secondary; let index = 0; while ((match = regex.exec(text))) { if (options?.forcePlaceholderCharacters) { regex = options?.useRightDiacritics === false ? extensionOnlySecondaryWithoutRightDiacritics : extensionOnlySecondary; } let source = match[0]; if (!source) { break; } text = text.slice(source.length).trimStart(); const secondary = { handwritten: options.handwritten, core: "STANDARD_PLACEHOLDER", }; if (options?.placeholder == "ALPHABETIC_PLACEHOLDER") { secondary.core = "ALPHABETIC_PLACEHOLDER"; } const CORE_ = options?.forcePlaceholderCharacters && index++ ? "" : CORE; if (match[1]) { secondary.top = source[0]; secondary.right = source[1]; secondary.bottom = source[2]; } else if (match[2]) { if (UNSTRESSED_VOWEL.includes(source[0])) { secondary.superposed = source[0]; source = source.slice(1); if (UNSTRESSED_VOWEL.includes(source[0])) { secondary.right = source[0]; source = source.slice(1); } } if (UNSTRESSED_VOWEL.includes(source.at(-1))) { secondary.underposed = source.at(-1); source = source.slice(0, -1); if (UNSTRESSED_VOWEL.includes(source.at(-1))) { secondary.right = source.at(-1); source = source.slice(0, -1); } } if (source.length == 1) { if (CORE_.includes(source)) { secondary.core = source; } else if (secondary.underposed) { secondary.top = source; } else { secondary.bottom = source; } } else if (source.length == 2) { if (CORE_.includes(source[0])) { secondary.core = source[0]; secondary.bottom = source[1]; } else if (CORE_.includes(source[1])) { secondary.top = source[0]; secondary.core = source[1]; } else { secondary.top = source[0]; secondary.bottom = source[1]; } } else if (source.length == 3) { secondary.top = source[0]; secondary.core = source[1]; secondary.bottom = source[2]; } } else if (match[3]) { secondary.superposed = source[0]; secondary.underposed = source[1]; } else if (match[4]) { if (source in STRESSED_TO_UNSTRESSED_VOWEL_MAP) { secondary.core = "STRESSED_SYLLABLE_PLACEHOLDER"; secondary.underposed = STRESSED_TO_UNSTRESSED_VOWEL_MAP[source]; } else { secondary.superposed = source; } } if (options?.useGeminateMarkers !== false && secondary.core) { if (secondary.core == secondary.top) { secondary.top = "CORE_GEMINATE"; } else if (secondary.core == secondary.bottom) { secondary.bottom = "CORE_GEMINATE"; } } if (secondary.top == "_") { delete secondary.top; } if (secondary.core == "_") { delete secondary.core; if (options?.placeholder == "ALPHABETIC_PLACEHOLDER") { secondary.core = "ALPHABETIC_PLACEHOLDER"; } } if (secondary.bottom == "_") { delete secondary.bottom; } output.push(secondary); } return output; }