@valueerror/ltjs-lang-en 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/LICENSE +232 -0
  2. package/NOTICE +10 -0
  3. package/README.md +25 -2
  4. package/index.js +34 -0
  5. package/licenses/LGPL-2.1.txt +504 -0
  6. package/licenses/english-pos-dict.pom.xml +135 -0
  7. package/licenses/resource_en_12dicts-readme.html +738 -0
  8. package/licenses/resource_en_agid-readme.txt +340 -0
  9. package/licenses/resource_en_pos-readme.txt +115 -0
  10. package/package.json +60 -4
  11. package/resource-root.js +4 -0
  12. package/resources/META-INF/org/languagetool/language-module.properties +1 -0
  13. package/resources/en-chunker.bin +0 -0
  14. package/resources/en-pos-maxent.bin +0 -0
  15. package/resources/en-token.bin +0 -0
  16. package/resources/org/languagetool/resource/en/12dicts-readme.html +738 -0
  17. package/resources/org/languagetool/resource/en/added.txt +446 -0
  18. package/resources/org/languagetool/resource/en/added_custom.txt +4 -0
  19. package/resources/org/languagetool/resource/en/agid-readme.txt +340 -0
  20. package/resources/org/languagetool/resource/en/compounds.txt +9059 -0
  21. package/resources/org/languagetool/resource/en/confusion_sets.txt +871 -0
  22. package/resources/org/languagetool/resource/en/disambiguation.xml +17238 -0
  23. package/resources/org/languagetool/resource/en/do-not-synthesize.txt +13 -0
  24. package/resources/org/languagetool/resource/en/en-US-GB.txt +4804 -0
  25. package/resources/org/languagetool/resource/en/en.sor +211 -0
  26. package/resources/org/languagetool/resource/en/english.dict +0 -0
  27. package/resources/org/languagetool/resource/en/english.info +8 -0
  28. package/resources/org/languagetool/resource/en/english_synth.dict +0 -0
  29. package/resources/org/languagetool/resource/en/english_synth.info +7 -0
  30. package/resources/org/languagetool/resource/en/english_tags.txt +88 -0
  31. package/resources/org/languagetool/resource/en/hunspell/en_AU.dict +0 -0
  32. package/resources/org/languagetool/resource/en/hunspell/en_AU.info +16 -0
  33. package/resources/org/languagetool/resource/en/hunspell/en_CA.dict +0 -0
  34. package/resources/org/languagetool/resource/en/hunspell/en_CA.info +13 -0
  35. package/resources/org/languagetool/resource/en/hunspell/en_GB.dict +0 -0
  36. package/resources/org/languagetool/resource/en/hunspell/en_GB.info +15 -0
  37. package/resources/org/languagetool/resource/en/hunspell/en_NZ.dict +0 -0
  38. package/resources/org/languagetool/resource/en/hunspell/en_NZ.info +18 -0
  39. package/resources/org/languagetool/resource/en/hunspell/en_US.dict +0 -0
  40. package/resources/org/languagetool/resource/en/hunspell/en_US.info +15 -0
  41. package/resources/org/languagetool/resource/en/hunspell/en_ZA.dict +0 -0
  42. package/resources/org/languagetool/resource/en/hunspell/en_ZA.info +16 -0
  43. package/resources/org/languagetool/resource/en/hunspell/ignore.txt +11070 -0
  44. package/resources/org/languagetool/resource/en/hunspell/prohibit.txt +383 -0
  45. package/resources/org/languagetool/resource/en/hunspell/prohibit_custom.txt +1 -0
  46. package/resources/org/languagetool/resource/en/hunspell/spelling.txt +477 -0
  47. package/resources/org/languagetool/resource/en/hunspell/spelling_custom.txt +1 -0
  48. package/resources/org/languagetool/resource/en/hunspell/spelling_en-AU.txt +34 -0
  49. package/resources/org/languagetool/resource/en/hunspell/spelling_en-CA.txt +28 -0
  50. package/resources/org/languagetool/resource/en/hunspell/spelling_en-GB.txt +44 -0
  51. package/resources/org/languagetool/resource/en/hunspell/spelling_en-NZ.txt +31 -0
  52. package/resources/org/languagetool/resource/en/hunspell/spelling_en-US.txt +41 -0
  53. package/resources/org/languagetool/resource/en/hunspell/spelling_en-ZA.txt +32 -0
  54. package/resources/org/languagetool/resource/en/hunspell/spelling_merged.txt +0 -0
  55. package/resources/org/languagetool/resource/en/multiwords.txt +8210 -0
  56. package/resources/org/languagetool/resource/en/pos-readme.txt +115 -0
  57. package/resources/org/languagetool/resource/en/removed.txt +31 -0
  58. package/resources/org/languagetool/resource/en/removed_custom.txt +4 -0
  59. package/resources/org/languagetool/resource/en/specific_case.txt +5621 -0
  60. package/resources/org/languagetool/resource/en/word_definitions.txt +1510 -0
  61. package/resources/org/languagetool/rules/en/coherency.txt +2501 -0
  62. package/resources/org/languagetool/rules/en/contractions.txt +198 -0
  63. package/resources/org/languagetool/rules/en/det_a.txt +959 -0
  64. package/resources/org/languagetool/rules/en/det_an.txt +4080 -0
  65. package/resources/org/languagetool/rules/en/diacritics.txt +1415 -0
  66. package/resources/org/languagetool/rules/en/en-AU/grammar.xml +171 -0
  67. package/resources/org/languagetool/rules/en/en-CA/grammar.xml +197 -0
  68. package/resources/org/languagetool/rules/en/en-GB/grammar.xml +555 -0
  69. package/resources/org/languagetool/rules/en/en-GB/replace.txt +104 -0
  70. package/resources/org/languagetool/rules/en/en-GB/style.xml +302 -0
  71. package/resources/org/languagetool/rules/en/en-NZ/grammar.xml +171 -0
  72. package/resources/org/languagetool/rules/en/en-NZ/replace.txt +5 -0
  73. package/resources/org/languagetool/rules/en/en-US/grammar.xml +913 -0
  74. package/resources/org/languagetool/rules/en/en-US/replace.txt +74 -0
  75. package/resources/org/languagetool/rules/en/en-US/style.xml +524 -0
  76. package/resources/org/languagetool/rules/en/grammar-l2-de.xml +227 -0
  77. package/resources/org/languagetool/rules/en/grammar-l2-fr.xml +39 -0
  78. package/resources/org/languagetool/rules/en/grammar.xml +142537 -0
  79. package/resources/org/languagetool/rules/en/redundancies.txt +866 -0
  80. package/resources/org/languagetool/rules/en/remote-rule-filters.xml +3622 -0
  81. package/resources/org/languagetool/rules/en/replace.txt +221 -0
  82. package/resources/org/languagetool/rules/en/replace_custom.txt +7 -0
  83. package/resources/org/languagetool/rules/en/replace_profanity.txt +540 -0
  84. package/resources/org/languagetool/rules/en/style.xml +12556 -0
  85. package/resources/org/languagetool/rules/en/synonyms.txt +42 -0
  86. package/resources/org/languagetool/rules/en/wordiness.txt +1061 -0
  87. package/resources/org/languagetool/rules/en/wrongWordInContext.txt +14 -0
  88. package/src/lang/en/chunking/EnglishChunkFilter.js +108 -0
  89. package/src/lang/en/chunking/EnglishChunker.js +135 -0
  90. package/src/lang/en/language/AmericanEnglish.js +73 -0
  91. package/src/lang/en/language/AustralianEnglish.js +42 -0
  92. package/src/lang/en/language/BritishEnglish.js +91 -0
  93. package/src/lang/en/language/CanadianEnglish.js +70 -0
  94. package/src/lang/en/language/English.js +398 -0
  95. package/src/lang/en/language/NewZealandEnglish.js +44 -0
  96. package/src/lang/en/language/SouthAfricanEnglish.js +40 -0
  97. package/src/lang/en/language/id2prioBritishEnglish.js +6 -0
  98. package/src/lang/en/language/id2prioEnglish.js +333 -0
  99. package/src/lang/en/rules/AbstractEnglishSpellerRule.js +677 -0
  100. package/src/lang/en/rules/AbstractEnglishSpellerRuleData.js +778 -0
  101. package/src/lang/en/rules/AdvancedSynthesizerFilter.js +12 -0
  102. package/src/lang/en/rules/AdverbFilter.js +538 -0
  103. package/src/lang/en/rules/AmericanReplaceRule.js +57 -0
  104. package/src/lang/en/rules/AvsAnData.js +37 -0
  105. package/src/lang/en/rules/AvsAnRule.js +182 -0
  106. package/src/lang/en/rules/BritishReplaceRule.js +57 -0
  107. package/src/lang/en/rules/CompoundRule.js +150 -0
  108. package/src/lang/en/rules/ConsistentApostrophesRule.js +87 -0
  109. package/src/lang/en/rules/ContractionSpellingRule.js +64 -0
  110. package/src/lang/en/rules/DateCheckFilter.js +58 -0
  111. package/src/lang/en/rules/DateFilterHelper.js +51 -0
  112. package/src/lang/en/rules/EnglishConvertToSentenceCaseFilter.js +17 -0
  113. package/src/lang/en/rules/EnglishDashRule.js +42 -0
  114. package/src/lang/en/rules/EnglishDiacriticsRule.js +67 -0
  115. package/src/lang/en/rules/EnglishMultitokenSpeller.js +15 -0
  116. package/src/lang/en/rules/EnglishNumberInWordFilter.js +38 -0
  117. package/src/lang/en/rules/EnglishPartialPosTagFilter.js +29 -0
  118. package/src/lang/en/rules/EnglishPlainEnglishRule.js +67 -0
  119. package/src/lang/en/rules/EnglishRedundancyRule.js +67 -0
  120. package/src/lang/en/rules/EnglishRepeatedWordsRule.js +212 -0
  121. package/src/lang/en/rules/EnglishSpecificCaseRule.js +47 -0
  122. package/src/lang/en/rules/EnglishSuppressMisspelledSuggestionsFilter.js +12 -0
  123. package/src/lang/en/rules/EnglishUnpairedBracketsRule.js +25 -0
  124. package/src/lang/en/rules/EnglishUnpairedQuotesRule.js +41 -0
  125. package/src/lang/en/rules/EnglishWordRepeatBeginningRule.js +107 -0
  126. package/src/lang/en/rules/EnglishWordRepeatRule.js +126 -0
  127. package/src/lang/en/rules/EnglishWrongWordInContextRule.js +50 -0
  128. package/src/lang/en/rules/FindSuggestionsFilter.js +41 -0
  129. package/src/lang/en/rules/FutureDateFilter.js +25 -0
  130. package/src/lang/en/rules/LongSentenceRule.js +19 -0
  131. package/src/lang/en/rules/MorfologikAmericanSpellerRule.js +69 -0
  132. package/src/lang/en/rules/MorfologikAustralianSpellerRule.js +45 -0
  133. package/src/lang/en/rules/MorfologikBritishSpellerRule.js +47 -0
  134. package/src/lang/en/rules/MorfologikCanadianSpellerRule.js +45 -0
  135. package/src/lang/en/rules/MorfologikNewZealandSpellerRule.js +45 -0
  136. package/src/lang/en/rules/MorfologikSouthAfricanSpellerRule.js +45 -0
  137. package/src/lang/en/rules/NewYearDateFilter.js +25 -0
  138. package/src/lang/en/rules/NewZealandReplaceRule.js +56 -0
  139. package/src/lang/en/rules/NoDisambiguationEnglishPartialPosTagFilter.js +24 -0
  140. package/src/lang/en/rules/OrdinalSuffixFilter.js +33 -0
  141. package/src/lang/en/rules/SimpleReplaceProfanityRule.js +55 -0
  142. package/src/lang/en/rules/SimpleReplaceRule.js +46 -0
  143. package/src/lang/en/rules/StyleTooOftenUsedAdjectiveRule.js +58 -0
  144. package/src/lang/en/rules/StyleTooOftenUsedNounRule.js +58 -0
  145. package/src/lang/en/rules/StyleTooOftenUsedVerbRule.js +58 -0
  146. package/src/lang/en/rules/UnitConversionRule.js +47 -0
  147. package/src/lang/en/rules/UnitConversionRuleImperial.js +57 -0
  148. package/src/lang/en/rules/UnitConversionRuleUS.js +62 -0
  149. package/src/lang/en/rules/VariantInfo.js +23 -0
  150. package/src/lang/en/rules/WordCoherencyRule.js +40 -0
  151. package/src/lang/en/rules/YMDDateCheckFilter.js +25 -0
  152. package/src/lang/en/rules/YMDNewYearDateFilter.js +25 -0
  153. package/src/lang/en/rules/translation/BeoLingusTranslator.js +357 -0
  154. package/src/lang/en/rules/translation/Inflector.js +72 -0
  155. package/src/lang/en/synthesis/EnglishSynthesizer.js +109 -0
  156. package/src/lang/en/tagging/EnglishHybridDisambiguator.js +28 -0
  157. package/src/lang/en/tagging/EnglishTagger.js +78 -0
  158. package/src/lang/en/tokenizers/EnglishWordTokenizer.js +113 -0
