@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
JavaScript
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;
}