@faircopy/rules-nlp
v1.26.0
Published
Optional NLP-powered ruleset for faircopy using compromise
Readme
@faircopy/rules-nlp
Optional NLP-powered ruleset for faircopy using compromise.
npm i -D @faircopy/rules-nlpLoad the ruleset once, then configure rules with bare rule IDs:
rulesets: ['@faircopy/rules-nlp'],
rules: {
'no-absolute-intensifiers': 'warn',
'no-adverb-overuse': 'warn',
'no-expletive-openers': 'warn',
'no-filter-words': 'warn',
'no-future-promises': 'warn',
'no-hedge-words': 'warn',
'no-empty-transformation-claims': 'warn',
'no-passive-voice': 'warn',
'no-qualifier-creep': 'warn',
'no-redundant-pairs': 'warn',
'no-vague-comparatives': 'warn',
'no-weak-modals': 'warn',
'no-stacked-adjectives': 'warn',
'no-nominalized-phrases': 'warn',
'no-noun-strings': 'warn',
'no-pronoun-led-claims': 'warn',
'no-buzzword-stacks': 'warn',
'no-complex-readability': 'warn',
'no-overly-complex-sentences': 'warn',
'no-vague-quantifiers': 'warn',
'no-meaningless-modifiers': 'warn',
'no-superlative-claims': 'warn',
'no-llm-speak': 'warn',
'no-n-things': 'warn',
'no-weak-verbs': 'warn',
}Package-qualified IDs like @faircopy/rules-nlp/no-passive-voice still work and are required if another loaded ruleset exposes the same bare rule name.
Rules
| Rule | Description |
|---|---|
| no-absolute-intensifiers | Flag intensifiers before absolute adjectives like very unique |
| no-adverb-overuse | Flag sentences with more than two adverbs ending in -ly |
| no-empty-transformation-claims | Flag broad transformation cliches like transform the way teams work |
| no-expletive-openers | Flag sentence openings like There are |
| no-filter-words | Ban filter phrases like I think and it seems |
| no-future-promises | Flag future-tense promises like will help you |
| no-hedge-words | Flag hedge words like kind of and somewhat |
| no-jargon | Flag business jargon like leverage and circle back |
| no-passive-voice | Flag likely passive-voice constructions |
| no-qualifier-creep | Flag stacked qualifiers or intensifiers like very really good |
| no-redundant-pairs | Flag redundant fixed phrases like first and foremost |
| no-vague-comparatives | Flag comparative claims that omit a clear baseline |
| no-weak-modals | Flag hedged modal claims like can help and might improve |
| no-stacked-adjectives | Flag noun phrases with multiple adjectives before the noun |
| no-nominalized-phrases | Flag nominalized X of Y phrases like optimization of onboarding |
| no-noun-strings | Flag dense strings of consecutive nouns like user experience design process |
| no-pronoun-led-claims | Flag vague sentence openers like This helps and It enables |
| no-buzzword-stacks | Flag sentences overloaded with abstract benefit nouns |
| no-complex-readability | Flag prose whose Flesch-Kincaid grade level exceeds a target |
| no-overly-complex-sentences | Flag sentences overloaded with coordinating or subordinating conjunctions |
| no-vague-quantifiers | Flag bare quantifiers without numeric anchors |
| no-meaningless-modifiers | Flag intensifiers like very and obviously that add no information |
| no-superlative-claims | Flag unproven superlatives like best and world-class |
| no-non-inclusive-language-nlp | Flag non-inclusive terms and suggest neutral alternatives |
| no-llm-speak | Flag LLM clichés like delve into and robust and suggest concrete alternatives |
| no-n-things | Flag the counted placeholder frame like Three things. and 5 things to know |
| no-weak-verbs | Flag vague action verbs like make and perform and suggest stronger alternatives |
| sentence-complexity | Flag sentences that exceed a word or clause threshold |
no-absolute-intensifiers
Absolute adjectives already express an extreme, so intensifiers such as very are redundant.
rules: {
'no-absolute-intensifiers': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| intensifiers | string[] | ['very', 'really', 'completely', ...] | Words or phrases to treat as intensifiers |
| absolutes | string[] | ['unique', 'finished', 'destroyed', ...] | Absolute adjectives that should not be intensified |
Example:
'no-absolute-intensifiers': ['warn', {
intensifiers: ['very', 'highly'],
absolutes: ['unique', 'critical'],
}]sentence-complexity
Long, clause-heavy sentences are harder to read. This rule flags any sentence that exceeds a configurable word count or contains too many finite-verb clauses, and suggests splitting it into shorter sentences.
rules: {
'sentence-complexity': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| maxWordCount | number | 25 | Maximum words allowed per sentence |
| maxClauseCount | number | 3 | Maximum finite-verb clauses allowed per sentence |
Example with custom thresholds:
'sentence-complexity': ['warn', {
maxWordCount: 20,
maxClauseCount: 2,
}]Flagged example:
The engineer reviewed the requirements and wrote the code and ran the tests and deployed the application while the team watched and celebrated the release together.Suggested fix: split the sentence around each independent clause.
The engineer reviewed the requirements. They wrote the code, ran the tests, and deployed the application. The team watched and celebrated the release together.no-overly-complex-sentences
Sentences packed with conjunctions are often run-ons or nested too deeply. This rule flags any sentence that exceeds a configurable number of coordinating conjunctions, subordinating conjunctions, or total conjunctions.
rules: {
'no-overly-complex-sentences': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| maxConjunctions | number | 4 | Maximum total conjunctions allowed per sentence |
| maxCoordinating | number | 3 | Maximum coordinating conjunctions allowed per sentence |
| maxSubordinating | number | 2 | Maximum subordinating conjunctions allowed per sentence |
| coordinating | string[] | ['and', 'but', 'or', 'nor', 'yet', 'so'] | Words treated as coordinating conjunctions |
| subordinating | string[] | ['because', 'although', 'though', 'while', 'since', 'unless', 'if', 'when', 'after', 'before', 'until', 'whether', 'once'] | Words treated as subordinating conjunctions |
| allowList | string[] | [] | Words to ignore when counting |
Example with custom thresholds:
'no-overly-complex-sentences': ['warn', {
maxConjunctions: 3,
maxCoordinating: 2,
maxSubordinating: 1,
}]Flagged example:
I ran and swam and biked and hiked and climbed.Suggested fix: split the list into shorter sentences or use a bulleted list.
I ran, swam, and biked. Then I hiked and climbed.Some words, such as since or so, can be prepositions or adverbs in certain contexts. If the rule is too noisy for your copy, add the word to allowList.
no-vague-comparatives
Comparative claims like faster, easier, or more efficient only persuade when the reader knows the baseline. This rule flags comparative adjectives and adverbs that are not paired with than in the same sentence.
rules: {
'no-vague-comparatives': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| comparatives | string[] | ['better', 'worse', 'more', 'less', 'faster', 'slower', 'easier', 'harder', 'stronger', 'weaker', 'higher', 'lower', 'bigger', 'smaller', 'greater'] | Comparative words or phrases that require a baseline |
| requireThan | boolean | true | Whether a than in the same sentence suppresses the diagnostic |
Example with custom settings:
'no-vague-comparatives': ['warn', {
comparatives: ['superior', 'inferior', 'better'],
requireThan: true,
}]Flagged example:
Our editor is faster. It is also easier to use.Suggested fix: add a concrete baseline.
Our editor is faster than the old one. It is also easier to use than a spreadsheet.no-qualifier-creep
Stacked qualifiers or intensifiers dilute a claim and make it sound hedged. This rule flags sequences of two or more qualifiers before an adjective or adverb.
rules: {
'no-qualifier-creep': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| qualifiers | string[] | ['very', 'really', 'quite', ...] | Words treated as qualifiers or intensifiers |
| maxQualifiers | number | 1 | Maximum qualifiers allowed in a row before the excess are flagged |
Example with custom settings:
'no-qualifier-creep': ['warn', {
qualifiers: ['very', 'really', 'quite'],
maxQualifiers: 1,
}]Flagged example:
The result is very really quite good.Suggested fix: keep the strongest qualifier or replace the phrase with concrete evidence.
The result is excellent.no-non-inclusive-language-nlp
Non-inclusive terms can alienate readers. This rule flags common non-inclusive language and suggests neutral alternatives using NLP-aware matching so it understands word boundaries and part-of-speech context.
rules: {
'no-non-inclusive-language-nlp': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| terms | NonInclusiveTerm[] | See source | Terms to flag, each with a list of alternatives |
| allowedTerms | string[] | [] | Terms to allow and skip |
Example with custom terms:
'no-non-inclusive-language-nlp': ['warn', {
terms: [
{ term: 'guys', alternatives: ['everyone', 'team', 'folks'] },
{ term: 'blacklist', alternatives: ['denylist', 'blocklist'] },
],
allowedTerms: ['whitelist'],
}]Flagged example:
Hey guys, add this to the blacklist and do a sanity check.Suggested fix:
Hey everyone, add this to the blocklist and do a quick check.The rule uses compromise to avoid partial-word matches (e.g., guyses is not flagged) and skips verb-only usages of ambiguous words such as master in master the skill.
no-llm-speak
LLM-generated copy often falls back to padded, abstract phrases that sound authoritative without saying much. This rule flags common LLM clichés and suggests concrete replacements.
rules: {
'no-llm-speak': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| phrases | LlmSpeakPhrase[] | See source | Phrases to flag, each with a list of alternatives |
| allowedPhrases | string[] | [] | Phrases to allow and skip |
Example with custom phrases:
'no-llm-speak': ['warn', {
phrases: [
{ phrase: 'delve into', alternatives: ['explore', 'examine'] },
{ phrase: 'robust', alternatives: ['strong', 'resilient'] },
],
allowedPhrases: ['crucial'],
}]Flagged example:
It's important to note that we will delve into the robust, intricate tapestry. Furthermore, the system is crucial.Suggested fix:
Note that we will explore the strong, detailed pattern. Also, the system is critical.The rule uses compromise for word-aware matching, so robustness is not flagged when the configured phrase is robust.
no-weak-verbs
Vague action verbs such as make, perform, conduct, and carry out hide the real action. This rule flags weak verbs used as verbs and suggests stronger, more specific alternatives. It uses compromise to identify verb inflections, so made, performed, and carried out are also flagged, while noun usages such as the make of the car are ignored.
rules: {
'no-weak-verbs': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| verbs | WeakVerb[] | [{ verb: 'make', alternatives: ['create', 'build', 'produce'] }, ...] | Verbs to flag, each with suggested alternatives |
| allowList | string[] | [] | Verbs or phrases to allow and skip |
Example with custom verbs:
'no-weak-verbs': ['warn', {
verbs: [
{ verb: 'utilize', alternatives: ['use'] },
{ verb: 'leverage', alternatives: ['use', 'exploit'] },
],
allowList: ['make'],
}]Flagged example:
We need to make a decision, perform a review, and carry out the plan.Suggested fix:
We need to decide, review, and implement the plan.Because the rule matches by verb inflection, it may also flag common phrasal verbs and idioms such as make out, make do, or made it. Add those to allowList if they are acceptable in your style guide.
no-noun-strings
Three or more nouns in a row create dense, hard-to-read compounds. This rule flags consecutive noun strings and suggests rewriting them with verbs or prepositions.
rules: {
'no-noun-strings': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| maxConsecutiveNouns | number | 3 | Maximum consecutive nouns allowed before flagging |
| allowedPhrases | string[] | [] | Phrases to allow and skip |
Example with custom settings:
'no-noun-strings': ['warn', {
maxConsecutiveNouns: 4,
allowedPhrases: ['user experience design process'],
}]Flagged example:
The user experience design process is slow.Suggested fix:
The process for designing the user experience is slow.The rule uses compromise for part-of-speech tagging and skips proper nouns such as place names.
no-n-things
A count plus a placeholder noun — Three things., 5 things to know before launch — borrows its number for rhythm instead of meaning. The frame is a documented AI-writing tell: the count is chosen because enumerated lists feel punchy, not because the content demanded that many items. Name the items in the heading, or drop the count and state the claim.
rules: {
'no-n-things': 'warn',
}Options:
| Option | Type | Default | Description |
|---|---|---|---|
| minCount | number | 2 | Minimum cardinal count before flagging; keeps one thing idioms alone |
| nouns | string[] | ['thing', 'things'] | Placeholder nouns that complete the N ___ frame |
| allowedPhrases | string[] | [] | Phrases to allow and skip |
Example with custom settings:
'no-n-things': ['warn', {
minCount: 3,
nouns: ['thing', 'things', 'tips', 'takeaways'],
}]Flagged example:
Three things you should know about memory.Suggested fix:
How Ditto remembers your conversations.The rule uses compromise for part-of-speech tagging. Only cardinal counts trigger it — idioms like First things first, All things considered, and a few things are left alone, as are concrete counted nouns like three tabs.