@@ -0,0 +1,677 @@
1
+ // org.languagetool.rules.en.AbstractEnglishSpellerRule (shared logic of the English Morfologik speller rules)
2
+ import { MorfologikSpellerRule } from '@valueerror/ltjs-core/src/core/rules/spelling/morfologik/MorfologikSpellerRule.js';
3
+ import { RuleMatch } from '@valueerror/ltjs-core/src/core/rules/model/RuleMatch.js';
4
+ import { SuggestedReplacement } from '@valueerror/ltjs-core/src/core/rules/model/SuggestedReplacement.js';
5
+ import { Example } from '@valueerror/ltjs-core/src/core/rules/model/Examples.js';
6
+ import { AnalyzedToken } from '@valueerror/ltjs-core/src/core/AnalyzedToken.js';
7
+ import { getDataBroker } from '@valueerror/ltjs-core/src/core/resources/LtStatics.js';
8
+ import { getUrl } from '@valueerror/ltjs-core/src/core/Tools.js';
9
+ import { startsWithUppercase, uppercaseFirstChar } from '@valueerror/ltjs-core/src/core/text/StringTools.js';
10
+ import { BeoLingusTranslator } from './translation/BeoLingusTranslator.js';
11
+ import { Pattern } from '@valueerror/ltjs-core/src/lib/java/regex/index.js';
12
+ import { IOException, RuntimeException, IllegalArgumentException } from '@valueerror/ltjs-core/src/lib/java/errors.js';
13
+ import { Objects } from '@valueerror/ltjs-core/src/lib/java/Objects.js';
14
+ import { replaceOnce } from '@valueerror/ltjs-core/src/lib/java/StringUtils.js';
15
+ import { javaReplace, javaReplaceFirst, javaSplit, javaTrim, substring, toLowerCase } from '@valueerror/ltjs-core/src/lib/java/strings.js';
16
+ import { LC_DO_NOT_SUGGEST_WORDS, getTopSuggestions, getTopSuggestionsIgnoreCase } from './AbstractEnglishSpellerRuleData.js';
17
+
18
+ const { topMatch } = SuggestedReplacement;
19
+ const FLAGS = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
20
+
21
+ const PROFILERATION = Pattern.compile("[Pp]rofileration");
22
+ const CEMETARY = Pattern.compile("[Cc]emetary");
23
+ const CEMETARIES = Pattern.compile("[Cc]emetaries");
24
+ const BASICLY = Pattern.compile("[Bb]asicly");
25
+ const BELEIVES = Pattern.compile("[Bb]eleives?");
26
+ const BELIVES = Pattern.compile("[Bb]elives?");
27
+ const BIZZARE = Pattern.compile("[Bb]izzare");
28
+ const COMPLETLY = Pattern.compile("[Cc]ompletly");
29
+ const DISSAPEARS = Pattern.compile("[Dd]issapears?");
30
+ const FARENHEIT = Pattern.compile("[Ff]arenheit");
31
+ const FREINDS = Pattern.compile("[Ff]reinds?");
32
+ const INCIDENTLY = Pattern.compile("[Ii]ncidently");
33
+ const INTERUPTS = Pattern.compile("[Ii]nterupts?");
34
+ const LOLLYPOPS = Pattern.compile("[Ll]ollypops?");
35
+ const OCASSIONS = Pattern.compile("[Oo]cassions?");
36
+ const OCCURANCES = Pattern.compile("[Oo]ccurances?");
37
+ const PERSISTANT = Pattern.compile("[Pp]ersistant");
38
+ const PEICES = Pattern.compile("[Pp]eices?");
39
+ const SEIGES = Pattern.compile("[Ss]eiges?");
40
+ const SUPERCEDES = Pattern.compile("[Ss]upercedes?");
41
+ const THRESHHOLDS = Pattern.compile("[Tt]hreshholds?");
42
+ const TOMMORROWS = Pattern.compile("[Tt]ommorrows?");
43
+ const TOUTES = Pattern.compile("[Tt]ounges?");
44
+ const WIERD = Pattern.compile("[Ww]ierd");
45
+ const SARGENT = Pattern.compile("[Ss]argent");
46
+ const SWIMMED = Pattern.compile("swimmed");
47
+ const MISSPELT = Pattern.compile("misspelt");
48
+ const JIST = Pattern.compile("[Jj]ist");
49
+ const ADHOC = Pattern.compile("[Ad]hoc");
50
+ const DEACTIVE = Pattern.compile("[De]eactive");
51
+ const HONGKONG = Pattern.compile("[hH]on[kg]kong");
52
+ const AFAIK = Pattern.compile("afaik");
53
+ const JANUARY = Pattern.compile("january");
54
+ const ADMITTINGLY = Pattern.compile("[Aa]dmittingly");
55
+ const APRIL = Pattern.compile("april");
56
+ const SEPTEMBER = Pattern.compile("september");
57
+ const OCTOBER = Pattern.compile("october");
58
+ const NOVEMBER = Pattern.compile("november");
59
+ const DECEMBER = Pattern.compile("december");
60
+ const ENGLISH = Pattern.compile("english");
61
+ const SPANISH = Pattern.compile("spanish");
62
+ const GITLAB = Pattern.compile("[Gg]itlab");
63
+ const BONAFIDE = Pattern.compile("[Bb]onafide");
64
+ const WHEREEVER = Pattern.compile("[Ww]hereever");
65
+ const UNINSPIRATIONAL = Pattern.compile("[Uu]ninspirational");
66
+ const WHATSAPP = Pattern.compile("[Ww]hatsapp");
67
+ const JETLAGGED = Pattern.compile("jetlagged");
68
+ const MACBOOK = Pattern.compile("[Mm]acbooks?");
69
+ const LIKELYHOOD = Pattern.compile("[Ll]ikelyhood");
70
+ const FORSEEABLE = Pattern.compile("[Ff]orseeable");
71
+ const UNFORSEEABLE = Pattern.compile("[Uu]nforseeable");
72
+ const FORSEEABLY = Pattern.compile("[Ff]orseeably");
73
+ const UNFORSEEABLY = Pattern.compile("[Uu]nforseeably");
74
+ const UNECESSARY = Pattern.compile("[Uu]necessary");
75
+ const HUBSPOT = Pattern.compile("[Hh]ubspot");
76
+ const URL = Pattern.compile("[Uu]rl");
77
+ const TV = Pattern.compile("tv");
78
+ const HTTP = Pattern.compile("[Hh]ttp");
79
+ const HTTPS = Pattern.compile("[Hh]ttps");
80
+ const EUROPEAN = Pattern.compile("european");
81
+ const EUROPEANS = Pattern.compile("europeans");
82
+ const FYI = Pattern.compile("[Ff]yi");
83
+ const MICROSOFT = Pattern.compile("microsoft");
84
+ const DEVOPS = Pattern.compile("[Dd]evops");
85
+ const ALLRIGHT = Pattern.compile("[Aa]llright");
86
+ const INTRANSPARENT = Pattern.compile("intransparent(ly)?");
87
+ const ADDON = Pattern.compile("[Aa]ddons?");
88
+ const WDYT = Pattern.compile("[Ww]dyt");
89
+ const UNCOMPLIANT = Pattern.compile("[UuIi]ncompliant");
90
+ const UX = Pattern.compile("ux");
91
+ const LANGUAGETOOL = Pattern.compile("[Ll]anguagetool");
92
+ const UNDETERMINISTIC = Pattern.compile("undeterministic");
93
+ const QUILLBOT_POS = Pattern.compile("QuillBots");
94
+ const QUILLBOT1 = Pattern.compile("[Qq]uill?bot");
95
+ const QUILLBOT1_POS = Pattern.compile("[Qq]uill?bots");
96
+ const QUILLBOT2 = Pattern.compile("QuilBot");
97
+ const QUILLBOT2_POS = Pattern.compile("QuilBots");
98
+
99
+ const CONTAINS_TOKEN = Pattern.compile('.* (b|c|d|e|f|g|h|j|k|l|m|n|o|p|q|r|s|t|v|w|y|z|ll|ve)'); // Java: AbstractEnglishSpellerRule#CONTAINS_TOKEN
100
+
101
+ const maxPatterns = 9;
102
+ const wordPatterns = new Array(maxPatterns).fill(null); // Java: AbstractEnglishSpellerRule#wordPatterns
103
+ const blogLinks = new Array(maxPatterns).fill(null); // Java: AbstractEnglishSpellerRule#blogLinks
104
+ wordPatterns[0] = Pattern.compile(".*[yi][zs]e([sd])?|.*[yi][zs]ings?|.*i[zs]ations?", FLAGS);
105
+ blogLinks[0] = "https://quillbot.com/blog/category/uk-vs-us/";
106
+ wordPatterns[1] = Pattern.compile(".*(defen[cs]e|offen[sc]e|preten[sc]e).*", FLAGS);
107
+ blogLinks[1] = "https://quillbot.com/blog/category/uk-vs-us/";
108
+ wordPatterns[2] = Pattern.compile(".*og|.*ogue", FLAGS);
109
+ blogLinks[2] = "https://quillbot.com/blog/category/uk-vs-us/";
110
+ wordPatterns[3] = Pattern.compile(".*(or|our).*", FLAGS);
111
+ blogLinks[3] = "https://languagetool.org/insights/post/our-or/#colour-or-color%E2%80%94colourise-or-colorize";
112
+ wordPatterns[4] = Pattern.compile(".*e?able|.*dge?ments?|aging|ageing|ax|axe|.*grame?s?|neuron|neurone|neurons|neurones", FLAGS);
113
+ blogLinks[4] = "https://languagetool.org/insights/post/our-or/#likeable-vs-likable-judgement-vs-judgment-oestrogen-vs-estrogen";
114
+ wordPatterns[5] = Pattern.compile(".*(centre|center).*|.*(re|er)", FLAGS);
115
+ blogLinks[5] = "https://languagetool.org/insights/post/re-vs-er/#the-difference-of-%E2%80%9C-reer%E2%80%9D-at-the-center-of-attention";
116
+ wordPatterns[6] = Pattern.compile("canceled|cancelled|canceling|cancelling|chili|chilli|chilies|chillies|chilis|chillis|counselor|counsellor|counselors|counsellors|defueled|defuelled|defueling|defuelling|defuelings|defuellings|dialed|dialled|dialer|dialler|dialers|diallers|dialing|dialling|dialog|dialogue|dialogize|dialogise|dialogized|dialogised|dialogizes|dialogises|dialogizing|dialogising|dialogs|dialogues|dialyzable|dialysable|dialyze|dialyse|dialyzed|dialysed|dialyzes|dialyses|dialyzing|dialysing|enroll|enrol|enrolled|enroled|enrolling|enroling|enrollment|enrolment|enrollments|enrolments|enrolls|enrols|fueled|fuelled|fueling|fuelling|fulfill|fulfil|fulfillment|fulfilment|fulfills|fulfils|installment|instalment|installments|instalments|jewelry|jewellery|labeled|labelled|labeling|labelling|marvelous|marvellous|medalist|medallist|medalists|medallists|modeled|modelled|modeling|modelling|noise-canceling|noise-cancelling|refueled|refuelled|refueling|refuelling|relabeled|relabelled|relabeling|relabelling|remodeled|remodelled|remodeling|remodelling|signalization|signalisation|signalize|signalise|signalized|signalised|signalizes|signalises|signalizing|signalising|skillful|skilful|skillfully|skilfully|tranquilize|tranquillize|tranquilized|tranquillized|tranquilizes|tranquillizes|traveled|travelled|traveler|traveller|travelers|travellers|traveling|travelling|uncanceled|uncancelled|uncanceling|uncancelling|unlabeled|unlabelled|wooly|woolly", FLAGS);
117
+ blogLinks[6] = "https://languagetool.org/insights/post/re-vs-er/#british-english-prefers-doubling-consonants-doesn%E2%80%99t-it";
118
+ wordPatterns[7] = Pattern.compile("airfoil|aerofoil|airfoils|aerofoils|airplane|aeroplane|airplanes|aeroplanes|aluminum|aluminium|artifact|artefact|artifacts|artefacts|backdraft|backdraught|cozy|cosy|", FLAGS);
119
+ blogLinks[7] = "https://languagetool.org/insights/post/re-vs-er/#more-radical-differences-between-british-and-american-english-spellings";
120
+ wordPatterns[8] = Pattern.compile("amenorrhea|amenorrhoea|anesthesia|anaesthesia|anesthesias|anaesthesias|anesthetic|anaesthetic|anesthetically|anaesthetically|anesthetics|anaesthetics|anesthetist|anaesthetist|anesthetists|anaesthetists|anesthetization|anaesthetisation|anesthetizations|anaesthetisations|anesthetize|anaesthetise|anesthetized|anaesthetised|anesthetizes|anaesthetises|anesthetizing|anaesthetising|archeological|archaeological|archeologically|archaeologically|archeologies|archaeologies|archeology|archaeology|cesium|caesium|diarrhea|diarrhoea|diarrheal|diarrhoeal|dyslipidemia|dyslipidaemia|dyslipidemias|dyslipidaemias|edematous|oedematous|encyclopedia|encyclopaedia|encyclopedias|encyclopaedias|eon|aeon|eons|aeons|esophagi|oesophagi|esophagus|oesophagus|esophaguses|oesophaguses|esthetic|aesthetic|esthetical|aesthetical|esthetically|aesthetically|esthetician|aesthetician|estheticians|aestheticians|estrogen|oestrogen|estrus|oestrus|etiologies|aetiologies|etiology|aetiology|feces|faeces|fetal|foetal|fetus|foetus|fetuses|foetuses|gastroesophageal|gastro-oesophageal|glycemic|glycaemic|gynecomastia|gynaecomastia|hematemesis|haematemesis|hematoma|haematoma|hematomas|haematomas|hematopoietic|haematopoietic|hematuria|haematuria|hematurias|haematurias|hemolytic|haemolytic|hemophilia|haemophilia|hemorrhage|haemorrhage|hemorrhages|haemorrhages|hemostasis|haemostasis|homeopathies|homoeopathies|homeopathy|homoeopathy|hyperemia|hyperaemia|hyperemic|hyperaemic|hypnopedia|hypnopaedia|hypnopedic|hypnopaedic|hypocalcaemia|hypocalcaemia|hypokalaemic|hypokalemic|kinesthesia|kinaesthesia|kinesthesis|kinaesthesis|kinesthetic|kinaesthetic|kinesthetically|kinaesthetically|maneuver|manoeuvre|maneuvers|manoeuvres|orthopedic|orthopaedic|orthopedics|orthopaedics|paleoecology|palaeoecology|paleogeographical|palaeogeographical|paleogeographically|palaeogeographically|paleogeography|palaeogeography|paresthesia|paraesthesia|pediatric|paediatric|pediatrically|paediatrically|pediatrician|paediatrician|pediatricians|paediatricians|pedomorphic|paedomorphic|pedophile|paedophile|pedophiles|paedophiles|polycythemia|polycythaemia|pretorium|praetorium|pyorrhea|pyorrhoea|septicemia|septicaemia|synesthesia|synaesthesia|synesthete|synaesthete|synesthetes|synaesthetes|tracheoesophageal|tracheo-oesophageal", FLAGS);
121
+ blogLinks[8] = "https://languagetool.org/insights/post/our-or/#likeable-vs-likable-judgement-vs-judgment-oestrogen-vs-estrogen";
122
+
123
+ // Java: AbstractEnglishSpellerRule.IrregularForms (private static class)
124
+ class IrregularForms {
125
+ // Java: IrregularForms(String,String,String,List)
126
+ constructor(baseform, posName, formName, forms) {
127
+ this.baseform = baseform;
128
+ this.posName = posName;
129
+ this.formName = formName;
130
+ this.forms = forms;
131
+ }
132
+ }
133
+
134
+ // Java: AbstractEnglishSpellerRule (abstract: getFileName, getId)
135
+ export class AbstractEnglishSpellerRule extends MorfologikSpellerRule {
136
+ static FQCN = 'org.languagetool.rules.en.AbstractEnglishSpellerRule';
137
+ static JAVA_ABSTRACT = true;
138
+
139
+ // Java: AbstractEnglishSpellerRule(ResourceBundle,Language) / (ResourceBundle,Language,UserConfig,List) / (ResourceBundle,Language,GlobalConfig,UserConfig,List,LanguageModel,Language)
140
+ constructor(messages, language, ...rest) {
141
+ let globalConfig = null;
142
+ let userConfig = null;
143
+ let altLanguages = [];
144
+ let languageModel = null;
145
+ let motherTongue = null;
146
+ if (rest.length === 5) {
147
+ [globalConfig, userConfig, altLanguages, languageModel, motherTongue] = rest;
148
+ } else if (rest.length === 2) {
149
+ [userConfig, altLanguages] = rest;
150
+ }
151
+ super(messages, language, globalConfig, userConfig, altLanguages, languageModel, motherTongue);
152
+ this.ignoreWordsWithLength = 1;
153
+ this.setCheckCompound(true);
154
+ this.addExamplePair(Example.wrong('This <marker>sentenc</marker> contains a spelling mistake.'),
155
+ Example.fixed('This <marker>sentence</marker> contains a spelling mistake.'));
156
+ const languageSpecificIgnoreFile = javaReplace(this.getSpellingFileName(), '.txt', `_${language.getShortCodeWithCountryAndVariant()}.txt`);
157
+ this.addIgnoreWordsList(this.wordListLoader.loadWords(languageSpecificIgnoreFile));
158
+ this.translator = BeoLingusTranslator.getInstance(globalConfig);
159
+ this.topSuggestions = getTopSuggestions();
160
+ this.topSuggestionsIgnoreCase = getTopSuggestionsIgnoreCase();
161
+ // Java: nerPipe = new NERService(globalConfig.getNerUrl()) is only used together with a BaseLanguageModel (EN-0080, LM not ported)
162
+ }
163
+
164
+ // Java: AbstractEnglishSpellerRule#getAdditionalSpellingFileNames()
165
+ getAdditionalSpellingFileNames() {
166
+ // NOTE: also add to GermanSpellerRule.getSpeller() when adding items here:
167
+ return [this.language.getShortCode() + MorfologikSpellerRule.CUSTOM_SPELLING_FILE, MorfologikSpellerRule.GLOBAL_SPELLING_FILE,
168
+ '/en/multiwords.txt'];
169
+ }
170
+
171
+ // Java: AbstractEnglishSpellerRule#match(AnalyzedSentence)
172
+ match(sentence) {
173
+ const matches = super.match(sentence);
174
+ // Java: NER filtering needs a BaseLanguageModel and nerPipe (EN-0080), neither exists in this port
175
+ // add custom URLs
176
+ for (const match of matches) {
177
+ const misspelledWord = substring(match.getSentence().getText(), match.getFromPos(), match.getToPos());
178
+ if (this.isValidInOtherVariant(misspelledWord) !== null) {
179
+ for (let i = 0; i < maxPatterns; i++) {
180
+ const m = wordPatterns[i].matcher(misspelledWord);
181
+ if (m.matches()) {
182
+ match.setUrl(getUrl(blogLinks[i]));
183
+ break;
184
+ }
185
+ }
186
+ }
187
+ }
188
+ return matches;
189
+ }
190
+
191
+ // Java: AbstractEnglishSpellerRule#filterNoSuggestWords(List)
192
+ filterNoSuggestWords(l) {
193
+ return l.filter((k) => !LC_DO_NOT_SUGGEST_WORDS.has(toLowerCase(k.getReplacement())));
194
+ }
195
+
196
+ // Java: AbstractEnglishSpellerRule#loadWordlist(String,int)
197
+ static loadWordlist(path, column) {
198
+ if (column !== 0 && column !== 1) {
199
+ throw new IllegalArgumentException(`Only column 0 and 1 are supported: ${column}`);
200
+ }
201
+ const words = new Map();
202
+ const lines = getDataBroker().getFromResourceDirAsLines(path);
203
+ for (let line of lines) {
204
+ line = javaTrim(line);
205
+ if (line.length === 0 || line.startsWith('#')) {
206
+ continue;
207
+ }
208
+ const parts = javaSplit(line, ';');
209
+ if (parts.length !== 2) {
210
+ throw new RuntimeException(`Unexpected format in ${path}: ${line} - expected two parts delimited by ';'`);
211
+ }
212
+ words.set(toLowerCase(parts[column]), parts[column === 1 ? 0 : 1]);
213
+ }
214
+ return words;
215
+ }
216
+
217
+ // Java: AbstractEnglishSpellerRule#filterSuggestions(List)
218
+ filterSuggestions(suggestions) {
219
+ const result = super.filterSuggestions(suggestions);
220
+ const clean = [];
221
+ for (const suggestion of result) {
222
+ if (!CONTAINS_TOKEN.matcher(suggestion.getReplacement()).matches()) { // e.g. 'timezones' suggests 'timezone s'
223
+ clean.push(suggestion);
224
+ }
225
+ }
226
+ return clean;
227
+ }
228
+
229
+ // Java: AbstractEnglishSpellerRule#getRuleMatches(String,int,AnalyzedSentence,List,int,AnalyzedTokenReadings[])
230
+ getRuleMatches(word, startPos, sentence, ruleMatchesSoFar, idx, tokens) {
231
+ const ruleMatches = super.getRuleMatches(word, startPos, sentence, ruleMatchesSoFar, idx, tokens);
232
+ if (ruleMatches.length > 0) {
233
+ // so 'word' is misspelled:
234
+ const forms = this.getIrregularFormsOrNull(word);
235
+ if (forms !== null) {
236
+ const message = `Possible spelling mistake. Did you mean <suggestion>${forms.forms[0]}</suggestion>, the ${forms.formName} form of the ${forms.posName} '${forms.baseform}'?`;
237
+ this.addFormsToFirstMatch(message, sentence, ruleMatches, forms.forms);
238
+ } else {
239
+ const variantInfo = this.isValidInOtherVariant(word);
240
+ if (variantInfo !== null) {
241
+ const message = `Possible spelling mistake. '${word}' is ${variantInfo.getVariantName()}.`;
242
+ const suggestion = startsWithUppercase(word)
243
+ ? uppercaseFirstChar(variantInfo.otherVariant()) : variantInfo.otherVariant();
244
+ this.replaceFormsOfFirstMatch(message, sentence, ruleMatches, suggestion);
245
+ }
246
+ }
247
+ }
248
+ // filter "re ..." (#2562):
249
+ return ruleMatches.map((m) => {
250
+ const copy = new RuleMatch(m);
251
+ copy.setLazySuggestedReplacements(() => cleanSuggestions(m));
252
+ return copy;
253
+ });
254
+ }
255
+
256
+ // Java: AbstractEnglishSpellerRule#isValidInOtherVariant(String)
257
+ isValidInOtherVariant() {
258
+ return null;
259
+ }
260
+
261
+ // Java: AbstractEnglishSpellerRule#addFormsToFirstMatch(String,AnalyzedSentence,List,List)
262
+ addFormsToFirstMatch(message, sentence, ruleMatches, forms) {
263
+ // recreating match, might overwrite information by SuggestionsRanker;
264
+ // this has precedence
265
+ const oldMatch = ruleMatches[0];
266
+ const newMatch = new RuleMatch(this, sentence, oldMatch.getFromPos(), oldMatch.getToPos(), message);
267
+ newMatch.setType(oldMatch.getType());
268
+ newMatch.setLazySuggestedReplacements(() => this.filterDupes([
269
+ ...forms.map((f) => new SuggestedReplacement(f)),
270
+ ...oldMatch.getSuggestedReplacementObjects(),
271
+ ]));
272
+ ruleMatches[0] = newMatch;
273
+ }
274
+
275
+ // Java: AbstractEnglishSpellerRule#replaceFormsOfFirstMatch(String,AnalyzedSentence,List,String)
276
+ replaceFormsOfFirstMatch(message, sentence, ruleMatches, suggestion) {
277
+ // recreating match, might overwrite information by SuggestionsRanker;
278
+ // this has precedence
279
+ const oldMatch = ruleMatches[0];
280
+ const newMatch = new RuleMatch(this, sentence, oldMatch.getFromPos(), oldMatch.getToPos(), message);
281
+ newMatch.setType(oldMatch.getType());
282
+ const sugg = new SuggestedReplacement(suggestion);
283
+ sugg.setShortDescription(this.language.getName());
284
+ newMatch.setSuggestedReplacementObjects([sugg]);
285
+ ruleMatches[0] = newMatch;
286
+ }
287
+
288
+ // Java: AbstractEnglishSpellerRule#getIrregularFormsOrNull(String) and (String,String,List,String,String,String)
289
+ getIrregularFormsOrNull(word, wordSuffix, suffixes, posTag, posName, formName) {
290
+ if (wordSuffix === undefined) {
291
+ let irregularFormsOrNull = this.getIrregularFormsOrNull(word, 'ed', ['ed'], 'VBD', 'verb', 'past tense');
292
+ if (irregularFormsOrNull !== null) return irregularFormsOrNull;
293
+ irregularFormsOrNull = this.getIrregularFormsOrNull(word, 'ed', ['d' /* e.g. awaked */], 'VBD', 'verb', 'past tense');
294
+ if (irregularFormsOrNull !== null) return irregularFormsOrNull;
295
+ irregularFormsOrNull = this.getIrregularFormsOrNull(word, 's', ['s'], 'NNS', 'noun', 'plural');
296
+ if (irregularFormsOrNull !== null) return irregularFormsOrNull;
297
+ irregularFormsOrNull = this.getIrregularFormsOrNull(word, 'es', ['es'/* e.g. 'analysises' */], 'NNS', 'noun', 'plural');
298
+ if (irregularFormsOrNull !== null) return irregularFormsOrNull;
299
+ irregularFormsOrNull = this.getIrregularFormsOrNull(word, 'er', ['er'/* e.g. 'farer' */], 'JJR', 'adjective', 'comparative');
300
+ if (irregularFormsOrNull !== null) return irregularFormsOrNull;
301
+ irregularFormsOrNull = this.getIrregularFormsOrNull(word, 'est', ['est'/* e.g. 'farest' */], 'JJS', 'adjective', 'superlative');
302
+ return irregularFormsOrNull;
303
+ }
304
+ try {
305
+ for (const suffix of suffixes) {
306
+ if (word.endsWith(wordSuffix)) {
307
+ const baseForm = substring(word, 0, word.length - suffix.length);
308
+ const forms = Objects.requireNonNull(this.language.getSynthesizer()).synthesize(new AnalyzedToken(word, null, baseForm), posTag);
309
+ const result = [];
310
+ for (const form of forms) {
311
+ if (!this.speller1.isMisspelled(form)) {
312
+ // only accept suggestions that the spellchecker will accept
313
+ result.push(form);
314
+ }
315
+ }
316
+ // the internal dict might contain forms that the spell checker doesn't accept (e.g. 'criterions'),
317
+ // but we trust the spell checker in this case:
318
+ removeFirst(result, word);
319
+ removeFirst(result, 'badder'); // non-standard usage
320
+ removeFirst(result, 'baddest'); // non-standard usage
321
+ removeFirst(result, 'spake'); // can be removed after dict update
322
+ if (result.length > 0) {
323
+ return new IrregularForms(baseForm, posName, formName, result);
324
+ }
325
+ }
326
+ }
327
+ return null;
328
+ } catch (e) {
329
+ if (e instanceof IOException) throw new RuntimeException(e);
330
+ throw e;
331
+ }
332
+ }
333
+
334
+ // Java: AbstractEnglishSpellerRule#getAdditionalTopSuggestions(List,String)
335
+ getAdditionalTopSuggestions(suggestions, word) {
336
+ const curatedSuggestions = [];
337
+ curatedSuggestions.push(...(this.topSuggestions.has(word) ? this.topSuggestions.get(word) : []));
338
+ const lc = toLowerCase(word);
339
+ curatedSuggestions.push(...(this.topSuggestionsIgnoreCase.has(lc) ? this.topSuggestionsIgnoreCase.get(lc) : []));
340
+ if (curatedSuggestions.length !== 0) {
341
+ return SuggestedReplacement.convert(curatedSuggestions);
342
+ } else if (word.endsWith('ys')) {
343
+ const suggestion = javaReplaceFirst(word, 'ys$', 'ies');
344
+ if (!this.speller1.isMisspelled(suggestion)) {
345
+ return SuggestedReplacement.convert([suggestion]);
346
+ }
347
+ }
348
+ return super.getAdditionalTopSuggestions(suggestions, word);
349
+ }
350
+
351
+ // trivial approach that assumes only one part of the hyphenated word has a typo...
352
+ // Java: AbstractEnglishSpellerRule#addHyphenSuggestions(String[],List)
353
+ addHyphenSuggestions(parts, topSuggestions) {
354
+ let i = 0;
355
+ for (const part of parts) {
356
+ if (this.isMisspelled(part)) {
357
+ let partSuggestions = this.speller1.getSuggestions(part);
358
+ if (partSuggestions.length === 0) {
359
+ partSuggestions = this.speller2.getSuggestions(part);
360
+ }
361
+ if (partSuggestions.length > 0) {
362
+ const suggestion = this.getHyphenatedWordSuggestion(parts, i, partSuggestions[0]);
363
+ topSuggestions.push(new SuggestedReplacement(suggestion));
364
+ }
365
+ }
366
+ i++;
367
+ }
368
+ }
369
+
370
+ // Java: AbstractEnglishSpellerRule#getHyphenatedWordSuggestion(String[],int,String)
371
+ getHyphenatedWordSuggestion(parts, currentPos, currentPostSuggestion) {
372
+ const newParts = [];
373
+ for (let j = 0; j < parts.length; j++) {
374
+ if (currentPos === j) {
375
+ newParts.push(currentPostSuggestion);
376
+ } else {
377
+ newParts.push(parts[j]);
378
+ }
379
+ }
380
+ return newParts.join('-');
381
+ }
382
+
383
+ // Java: AbstractEnglishSpellerRule#getTranslator(GlobalConfig)
384
+ getTranslator() {
385
+ return this.translator;
386
+ }
387
+
388
+ // Do not tokenize new words from spelling.txt...
389
+ // Multi-token words should be in multiwords.txt
390
+ // Java: AbstractEnglishSpellerRule#tokenizeNewWords()
391
+ tokenizeNewWords() {
392
+ return false;
393
+ }
394
+
395
+ // Java: AbstractEnglishSpellerRule#getOnlySuggestions(String)
396
+ getOnlySuggestions(word) {
397
+ // NOTE: only add words here that would otherwise have more than one suggestion
398
+ // and have apply to all variants of English (en-US, en-GB, ...):
399
+ if (PROFILERATION.matcher(word).matches()) return topMatch(replaceOnce(word, "rofileration", "roliferation"), "rapid expansion");
400
+ if (CEMETARY.matcher(word).matches()) return topMatch(replaceOnce(word, "emetary", "emetery"));
401
+ if (CEMETARIES.matcher(word).matches()) return topMatch(replaceOnce(word, "emetaries", "emeteries"));
402
+ if (BASICLY.matcher(word).matches()) return topMatch(replaceOnce(word, "asicly", "asically"));
403
+ if (BELEIVES.matcher(word).matches()) return topMatch(replaceOnce(word, "eleive", "elieve"));
404
+ if (BELIVES.matcher(word).matches()) return topMatch(replaceOnce(word, "elive", "elieve"));
405
+ if (BIZZARE.matcher(word).matches()) return topMatch(replaceOnce(word, "izzare", "izarre"));
406
+ if (COMPLETLY.matcher(word).matches()) return topMatch(replaceOnce(word, "ompletly", "ompletely"));
407
+ if (DISSAPEARS.matcher(word).matches()) return topMatch(replaceOnce(word, "issapear", "isappear"));
408
+ if (FARENHEIT.matcher(word).matches()) return topMatch(replaceOnce(word, "arenheit", "ahrenheit"));
409
+ if (FREINDS.matcher(word).matches()) return topMatch(replaceOnce(word, "reind", "riend"));
410
+ if (INCIDENTLY.matcher(word).matches()) return topMatch(replaceOnce(word, "ncidently", "ncidentally"));
411
+ if (INTERUPTS.matcher(word).matches()) return topMatch(replaceOnce(word, "nterupt", "nterrupt"));
412
+ if (LOLLYPOPS.matcher(word).matches()) return topMatch(replaceOnce(word, "ollypop", "ollipop"));
413
+ if (OCASSIONS.matcher(word).matches()) return topMatch(replaceOnce(word, "cassion", "ccasion"));
414
+ if (OCCURANCES.matcher(word).matches()) return topMatch(replaceOnce(word, "ccurance", "ccurrence"));
415
+ if (PERSISTANT.matcher(word).matches()) return topMatch(replaceOnce(word, "ersistant", "ersistent"));
416
+ if (PEICES.matcher(word).matches()) return topMatch(replaceOnce(word, "eice", "iece"));
417
+ if (SEIGES.matcher(word).matches()) return topMatch(replaceOnce(word, "eige", "iege"));
418
+ if (SUPERCEDES.matcher(word).matches()) return topMatch(replaceOnce(word, "upercede", "upersede"));
419
+ if (THRESHHOLDS.matcher(word).matches()) return topMatch(replaceOnce(word, "hreshhold", "hreshold"));
420
+ if (TOMMORROWS.matcher(word).matches()) return topMatch(replaceOnce(word, "ommorrow", "omorrow"));
421
+ if (TOUTES.matcher(word).matches()) return topMatch(replaceOnce(word, "ounge", "ongue"));
422
+ if (WIERD.matcher(word).matches()) return topMatch(replaceOnce(word, "ierd", "eird"));
423
+ if (SARGENT.matcher(word).matches()) return topMatch(replaceOnce(word, "argent", "ergeant"));
424
+ if (SWIMMED.matcher(word).matches()) return topMatch("swam");
425
+ if (MISSPELT.matcher(word).matches()) return topMatch("misspelled");
426
+ if (ADHOC.matcher(word).matches()) return topMatch("ad hoc");
427
+ if (DEACTIVE.matcher(word).matches()) return topMatch("inactive");
428
+ if (HUBSPOT.matcher(word).matches()) return topMatch("HubSpot");
429
+ if (URL.matcher(word).matches()) return topMatch("URL");
430
+ if (HTTP.matcher(word).matches()) return topMatch("HTTP");
431
+ if (HTTPS.matcher(word).matches()) return topMatch("HTTPS");
432
+ if (FYI.matcher(word).matches()) return topMatch("FYI");
433
+ if (EUROPEAN.matcher(word).matches()) return topMatch("European");
434
+ if (EUROPEANS.matcher(word).matches()) return topMatch("Europeans");
435
+ if (DEVOPS.matcher(word).matches()) return topMatch("DevOps");
436
+ if (MICROSOFT.matcher(word).matches()) return topMatch("Microsoft");
437
+ if (LANGUAGETOOL.matcher(word).matches()) return topMatch("LanguageTool");
438
+ if (HONGKONG.matcher(word).matches()) return topMatch("Hong Kong");
439
+ if (OCTOBER.matcher(word).matches()) return topMatch("October");
440
+ if (SEPTEMBER.matcher(word).matches()) return topMatch("September");
441
+ if (DECEMBER.matcher(word).matches()) return topMatch("December");
442
+ if (NOVEMBER.matcher(word).matches()) return topMatch("November");
443
+ if (APRIL.matcher(word).matches()) return topMatch("April");
444
+ if (AFAIK.matcher(word).matches()) return topMatch("AFAIK");
445
+ if (JANUARY.matcher(word).matches()) return topMatch("January");
446
+ if (ADMITTINGLY.matcher(word).matches()) return topMatch(replaceOnce(word, "dmittingly", "dmittedly"));
447
+ if (ENGLISH.matcher(word).matches()) return topMatch("English");
448
+ if (SPANISH.matcher(word).matches()) return topMatch("Spanish");
449
+ if (UNDETERMINISTIC.matcher(word).matches()) return topMatch("nondeterministic");
450
+ if (WDYT.matcher(word).matches()) return topMatch("WDYT");
451
+ if (INTRANSPARENT.matcher(word).matches()) return topMatch(replaceOnce(word, "in", "un"));
452
+ if (UNCOMPLIANT.matcher(word).matches()) return topMatch("non-compliant");
453
+ if (UX.matcher(word).matches()) return topMatch("UX");
454
+ if (GITLAB.matcher(word).matches()) return topMatch("GitLab");
455
+ if (BONAFIDE.matcher(word).matches()) return topMatch(replaceOnce(word, "onafide", "ona fide"));
456
+ if (ALLRIGHT.matcher(word).matches()) return topMatch(replaceOnce(word, "llright", "lright"));
457
+ if (ADDON.matcher(word).matches()) return topMatch(replaceOnce(word, "ddon", "dd-on"));
458
+ if (WHEREEVER.matcher(word).matches()) return topMatch(replaceOnce(word, "hereever", "herever"));
459
+ if (WHATSAPP.matcher(word).matches()) return topMatch("WhatsApp");
460
+ if (UNINSPIRATIONAL.matcher(word).matches()) return topMatch(replaceOnce(word, "ninspirational", "ninspiring"));
461
+ if (JETLAGGED.matcher(word).matches()) return topMatch("jet-lagged");
462
+ if (MACBOOK.matcher(word).matches()) return topMatch(replaceOnce(word, "acbook", "acBook"));
463
+ if (LIKELYHOOD.matcher(word).matches()) return topMatch(replaceOnce(word, "ikelyhood", "ikelihood"));
464
+ if (UNECESSARY.matcher(word).matches()) return topMatch(replaceOnce(word, "necessary", "nnecessary"));
465
+ if (FORSEEABLE.matcher(word).matches()) return topMatch(replaceOnce(word, "orseeable", "oreseeable"));
466
+ if (UNFORSEEABLE.matcher(word).matches()) return topMatch(replaceOnce(word, "orseeable", "oreseeable"));
467
+ if (FORSEEABLY.matcher(word).matches()) return topMatch(replaceOnce(word, "orseeably", "oreseeably"));
468
+ if (UNFORSEEABLY.matcher(word).matches()) return topMatch(replaceOnce(word, "orseeably", "oreseeably"));
469
+ if (QUILLBOT1.matcher(word).matches() || QUILLBOT2.matcher(word).matches()) return topMatch("QuillBot");
470
+ if (QUILLBOT_POS.matcher(word).matches() || QUILLBOT1_POS.matcher(word).matches()
471
+ || QUILLBOT2_POS.matcher(word).matches()) {
472
+ return [new SuggestedReplacement("QuillBot's"), new SuggestedReplacement('QuillBot')];
473
+ }
474
+ if (TV.matcher(word).matches()) {
475
+ return [new SuggestedReplacement('TV'), new SuggestedReplacement('to')];
476
+ }
477
+ if (JIST.matcher(word).matches()) {
478
+ return [new SuggestedReplacement('just'), new SuggestedReplacement('gist')];
479
+ }
480
+ return [];
481
+ }
482
+ }
483
+
484
+ // Java: List#remove(Object) (first occurrence)
485
+ function removeFirst(list, o) {
486
+ const i = list.indexOf(o);
487
+ if (i >= 0) list.splice(i, 1);
488
+ }
489
+
490
+ // Java: AbstractEnglishSpellerRule#cleanSuggestions(RuleMatch) (private static)
491
+ function cleanSuggestions(ruleMatch) {
492
+ return ruleMatch.getSuggestedReplacementObjects().filter((k) => {
493
+ const rep = k.getReplacement();
494
+ if (!rep.includes(' ')) {
495
+ return true;
496
+ }
497
+ const repLc = toLowerCase(rep);
498
+ return true
499
+ && !repLc.startsWith("re ")
500
+ && !repLc.startsWith("en ")
501
+ && !repLc.startsWith("co ")
502
+ && !repLc.startsWith("cl ")
503
+ && !repLc.startsWith("de ")
504
+ && !repLc.startsWith("ex ")
505
+ && !repLc.startsWith("es ")
506
+ && !repLc.startsWith("ab ")
507
+ && !repLc.startsWith("ty ")
508
+ && !repLc.startsWith("mid ")
509
+ && !repLc.startsWith("non ")
510
+ && !repLc.startsWith("bio ")
511
+ && !repLc.startsWith("bi ")
512
+ && !repLc.startsWith("op ")
513
+ && !repLc.startsWith("con ")
514
+ && !repLc.startsWith("pre ")
515
+ && !repLc.startsWith("mis ")
516
+ && !repLc.startsWith("socio ")
517
+ && !repLc.startsWith("proto ")
518
+ && !repLc.startsWith("neo ")
519
+ && !repLc.startsWith("geo ")
520
+ && !repLc.startsWith("inter ")
521
+ && !repLc.startsWith("multi ")
522
+ && !repLc.startsWith("retro ")
523
+ && !repLc.startsWith("extra ")
524
+ && !repLc.startsWith("mega ")
525
+ && !repLc.startsWith("meta ")
526
+ && !repLc.startsWith("poly ")
527
+ && !repLc.startsWith("para ")
528
+ && !repLc.startsWith("uni ")
529
+ && !repLc.startsWith("anti ")
530
+ && !repLc.startsWith("necro ")
531
+ && !repLc.startsWith("photo ")
532
+ && !repLc.startsWith("post ")
533
+ && !repLc.startsWith("sub ")
534
+ && !repLc.startsWith("auto ")
535
+ && !repLc.startsWith("pl ")
536
+ && !repLc.startsWith("ht ")
537
+ && !repLc.startsWith("dis ")
538
+ && !repLc.startsWith("est ")
539
+ && !repLc.startsWith("mono ")
540
+ && !repLc.startsWith("trans ")
541
+ && !repLc.startsWith("neuro ")
542
+ && !repLc.startsWith("hetero ")
543
+ && !repLc.startsWith("ultra ")
544
+ && !repLc.startsWith("mini ")
545
+ && !repLc.startsWith("hyper ")
546
+ && !repLc.startsWith("micro ")
547
+ && !repLc.startsWith("counter ")
548
+ && !repLc.startsWith("over ")
549
+ && !repLc.startsWith("overs ")
550
+ && !repLc.startsWith("overt ")
551
+ && !repLc.startsWith("under ")
552
+ && !repLc.startsWith("cyber ")
553
+ && !repLc.startsWith("hydro ")
554
+ && !repLc.startsWith("ergo ")
555
+ && !repLc.startsWith("fore ")
556
+ && !repLc.startsWith("pro ")
557
+ && !repLc.startsWith("pseudo ")
558
+ && !repLc.startsWith("psycho ")
559
+ && !repLc.startsWith("mi ")
560
+ && !repLc.startsWith("nano ")
561
+ && !repLc.startsWith("ans ")
562
+ && !repLc.startsWith("semi ")
563
+ && !repLc.startsWith("infra ")
564
+ && !repLc.startsWith("hypo ")
565
+ && !repLc.startsWith("syn ")
566
+ && !repLc.startsWith("adv ")
567
+ && !repLc.startsWith("com ")
568
+ && !repLc.startsWith("res ")
569
+ && !repLc.startsWith("resp ")
570
+ && !repLc.startsWith("lo ")
571
+ && !repLc.startsWith("ed ")
572
+ && !repLc.startsWith("ac ")
573
+ && !repLc.startsWith("al ")
574
+ && !repLc.startsWith("ea ")
575
+ && !repLc.startsWith("ge ")
576
+ && !repLc.startsWith("mu ")
577
+ && !repLc.startsWith("ma ")
578
+ && !repLc.startsWith("la ")
579
+ && !repLc.startsWith("bis ")
580
+ && !repLc.startsWith("ger ")
581
+ && !repLc.startsWith("inf ")
582
+ && !repLc.startsWith("tar ")
583
+ && !repLc.startsWith("f ")
584
+ && !repLc.startsWith("k ")
585
+ && !repLc.startsWith("l ")
586
+ && !repLc.startsWith("b ")
587
+ && !repLc.startsWith("e ")
588
+ && !repLc.startsWith("c ")
589
+ && !repLc.startsWith("d ")
590
+ && !repLc.startsWith("p ")
591
+ && !repLc.startsWith("v ")
592
+ && !repLc.startsWith("h ")
593
+ && !repLc.startsWith("r ")
594
+ && !repLc.startsWith("s ")
595
+ && !repLc.startsWith("t ")
596
+ && !repLc.startsWith("u ")
597
+ && !repLc.startsWith("w ")
598
+ && !repLc.startsWith("um ")
599
+ && !repLc.startsWith("oft ")
600
+ && !rep.startsWith("i ")
601
+ && !rep.startsWith("sh ")
602
+ && !rep.startsWith("li ")
603
+ && !rep.startsWith("ha ")
604
+ && !rep.startsWith("st ")
605
+ && !rep.startsWith("ins ")
606
+ && !rep.endsWith(" i")
607
+ && !rep.endsWith(" ING")
608
+ && !rep.endsWith(" able")
609
+ && !rep.endsWith(" om")
610
+ && !rep.endsWith(" ox")
611
+ && !rep.endsWith(" ht")
612
+ && !rep.endsWith(" wide")
613
+ && !rep.endsWith(" less")
614
+ && !rep.endsWith(" sly")
615
+ && !rep.endsWith(" OO")
616
+ && !rep.endsWith(" HHH")
617
+ && !rep.endsWith(" ally")
618
+ && !rep.endsWith(" ize")
619
+ && !rep.endsWith(" sh")
620
+ && !rep.endsWith(" st")
621
+ && !rep.endsWith(" est")
622
+ && !rep.endsWith(" em")
623
+ && !rep.endsWith(" ward")
624
+ && !rep.endsWith(" ability")
625
+ && !rep.endsWith(" ware")
626
+ && !rep.endsWith(" logy")
627
+ && !rep.endsWith(" ting")
628
+ && !rep.endsWith(" ion")
629
+ && !rep.endsWith(" ions")
630
+ && !rep.endsWith(" cal")
631
+ && !rep.endsWith(" ted")
632
+ && !rep.endsWith(" sphere")
633
+ && !rep.endsWith(" ell")
634
+ && !rep.endsWith(" co")
635
+ && !rep.endsWith(" con")
636
+ && !rep.endsWith(" com")
637
+ && !rep.endsWith(" sis")
638
+ && !rep.endsWith(" like")
639
+ && !rep.endsWith(" full")
640
+ && !rep.endsWith(" en")
641
+ && !rep.endsWith(" ne")
642
+ && !rep.endsWith(" ed")
643
+ && !rep.endsWith(" al")
644
+ && !rep.endsWith(" ans")
645
+ && !rep.endsWith(" mans")
646
+ && !rep.endsWith(" ti")
647
+ && !rep.endsWith(" de")
648
+ && !rep.endsWith(" ea")
649
+ && !rep.endsWith(" ge")
650
+ && !rep.endsWith(" ab")
651
+ && !rep.endsWith(" rs")
652
+ && !rep.endsWith(" mi")
653
+ && !rep.endsWith(" tar")
654
+ && !rep.endsWith(" adv")
655
+ && !rep.endsWith(" re")
656
+ && !rep.endsWith(" e")
657
+ && !rep.endsWith(" c")
658
+ && !rep.endsWith(" v")
659
+ && !rep.endsWith(" h")
660
+ && !rep.endsWith(" s")
661
+ && !rep.endsWith(" r")
662
+ && !rep.endsWith(" l")
663
+ && !rep.endsWith(" u")
664
+ && !rep.endsWith(" um")
665
+ && !rep.endsWith(" er")
666
+ && !rep.endsWith(" es")
667
+ && !rep.endsWith(" ex")
668
+ && !rep.endsWith(" na")
669
+ && !rep.endsWith(" ifs")
670
+ && !rep.endsWith(" gs")
671
+ && !rep.endsWith(" don")
672
+ && !rep.endsWith(" dons")
673
+ && !rep.endsWith(" la")
674
+ && !rep.endsWith(" ism")
675
+ && !rep.endsWith(" ma");
676
+ });
677
+ }