@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.
281 lines (280 loc) • 12.4 kB
JavaScript
import { getIntegerCs } from "../../data/affixes-map.js";
import { getIntegerCr } from "../../data/roots-map.js";
import {} from "../ca/index.js";
import { deepFreeze } from "../helpers/deep-freeze.js";
import { applyStress, countVowelForms } from "../helpers/stress.js";
import { ONE_INDEXED_STANDARD_VOWEL_TABLE } from "../helpers/vowel-table.js";
import { WithWYAlternative } from "../helpers/with-wy-alternative.js";
import { isLegalWordInitialConsonantForm } from "../phonotactics/word-initial.js";
import { referentListToPersonalReferenceRoot } from "../referential/index.js";
import { fillInDefaultFormativeSlots } from "./default.js";
import {} from "./shortcut-type.js";
import { slotIToIthkuil } from "./slot-1/index.js";
import { applySlotXStress } from "./slot-10/index.js";
import { SLOT_II_MAP, SLOT_II_SHORTCUT_MAP, slotIIToIthkuil, } from "./slot-2/index.js";
import {} from "./slot-3/index.js";
import { slotIVToIthkuil, } from "./slot-4/index.js";
import { slotVToIthkuil } from "./slot-5/index.js";
import { slotVIToIthkuil } from "./slot-6/index.js";
import { slotVIIToIthkuil } from "./slot-7/index.js";
import { caseScopeToIthkuil, moodToIthkuil, slotVIIIToIthkuil, } from "./slot-8/index.js";
import { ALL_CASES, slotIXToIthkuil, } from "./slot-9/index.js";
export * from "./default.js";
export * from "./shortcut-type.js";
export * from "./slot-1/index.js";
export * from "./slot-10/index.js";
export * from "./slot-2/index.js";
export * from "./slot-3/index.js";
export * from "./slot-4/index.js";
export * from "./slot-5/index.js";
export * from "./slot-6/index.js";
export * from "./slot-7/index.js";
export * from "./slot-8/index.js";
export * from "./slot-9/index.js";
/** An object mapping from formative types to their names. */
export const FORMATIVE_TYPE_TO_NAME_MAP = /* @__PURE__ */ deepFreeze({
"UNF/C": "Nominal",
"UNF/K": "Unframed Verbal",
FRM: "Framed Verbal",
});
const isArray = /* @__PURE__ */ (() => Array.isArray)();
/**
* Converts a formative into Ithkuil.
*
* @param formative The formative to be converted.
* @returns Romanized Ithkuilic text representing the formative.
*/
function completeFormativeToIthkuil(formative) {
const slot3 = typeof formative.root == "string" ? formative.root
: typeof formative.root == "number" || typeof formative.root == "bigint" ?
(getIntegerCr(formative.root) ?? String(formative.root))
: isArray(formative.root) ?
referentListToPersonalReferenceRoot(formative.root)
: ((typeof formative.root.cs == "number" ||
typeof formative.root.cs == "bigint") &&
getIntegerCs(formative.root.cs)) ||
"" + formative.root.cs;
let slot4 = slotIVToIthkuil(formative, {
slotIII: slot3,
affixualFormativeDegree: typeof formative.root == "object" && !isArray(formative.root) ?
formative.root.degree
: undefined,
});
let slot6 = slotVIToIthkuil(formative.ca, {
isSlotVFilled: formative.slotVAffixes.length > 0,
});
let slot1 = slotIToIthkuil({
concatenationType: formative.type == "UNF/C" ? formative.concatenationType : "none",
caShortcutType: "none",
});
let slot2 = slotIIToIthkuil(formative, {
slotI: slot1,
slotIII: formative.root,
function: formative.function,
doesSlotVHaveAtLeastTwoAffixes: formative.slotVAffixes.length >= 2,
});
const slotVIIAffixes = formative.slotVIIAffixes.slice();
let didVIIShortcut = false;
if (slotVIIAffixes.length != 0 &&
typeof formative.root == "string" &&
(formative.shortcut === true ||
formative.shortcut === "VII" ||
formative.shortcut === "VII+VIII")) {
const finalSlotVIIAffix = slotVIIAffixes.pop();
const shortcut = (finalSlotVIIAffix &&
"cs" in finalSlotVIIAffix &&
finalSlotVIIAffix.cs &&
finalSlotVIIAffix.type == 1) ?
finalSlotVIIAffix.cs == "r" && finalSlotVIIAffix.degree == 4 ? "NEG/4"
: finalSlotVIIAffix.cs == "t" ?
finalSlotVIIAffix.degree == 4 ? "DCD/4"
: finalSlotVIIAffix.degree == 5 ? "DCD/5"
: null
: null
: null;
if (shortcut) {
const slotII = SLOT_II_MAP[shortcut][formative.stem][formative.version == "CPT" ? 1 : 0];
slot2 = WithWYAlternative.of(slotII).withPreviousText(slot1);
didVIIShortcut = true;
}
else if (finalSlotVIIAffix) {
slotVIIAffixes.push(finalSlotVIIAffix);
}
}
let didVIIIShortcut = false;
if (formative.slotVAffixes.length == 0 &&
(formative.shortcut === true ||
formative.shortcut === "VIII" ||
formative.shortcut === "VII+VIII") &&
formative.vn == "MNO" &&
(formative.type == "UNF/K" ?
formative.mood != "FAC"
: formative.caseScope != "CCN") &&
formative.ca.affiliation == "CSL" &&
formative.ca.configuration == "UPX" &&
formative.ca.extension == "DEL" &&
formative.ca.perspective == "M" &&
formative.ca.essence == "NRM") {
didVIIIShortcut = true;
slot6 =
formative.type == "UNF/K" ?
moodToIthkuil(formative.mood, "non-aspect")
: caseScopeToIthkuil(formative.caseScope, "non-aspect");
}
if (!didVIIShortcut &&
!didVIIIShortcut &&
(formative.shortcut === true || formative.shortcut === "IV/VI") &&
(typeof formative.root == "string" || Array.isArray(formative.root)) &&
formative.specification == "BSC" &&
formative.context == "EXS" &&
formative.function == "STA" &&
formative.ca.configuration == "UPX" &&
formative.ca.affiliation == "CSL") {
if (Array.isArray(formative.root)) {
if (formative.ca.essence == "NRM" &&
formative.ca.perspective == "M" &&
(formative.ca.extension == "DEL" || formative.ca.extension == "PRX")) {
slot1 = slotIToIthkuil({
concatenationType: formative.type == "UNF/C" ? formative.concatenationType : "none",
caShortcutType: formative.ca.extension == "DEL" ? "w" : "y",
});
slot4 = "";
slot6 = "";
}
}
else {
const { extension, perspective, essence } = formative.ca;
const shortcut = essence == "RPV" ?
perspective == "M" && extension == "DEL" ?
1 // RPV
: perspective == "G" && extension == "DEL" ?
3 // G / RPV
: perspective == "M" && extension == "PRX" ?
3 // PRX / RPV
: null
: perspective == "M" && extension == "PRX" ?
0 // PRX
: extension == "DEL" ?
{
M: 0,
G: 1,
N: 2,
A: 2,
}[perspective]
: null;
const shortcutType = essence == "RPV" ?
perspective == "M" && extension == "DEL" ?
"y" // RPV
: perspective == "G" && extension == "DEL" ?
"y" // G / RPV
: perspective == "M" && extension == "PRX" ?
"y" // PRX / RPV
: null
: perspective == "M" && extension == "PRX" ?
"y" // PRX
: extension == "DEL" ?
{
M: "w",
G: "w",
N: "w",
A: "y",
}[perspective]
: null;
if (shortcut != null) {
slot1 = slotIToIthkuil({
concatenationType: formative.type == "UNF/C" ? formative.concatenationType : "none",
caShortcutType: shortcutType,
});
let slotII = WithWYAlternative.of(ONE_INDEXED_STANDARD_VOWEL_TABLE[shortcut][SLOT_II_SHORTCUT_MAP[formative.stem][formative.version]]);
if (formative.slotVAffixes.length >= 2) {
slotII = slotII.insertGlottalStop(false);
}
slot2 = slotII.withPreviousText(slot1);
slot4 = "";
slot6 = "";
}
}
}
const slot5 = slotVToIthkuil(formative.slotVAffixes, {
isAtEndOfWord: false,
isSlotVIElided: slot6 == "",
}).withPreviousText(slot3 + slot4);
const slot7 = slotVIIToIthkuil(slotVIIAffixes).withPreviousText(slot3 + slot4 + slot5 + slot6);
if (slot1 == "" && slot2 == "" && !isLegalWordInitialConsonantForm(slot3)) {
slot2 = "a";
}
// Nominal formatives
if (formative.type == "UNF/C") {
const slot8 = didVIIIShortcut ? "" : (slotVIIIToIthkuil({
vn: formative.vn,
cn: formative.caseScope,
}, {
omitDefault: true,
}).withPreviousText(slot3 + slot4 + slot5 + slot6 + slot7));
const slot9 = WithWYAlternative.of(slotIXToIthkuil(formative.case, {
elideIfPossible: false,
isPartOfConcatenatedFormative: formative.concatenationType != "none",
})).withPreviousText(slot3 + slot4 + slot5 + slot6 + slot7 + slot8);
const word = slot1 + slot2 + slot3 + slot4 + slot5 + slot6 + slot7 + slot8 + slot9;
if (formative.concatenationType == "none") {
return applySlotXStress(word, "UNF/C");
}
if (ALL_CASES.indexOf(formative.case) >= 36) {
return applyStress(word, -1);
}
else {
return word;
}
}
// Unframed verbal formatives
if (formative.type == "UNF/K") {
const slot8 = didVIIIShortcut ? "" : (slotVIIIToIthkuil({
vn: formative.vn,
cn: formative.mood,
}, {
omitDefault: true,
}).withPreviousText(slot3 + slot4 + slot5 + slot6 + slot7));
const slot9 = WithWYAlternative.of(slotIXToIthkuil(formative.illocutionValidation, {
elideIfPossible: false,
isPartOfConcatenatedFormative: false,
})).withPreviousText(slot3 + slot4 + slot5 + slot6 + slot7 + slot8);
const word = slot1 + slot2 + slot3 + slot4 + slot5 + slot6 + slot7 + slot8 + slot9;
return applySlotXStress(word, "UNF/K");
}
// Framed verbal formatives
if (formative.type == "FRM") {
if (countVowelForms(slot1 + slot2 + slot3 + slot4 + slot5 + slot6 + slot7) <
2 &&
slot2 == "" &&
formative.vn == "MNO" &&
formative.caseScope == "CCN") {
slot2 = "a";
}
const slot8 = didVIIIShortcut ? "" : (slotVIIIToIthkuil({
vn: formative.vn,
cn: formative.caseScope,
}, {
omitDefault: countVowelForms(slot1 + slot2 + slot3 + slot4 + slot5 + slot6 + slot7) >= 2,
}).withPreviousText(slot3 + slot4 + slot5 + slot6 + slot7));
const slot9 = WithWYAlternative.of(slotIXToIthkuil(formative.case, {
elideIfPossible: false,
isPartOfConcatenatedFormative: false,
})).withPreviousText(slot3 + slot4 + slot5 + slot6 + slot7 + slot8);
if (countVowelForms(slot1 + slot2 + slot3 + slot4 + slot5 + slot6 + slot7 + slot8 + slot9) < 3 &&
slot2 == "") {
slot2 = "a";
}
const word = slot1 + slot2 + slot3 + slot4 + slot5 + slot6 + slot7 + slot8 + slot9;
return applySlotXStress(word, "FRM");
}
throw new Error("Unknown formative type '" + formative?.type + "'.");
}
/**
* Converts a formative into Ithkuil.
*
* @param formative The formative to be converted.
* @returns Romanized Ithkuilic text representing the formative.
*/
export function formativeToIthkuil(formative) {
return completeFormativeToIthkuil(fillInDefaultFormativeSlots(formative));
}