From 509001f004608a203ed05285ffe332af2d50740d Mon Sep 17 00:00:00 2001 From: Jean Date: Fri, 21 Feb 2025 20:03:29 -0800 Subject: [PATCH] Improving on verb handling, fixes #17, fixes #20, fixes #27 --- src/replace-words.js | 228 +++++++++++++++++++++++++++++++++---------- 1 file changed, 176 insertions(+), 52 deletions(-) diff --git a/src/replace-words.js b/src/replace-words.js index 73ad3a0..e2b5859 100644 --- a/src/replace-words.js +++ b/src/replace-words.js @@ -38,20 +38,25 @@ function replaceAll() { /* Replaces all instances of "Y/n" with the user's name */ function replaceName(options) { - const search_term = /\by\/n\b|\(y\/n\)|\[y\/n\]/ig; - walk(document.body, search_term, options["name"], directMethod); + const searchTerm = /\by\/n\b|\(y\/n\)|\[y\/n\]/ig; + walk(document.body, searchTerm, options["name"], directMethod); } /* Replaces all verb keys */ function replaceVerbs(options) { - const isPluralThird = options.pov == "third" && getPronouns(options.preset, options.other).plurality == "plural"; - if (isPluralThird) { - const search_term = /([Pp])(?:rn|ov)\/S [Vv]rb\/([\w\s]+)\/([\w\s]+)\/|[Vv]rb\/([\w\s]+)\/([\w\s]+)\/ ([Pp])(?:rn|ov)\/S/; - walk(document.body, search_term, options, pluralThirdVerbMethod); + const isPlural = getPronouns(options.preset, options.other).plurality == "plural"; + if (isPlural) { + walk(document.body, /([Vv])r([Nn])\/([\w\s]+)\/([\w\s]+)\//, options, pluralPrnVerbMethod); + } else { + walk(document.body, /([Vv])r[Nn]\/([\w\s]+)\/([\w\s]+)\//, options, prnVerbMethod); } - const search_term = /vrb\/([\w\s]+)\/([\w\s]+)\//; - walk(document.body, search_term, options, verbMethod); + const isPluralThird = isPlural && options.pov == "third"; + if (isPluralThird) { + walk(document.body, /([Vv])r([Bb])\/([\w\s]+)\/([\w\s]+)\//, options, pluralThirdVerbMethod); + } else { + walk(document.body, /([Vv])r[Bb]\/([\w\s]+)\/([\w\s]+)\//, options, verbMethod); + } } /* Replaces all pronoun keys */ @@ -225,21 +230,21 @@ function replaceAlso(options) { } /* Turns a term into regexp format and uses that to replace it */ -function escapeAndReplace(search_term, replace_value, case_sensitive) { - let search_term_escaped = search_term.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - const flags = case_sensitive ? "g" : "ig" - if (search_term_escaped[0].match(/[a-z]/i)) { - search_term_escaped = `\\b${search_term_escaped}` +function escapeAndReplace(searchTerm, replaceValue, caseSensitive) { + let searchTermEscaped = searchTerm.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + const flags = caseSensitive ? "g" : "ig" + if (searchTermEscaped[0].match(/[a-z]/i)) { + searchTermEscaped = `\\b${searchTermEscaped}` } - if (search_term_escaped[search_term_escaped.length - 1].match((/[a-z]/i))) { - search_term_escaped = `${search_term_escaped}\\b` + if (searchTermEscaped[searchTermEscaped.length - 1].match((/[a-z]/i))) { + searchTermEscaped = `${searchTermEscaped}\\b` } - const search_term_regexp = new RegExp(search_term_escaped, flags) - walk(document.body, search_term_regexp, replace_value, directMethod); + const searchTermRegexp = new RegExp(searchTermEscaped, flags) + walk(document.body, searchTermRegexp, replaceValue, directMethod); } /* Traverses a node and its children to run the provided replacement method */ -function walk(node, search_term, replace_value, replaceMethod) { +function walk(node, searchTerm, replaceValue, replaceMethod) { if (node.contentEditable == "true" || node.type == "textarea" || node.type == "input") { return; } let child, next; switch (node.nodeType) { @@ -249,58 +254,143 @@ function walk(node, search_term, replace_value, replaceMethod) { child = node.firstChild; while (child) { next = child.nextSibling; - walk(child, search_term, replace_value, replaceMethod); + walk(child, searchTerm, replaceValue, replaceMethod); child = next; } break; case 3: /* TEXT_NODE */ - replaceMethod(node, search_term, replace_value); + replaceMethod(node, searchTerm, replaceValue); } } /* Replaces all of the provided terms in a node */ -function directMethod(node, search_term, replace_value) { - node.nodeValue = node.nodeValue.replaceAll(search_term, replace_value); +function directMethod(node, searchTerm, replaceValue) { + node.nodeValue = node.nodeValue.replaceAll(searchTerm, replaceValue); } /* Replaces all verbs, not used for third-person plural */ -/* TODO Is the "options" variable here readable? It's not replace_value and that seems bad */ -function verbMethod(node, search_term, options) { - let match = node.nodeValue.match(search_term); +/* TODO Is the "options" variable here readable? It's not replaceValue and that seems bad */ +function verbMethod(node, searchTerm, options) { + let match = node.nodeValue.match(searchTerm); if (match == null) { return; } - const verb = match[1]; - const tense = match[2].toUpperCase().replaceAll(" ", "_"); - const replace_value = verbsHelper.getConjugation(verbsData, verb, tense, getPovIndex(options)); - node.nodeValue = node.nodeValue.replace(search_term, replace_value); - verbMethod(node, search_term, options); + const isCapital = /V/.test(match[1]); + const verb = match[2]; + let tense = getTense(match[3]); + const isTenseProvided = tense != null; + if (!isTenseProvided) { + tense = "PAST"; + } + + let replaceValue = verbsHelper.getConjugation(verbsData, verb, tense, getPovIndex(options)); + + if (isCapital) { + replaceValue = capitalize(replaceValue); + } + + if (isTenseProvided) { + node.nodeValue = node.nodeValue.replace(searchTerm, replaceValue); + } else { + const searchTermShortVerb = /([Vv])r[Bb]\/([\w\s]+)\// + node.nodeValue = node.nodeValue.replace(searchTermShortVerb, replaceValue); + } + + verbMethod(node, searchTerm, options); } /* Replaces all verbs, used only for third-person plural */ -/* TODO This is meant to be able to replace in both subject-object and object-subject order, but it's only the first for now. */ -function pluralThirdVerbMethod(node, search_term, options) { - let match = node.nodeValue.match(search_term); +function pluralThirdVerbMethod(node, searchTerm, options) { + let match = node.nodeValue.match(searchTerm); if (match == null) { return; } - const before = match[1]; - const after = match[4]; - const wasBefore = !(before === undefined); - let verb, tense; - if (wasBefore) { - verb = match[2]; - tense = match[3]; - } else { - verb = match[5]; - tense = match[6]; + const isCapital = /V/.test(match[1]); + const isNamedActor = /B/.test(match[2]); + const verb = match[3]; + let tense = getTense(match[4]); + const isTenseProvided = tense != null; + if (!isTenseProvided) { + tense = "PAST"; } - tense = tense.toUpperCase().replaceAll(" ", "_"); - const replace_verb = verbsHelper.getConjugation(verbsData, verb, tense, 2); - let replace_value; - if (wasBefore) { - replace_value = options["name"] + " " + replace_verb; + + let replaceValue; + if (isNamedActor) { + replaceValue = verbsHelper.getConjugation(verbsData, verb, tense, 2); } else { - replace_value = replace_verb + " " + options["name"]; + replaceValue = verbsHelper.getConjugation(verbsData, verb, tense, getPovIndex(options)); } - node.nodeValue = node.nodeValue.replace(search_term, replace_value); - pluralThirdVerbMethod(node, search_term, options); + + if (isCapital) { + replaceValue = capitalize(replaceValue); + } + + if (isTenseProvided) { + node.nodeValue = node.nodeValue.replace(searchTerm, replaceValue); + } else { + const searchTermShortVerb = /([Vv])r([Bb])\/([\w\s]+)\// + node.nodeValue = node.nodeValue.replace(searchTermShortVerb, replaceValue); + } + + pluralThirdVerbMethod(node, searchTerm, options); +} + +/* Replaces verbs by pronoun rather than POV, not used for plural */ +function prnVerbMethod(node, searchTerm, options) { + let match = node.nodeValue.match(searchTerm); + if (match == null) { return; } + const isCapital = /V/.test(match[1]); + const verb = match[2]; + let tense = getTense(match[3]); + const isTenseProvided = tense != null; + if (!isTenseProvided) { + tense = "PAST"; + } + + let replaceValue = verbsHelper.getConjugation(verbsData, verb, tense, 2); + + if (isCapital) { + replaceValue = capitalize(replaceValue); + } + + if (isTenseProvided) { + node.nodeValue = node.nodeValue.replace(searchTerm, replaceValue); + } else { + const searchTermShortVerb = /([Vv])r[Bb]\/([\w\s]+)\// + node.nodeValue = node.nodeValue.replace(searchTermShortVerb, replaceValue); + } + + prnVerbMethod(node, searchTerm, options); +} + +/* Replaces verbs by pronoun rather than POV, used only for plural */ +function pluralPrnVerbMethod(node, searchTerm, options) { + let match = node.nodeValue.match(searchTerm); + if (match == null) { return; } + const isCapital = /V/.test(match[1]); + const isNamedActor = /N/.test(match[2]); + const verb = match[3]; + let tense = getTense(match[4]); + const isTenseProvided = tense != null; + if (!isTenseProvided) { + tense = "PAST"; + } + + let replaceValue; + if (isNamedActor) { + replaceValue = verbsHelper.getConjugation(verbsData, verb, tense, 2); + } else { + replaceValue = verbsHelper.getConjugation(verbsData, verb, tense, 5); + } + + if (isCapital) { + replaceValue = capitalize(replaceValue); + } + + if (isTenseProvided) { + node.nodeValue = node.nodeValue.replace(searchTerm, replaceValue); + } else { + const searchTermShortVerb = /([Vv])r([Bb])\/([\w\s]+)\// + node.nodeValue = node.nodeValue.replace(searchTermShortVerb, replaceValue); + } + + pluralPrnVerbMethod(node, searchTerm, options); } /* Returns the input word, capitalized */ @@ -309,7 +399,6 @@ function capitalize(word) { } /* Determines the index for point-of-view to be used when conjugating verbs */ -/* TODO Did I ever implement third-person plural? */ function getPovIndex(options) { switch (options.pov) { case "first": @@ -325,4 +414,39 @@ function getPovIndex(options) { } } +/* Gets the verb tense from a regexp match */ +function getTense(match) { + const tense = match.toUpperCase().replaceAll(" ", "_"); + const tenses = [ + // SIMPLE + 'SIMPLE_PAST', + 'PAST', + 'SIMPLE_PRESENT', + 'PRESENT', + 'SIMPLE_FUTURE', + 'FUTURE', + // PROGRESSIVE + 'PROGRESSIVE_PAST', + 'PROGRESSIVE_PRESENT', + 'PROGRESSIVE_FUTURE', + // PERFECT + 'PERFECT_PAST', + 'PERFECT_PRESENT', + 'PERFECT_FUTURE', + // PERFECT PROGRESSIVE + 'PERFECT_PROGRESSIVE_PAST', + 'PERFECT_PROGRESSIVE_PRESENT', + 'PERFECT_PROGRESSIVE_FUTURE', + // PARTICIPLE + 'PARTICIPLE_PRESENT', + 'PARTICIPLE_PAST', + ]; + + if (tenses.indexOf(tense) == -1) { + return null; + } else { + return tense; + } +} + replaceAll();