mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
293 lines
11 KiB
JavaScript
293 lines
11 KiB
JavaScript
/*
|
|
* Copyright (C) 2024-2025 Yomitan Authors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import {prefixInflection, suffixInflection} from '../language-transforms.js';
|
|
|
|
/** @typedef {keyof typeof conditions} Condition */
|
|
|
|
/**
|
|
* @param {string} consonants
|
|
* @param {string} suffix
|
|
* @param {Condition[]} conditionsIn
|
|
* @param {Condition[]} conditionsOut
|
|
* @returns {import('language-transformer').SuffixRule<Condition>[]}
|
|
*/
|
|
function doubledConsonantInflection(consonants, suffix, conditionsIn, conditionsOut) {
|
|
const inflections = [];
|
|
for (const consonant of consonants) {
|
|
inflections.push(suffixInflection(`${consonant}${consonant}${suffix}`, consonant, conditionsIn, conditionsOut));
|
|
}
|
|
return inflections;
|
|
}
|
|
|
|
const pastSuffixInflections = [
|
|
suffixInflection('ed', '', ['v'], ['v']), // 'walked'
|
|
suffixInflection('ed', 'e', ['v'], ['v']), // 'hoped'
|
|
suffixInflection('ied', 'y', ['v'], ['v']), // 'tried'
|
|
suffixInflection('cked', 'c', ['v'], ['v']), // 'frolicked'
|
|
...doubledConsonantInflection('bdgklmnprstz', 'ed', ['v'], ['v']),
|
|
|
|
suffixInflection('laid', 'lay', ['v'], ['v']),
|
|
suffixInflection('paid', 'pay', ['v'], ['v']),
|
|
suffixInflection('said', 'say', ['v'], ['v']),
|
|
];
|
|
|
|
const ingSuffixInflections = [
|
|
suffixInflection('ing', '', ['v'], ['v']), // 'walking'
|
|
suffixInflection('ing', 'e', ['v'], ['v']), // 'driving'
|
|
suffixInflection('ying', 'ie', ['v'], ['v']), // 'lying'
|
|
suffixInflection('cking', 'c', ['v'], ['v']), // 'panicking'
|
|
...doubledConsonantInflection('bdgklmnprstz', 'ing', ['v'], ['v']),
|
|
];
|
|
|
|
const thirdPersonSgPresentSuffixInflections = [
|
|
suffixInflection('s', '', ['v'], ['v']), // 'walks'
|
|
suffixInflection('es', '', ['v'], ['v']), // 'teaches'
|
|
suffixInflection('ies', 'y', ['v'], ['v']), // 'tries'
|
|
];
|
|
|
|
const phrasalVerbParticles = ['aboard', 'about', 'above', 'across', 'ahead', 'alongside', 'apart', 'around', 'aside', 'astray', 'away', 'back', 'before', 'behind', 'below', 'beneath', 'besides', 'between', 'beyond', 'by', 'close', 'down', 'east', 'west', 'north', 'south', 'eastward', 'westward', 'northward', 'southward', 'forward', 'backward', 'backwards', 'forwards', 'home', 'in', 'inside', 'instead', 'near', 'off', 'on', 'opposite', 'out', 'outside', 'over', 'overhead', 'past', 'round', 'since', 'through', 'throughout', 'together', 'under', 'underneath', 'up', 'within', 'without'];
|
|
const phrasalVerbPrepositions = ['aback', 'about', 'above', 'across', 'after', 'against', 'ahead', 'along', 'among', 'apart', 'around', 'as', 'aside', 'at', 'away', 'back', 'before', 'behind', 'below', 'between', 'beyond', 'by', 'down', 'even', 'for', 'forth', 'forward', 'from', 'in', 'into', 'of', 'off', 'on', 'onto', 'open', 'out', 'over', 'past', 'round', 'through', 'to', 'together', 'toward', 'towards', 'under', 'up', 'upon', 'way', 'with', 'without'];
|
|
|
|
const particlesDisjunction = phrasalVerbParticles.join('|');
|
|
const phrasalVerbWordSet = new Set([...phrasalVerbParticles, ...phrasalVerbPrepositions]);
|
|
const phrasalVerbWordDisjunction = [...phrasalVerbWordSet].join('|');
|
|
/**
|
|
* @type {import('language-transformer').Rule<Condition>}
|
|
*/
|
|
const phrasalVerbInterposedObjectRule = {
|
|
type: 'other',
|
|
isInflected: new RegExp(`^\\w* (?:(?!\\b(${phrasalVerbWordDisjunction})\\b).)+ (?:${particlesDisjunction})`),
|
|
deinflect: (term) => {
|
|
return term.replace(new RegExp(`(?<=\\w) (?:(?!\\b(${phrasalVerbWordDisjunction})\\b).)+ (?=(?:${particlesDisjunction}))`), ' ');
|
|
},
|
|
conditionsIn: [],
|
|
conditionsOut: ['v_phr'],
|
|
};
|
|
|
|
/**
|
|
* @param {string} inflected
|
|
* @param {string} deinflected
|
|
* @returns {import('language-transformer').Rule<Condition>}
|
|
*/
|
|
function createPhrasalVerbInflection(inflected, deinflected) {
|
|
return {
|
|
type: 'other',
|
|
isInflected: new RegExp(`^\\w*${inflected} (?:${phrasalVerbWordDisjunction})`),
|
|
deinflect: (term) => {
|
|
return term.replace(new RegExp(`(?<=)${inflected}(?= (?:${phrasalVerbWordDisjunction}))`), deinflected);
|
|
},
|
|
conditionsIn: ['v'],
|
|
conditionsOut: ['v_phr'],
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {import('language-transformer').SuffixRule<Condition>[]} sourceRules
|
|
* @returns {import('language-transformer').Rule<Condition>[]}
|
|
*/
|
|
function createPhrasalVerbInflectionsFromSuffixInflections(sourceRules) {
|
|
return sourceRules.flatMap(({isInflected, deinflected}) => {
|
|
if (typeof deinflected === 'undefined') { return []; }
|
|
const inflectedSuffix = isInflected.source.replace('$', '');
|
|
const deinflectedSuffix = deinflected;
|
|
return [createPhrasalVerbInflection(inflectedSuffix, deinflectedSuffix)];
|
|
});
|
|
}
|
|
|
|
const conditions = {
|
|
v: {
|
|
name: 'Verb',
|
|
isDictionaryForm: true,
|
|
subConditions: ['v_phr'],
|
|
},
|
|
v_phr: {
|
|
name: 'Phrasal verb',
|
|
isDictionaryForm: true,
|
|
},
|
|
n: {
|
|
name: 'Noun',
|
|
isDictionaryForm: true,
|
|
subConditions: ['np', 'ns'],
|
|
},
|
|
np: {
|
|
name: 'Noun plural',
|
|
isDictionaryForm: true,
|
|
},
|
|
ns: {
|
|
name: 'Noun singular',
|
|
isDictionaryForm: true,
|
|
},
|
|
adj: {
|
|
name: 'Adjective',
|
|
isDictionaryForm: true,
|
|
},
|
|
adv: {
|
|
name: 'Adverb',
|
|
isDictionaryForm: true,
|
|
},
|
|
};
|
|
|
|
/** @type {import('language-transformer').LanguageTransformDescriptor<Condition>} */
|
|
export const englishTransforms = {
|
|
language: 'en',
|
|
conditions,
|
|
transforms: {
|
|
'plural': {
|
|
name: 'plural',
|
|
description: 'Plural form of a noun',
|
|
rules: [
|
|
suffixInflection('s', '', ['np'], ['ns']),
|
|
suffixInflection('es', '', ['np'], ['ns']),
|
|
suffixInflection('ies', 'y', ['np'], ['ns']),
|
|
suffixInflection('ves', 'fe', ['np'], ['ns']),
|
|
suffixInflection('ves', 'f', ['np'], ['ns']),
|
|
],
|
|
},
|
|
'possessive': {
|
|
name: 'possessive',
|
|
description: 'Possessive form of a noun',
|
|
rules: [
|
|
suffixInflection('\'s', '', ['n'], ['n']),
|
|
suffixInflection('s\'', 's', ['n'], ['n']),
|
|
],
|
|
},
|
|
'past': {
|
|
name: 'past',
|
|
description: 'Simple past tense of a verb',
|
|
rules: [
|
|
...pastSuffixInflections,
|
|
...createPhrasalVerbInflectionsFromSuffixInflections(pastSuffixInflections),
|
|
],
|
|
},
|
|
'ing': {
|
|
name: 'ing',
|
|
description: 'Present participle of a verb',
|
|
rules: [
|
|
...ingSuffixInflections,
|
|
...createPhrasalVerbInflectionsFromSuffixInflections(ingSuffixInflections),
|
|
],
|
|
},
|
|
'3rd pers. sing. pres': {
|
|
name: '3rd pers. sing. pres',
|
|
description: 'Third person singular present tense of a verb',
|
|
rules: [
|
|
...thirdPersonSgPresentSuffixInflections,
|
|
...createPhrasalVerbInflectionsFromSuffixInflections(thirdPersonSgPresentSuffixInflections),
|
|
],
|
|
},
|
|
'interposed object': {
|
|
name: 'interposed object',
|
|
description: 'Phrasal verb with interposed object',
|
|
rules: [
|
|
phrasalVerbInterposedObjectRule,
|
|
],
|
|
},
|
|
'archaic': {
|
|
name: 'archaic',
|
|
description: 'Archaic form of a word',
|
|
rules: [
|
|
suffixInflection('\'d', 'ed', ['v'], ['v']),
|
|
],
|
|
},
|
|
'adverb': {
|
|
name: 'adverb',
|
|
description: 'Adverb form of an adjective',
|
|
rules: [
|
|
suffixInflection('ly', '', ['adv'], ['adj']), // 'quickly'
|
|
suffixInflection('ily', 'y', ['adv'], ['adj']), // 'happily'
|
|
suffixInflection('ly', 'le', ['adv'], ['adj']), // 'humbly'
|
|
],
|
|
},
|
|
'comparative': {
|
|
name: 'comparative',
|
|
description: 'Comparative form of an adjective',
|
|
rules: [
|
|
suffixInflection('er', '', ['adj'], ['adj']), // 'faster'
|
|
suffixInflection('er', 'e', ['adj'], ['adj']), // 'nicer'
|
|
suffixInflection('ier', 'y', ['adj'], ['adj']), // 'happier'
|
|
...doubledConsonantInflection('bdgmnt', 'er', ['adj'], ['adj']),
|
|
],
|
|
},
|
|
'superlative': {
|
|
name: 'superlative',
|
|
description: 'Superlative form of an adjective',
|
|
rules: [
|
|
suffixInflection('est', '', ['adj'], ['adj']), // 'fastest'
|
|
suffixInflection('est', 'e', ['adj'], ['adj']), // 'nicest'
|
|
suffixInflection('iest', 'y', ['adj'], ['adj']), // 'happiest'
|
|
...doubledConsonantInflection('bdgmnt', 'est', ['adj'], ['adj']),
|
|
],
|
|
},
|
|
'dropped g': {
|
|
name: 'dropped g',
|
|
description: 'Dropped g in -ing form of a verb',
|
|
rules: [
|
|
suffixInflection('in\'', 'ing', ['v'], ['v']),
|
|
],
|
|
},
|
|
'-y': {
|
|
name: '-y',
|
|
description: 'Adjective formed from a verb or noun',
|
|
rules: [
|
|
suffixInflection('y', '', ['adj'], ['n', 'v']), // 'dirty', 'pushy'
|
|
suffixInflection('y', 'e', ['adj'], ['n', 'v']), // 'hazy'
|
|
...doubledConsonantInflection('glmnprst', 'y', [], ['n', 'v']), // 'baggy', 'saggy'
|
|
],
|
|
},
|
|
'un-': {
|
|
name: 'un-',
|
|
description: 'Negative form of an adjective, adverb, or verb',
|
|
rules: [
|
|
prefixInflection('un', '', ['adj', 'adv', 'v'], ['adj', 'adv', 'v']),
|
|
],
|
|
},
|
|
'going-to future': {
|
|
name: 'going-to future',
|
|
description: 'Going-to future tense of a verb',
|
|
rules: [
|
|
prefixInflection('going to ', '', ['v'], ['v']),
|
|
],
|
|
},
|
|
'will future': {
|
|
name: 'will future',
|
|
description: 'Will-future tense of a verb',
|
|
rules: [
|
|
prefixInflection('will ', '', ['v'], ['v']),
|
|
],
|
|
},
|
|
'imperative negative': {
|
|
name: 'imperative negative',
|
|
description: 'Negative imperative form of a verb',
|
|
rules: [
|
|
prefixInflection('don\'t ', '', ['v'], ['v']),
|
|
prefixInflection('do not ', '', ['v'], ['v']),
|
|
],
|
|
},
|
|
'-able': {
|
|
name: '-able',
|
|
description: 'Adjective formed from a verb',
|
|
rules: [
|
|
suffixInflection('able', '', ['v'], ['adj']),
|
|
suffixInflection('able', 'e', ['v'], ['adj']),
|
|
suffixInflection('iable', 'y', ['v'], ['adj']),
|
|
...doubledConsonantInflection('bdgklmnprstz', 'able', ['v'], ['adj']),
|
|
],
|
|
},
|
|
},
|
|
};
|