retext-repeated-words
Advanced tools
Comparing version 4.2.0 to 5.0.0
@@ -1,20 +0,1 @@ | ||
/** | ||
* A retext plugin to check for for repeated words. | ||
* | ||
* * Doesn’t warn for some words which *do* occur twice (`the best exhibition | ||
* they had had since`) | ||
* * Doesn’t warn for initialisms (`D. D. will pop up with…`) | ||
* * Doesn’t warn for capitalised words (`Duran Duran…`) | ||
* | ||
* @type {import('unified').Plugin<[], Root>} | ||
*/ | ||
export default function retextRepeatedWords(): | ||
| void | ||
| import('unified').Transformer<import('nlcst').Root, import('nlcst').Root> | ||
export type Root = import('nlcst').Root | ||
export type SentenceContent = import('nlcst').SentenceContent | ||
export type Info = { | ||
value: string | ||
child: SentenceContent | ||
index: number | ||
} | ||
export { default } from "./lib/index.js"; |
118
index.js
@@ -1,117 +0,1 @@ | ||
/** | ||
* @typedef {import('nlcst').Root} Root | ||
* @typedef {import('nlcst').SentenceContent} SentenceContent | ||
* @typedef {{value: string, child: SentenceContent, index: number}} Info | ||
*/ | ||
import {toString} from 'nlcst-to-string' | ||
import {visit, SKIP} from 'unist-util-visit' | ||
import {pointStart, pointEnd} from 'unist-util-position' | ||
const source = 'retext-repeated-words' | ||
const url = 'https://github.com/retextjs/retext-repeated-words#readme' | ||
// List of words that can legally occur twice. | ||
const list = new Set([ | ||
'had', | ||
'that', | ||
'can', | ||
'blah', | ||
'beep', | ||
'yadda', | ||
'sapiens', | ||
'tse', | ||
'mau' | ||
]) | ||
/** | ||
* A retext plugin to check for for repeated words. | ||
* | ||
* * Doesn’t warn for some words which *do* occur twice (`the best exhibition | ||
* they had had since`) | ||
* * Doesn’t warn for initialisms (`D. D. will pop up with…`) | ||
* * Doesn’t warn for capitalised words (`Duran Duran…`) | ||
* | ||
* @type {import('unified').Plugin<[], Root>} | ||
*/ | ||
export default function retextRepeatedWords() { | ||
return (tree, file) => { | ||
visit(tree, 'SentenceNode', (parent) => { | ||
let index = -1 | ||
/** @type {Info|undefined} */ | ||
let previous | ||
/** @type {Info|undefined} */ | ||
let current | ||
while (++index < parent.children.length) { | ||
const child = parent.children[index] | ||
if (child.type === 'WordNode') { | ||
const value = toString(child) | ||
current = {child, index, value} | ||
if ( | ||
previous && | ||
previous.value.toLowerCase() === value.toLowerCase() && | ||
!ignore(value) | ||
) { | ||
Object.assign( | ||
file.message( | ||
'Expected `' + value + '` once, not twice', | ||
{start: pointStart(previous.child), end: pointEnd(child)}, | ||
[source, value.toLowerCase().replace(/\W+/g, '-')].join(':') | ||
), | ||
{ | ||
actual: toString( | ||
parent.children.slice(previous.index, index + 1) | ||
), | ||
expected: [value], | ||
url | ||
} | ||
) | ||
} | ||
} else if (child.type === 'WhiteSpaceNode') { | ||
previous = current | ||
current = undefined | ||
} else { | ||
previous = undefined | ||
current = undefined | ||
} | ||
} | ||
return SKIP | ||
}) | ||
} | ||
} | ||
/** | ||
* Check if `value`, a word which occurs twice, should be ignored. | ||
* | ||
* @param {string} value | ||
* @returns {boolean} | ||
*/ | ||
function ignore(value) { | ||
// …the most heartening exhibition they had had since… | ||
if (list.has(value.toLowerCase())) { | ||
return true | ||
} | ||
const head = value.charAt(0) | ||
if (head === head.toUpperCase()) { | ||
// D. D. will pop up with… | ||
if (value.length === 2 && value.charAt(1) === '.') { | ||
return true | ||
} | ||
const tail = value.slice(1) | ||
// Duran Duran… Bella Bella… | ||
if (tail === tail.toLowerCase()) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
export {default} from './lib/index.js' |
{ | ||
"name": "retext-repeated-words", | ||
"version": "4.2.0", | ||
"version": "5.0.0", | ||
"description": "retext plugin to check for for repeated words", | ||
@@ -29,5 +29,5 @@ "license": "MIT", | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"exports": "./index.js", | ||
"files": [ | ||
"lib/", | ||
"index.d.ts", | ||
@@ -37,43 +37,38 @@ "index.js" | ||
"dependencies": { | ||
"@types/nlcst": "^1.0.0", | ||
"nlcst-to-string": "^3.0.0", | ||
"unified": "^10.0.0", | ||
"unist-util-position": "^4.0.0", | ||
"unist-util-visit": "^4.0.0" | ||
"@types/nlcst": "^2.0.0", | ||
"nlcst-to-string": "^4.0.0", | ||
"unist-util-position": "^5.0.0", | ||
"unist-util-visit": "^5.0.0", | ||
"vfile": "^6.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/tape": "^4.0.0", | ||
"@types/unist": "^2.0.0", | ||
"c8": "^7.0.0", | ||
"prettier": "^2.0.0", | ||
"remark-cli": "^10.0.0", | ||
"@types/node": "^20.0.0", | ||
"c8": "^8.0.0", | ||
"prettier": "^3.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"retext": "^8.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"retext": "^9.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.47.0" | ||
"typescript": "^5.0.0", | ||
"xo": "^0.56.0" | ||
}, | ||
"scripts": { | ||
"build": "rimraf \"*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"build": "tsc --build --clean && tsc --build && type-coverage", | ||
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix", | ||
"prepack": "npm run build && npm run format", | ||
"test": "npm run build && npm run format && npm run test-coverage", | ||
"test-api": "node --conditions development test.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --conditions development test.js", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
"test-coverage": "c8 --100 --check-coverage --reporter lcov npm run test-api" | ||
}, | ||
"prettier": { | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"bracketSpacing": false, | ||
"singleQuote": true, | ||
"bracketSpacing": false, | ||
"semi": false, | ||
"trailingComma": "none" | ||
"tabWidth": 2, | ||
"trailingComma": "none", | ||
"useTabs": false | ||
}, | ||
"xo": { | ||
"prettier": true | ||
}, | ||
"remarkConfig": { | ||
"plugins": [ | ||
"preset-wooorm" | ||
"remark-preset-wooorm" | ||
] | ||
@@ -84,5 +79,11 @@ }, | ||
"detail": true, | ||
"strict": true, | ||
"ignoreCatch": true | ||
"ignoreCatch": true, | ||
"strict": true | ||
}, | ||
"xo": { | ||
"prettier": true, | ||
"rules": { | ||
"unicorn/prefer-string-replace-all": "off" | ||
} | ||
} | ||
} |
142
readme.md
@@ -11,11 +11,34 @@ # retext-repeated-words | ||
[**retext**][retext] plugin to check for ~~`for`~~ repeated words. | ||
**[retext][]** plugin to check for ~~`for`~~ repeated words. | ||
## Contents | ||
* [What is this?](#what-is-this) | ||
* [When should I use this?](#when-should-i-use-this) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`unified().use(retextRepeatedWords)`](#unifieduseretextrepeatedwords) | ||
* [Messages](#messages) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Related](#related) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
## What is this? | ||
This package is a [unified][] ([retext][]) plugin to check for repeated words. | ||
For example, `like like` this. | ||
## When should I use this? | ||
You can opt-into this plugin when you’re dealing with content that might contain | ||
grammar mistakes, and have authors that can fix that content. | ||
## Install | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
This package is [ESM only][esm]. | ||
In Node.js (version 16+), install with [npm][]: | ||
[npm][]: | ||
```sh | ||
@@ -25,5 +48,19 @@ npm install retext-repeated-words | ||
In Deno with [`esm.sh`][esmsh]: | ||
```js | ||
import retextRepeatedWords from 'https://esm.sh/retext-repeated-words@5' | ||
``` | ||
In browsers with [`esm.sh`][esmsh]: | ||
```html | ||
<script type="module"> | ||
import retextRepeatedWords from 'https://esm.sh/retext-repeated-words@5?bundle' | ||
</script> | ||
``` | ||
## Use | ||
Say we have the following file, `example.txt`: | ||
Say our document `example.txt` contains: | ||
@@ -35,6 +72,6 @@ ```txt | ||
…and our script, `example.js`, looks like this: | ||
…and our module `example.js` contains: | ||
```js | ||
import {readSync} from 'to-vfile' | ||
import {read} from 'to-vfile' | ||
import {reporter} from 'vfile-reporter' | ||
@@ -46,21 +83,18 @@ import {unified} from 'unified' | ||
const file = readSync('example.txt') | ||
unified() | ||
const file = await unified() | ||
.use(retextEnglish) | ||
.use(retextRepeatedWords) | ||
.use(retextStringify) | ||
.process(file) | ||
.then((file) => { | ||
console.error(reporter(file)) | ||
}) | ||
.process(await read('example.txt')) | ||
console.error(reporter(file)) | ||
``` | ||
Now, running `node example` yields: | ||
…then running `node example.js` yields: | ||
```txt | ||
example.txt | ||
1:7-1:12 warning Expected `it` once, not twice it retext-repeated-words | ||
1:26-1:31 warning Expected `to` once, not twice to retext-repeated-words | ||
1:51-2:4 warning Expected `the` once, not twice the retext-repeated-words | ||
1:7-1:12 warning Unexpected repeated `it`, remove one occurrence it retext-repeated-words | ||
1:26-1:31 warning Unexpected repeated `to`, remove one occurrence to retext-repeated-words | ||
1:51-2:4 warning Unexpected repeated `the`, remove one occurrence the retext-repeated-words | ||
@@ -73,3 +107,3 @@ ⚠ 3 warnings | ||
This package exports no identifiers. | ||
The default export is `retextRepeatedWords`. | ||
The default export is [`retextRepeatedWords`][api-retext-repeated-words]. | ||
@@ -80,3 +114,13 @@ ### `unified().use(retextRepeatedWords)` | ||
* Doesn’t warn for some words which *do* occur twice (`the best exhibition | ||
###### Parameters | ||
There are no parameters. | ||
###### Returns | ||
Transform ([`Transformer`][unified-transformer]). | ||
###### Notes | ||
* Doesn’t warn for certain words which *do* occur twice (`the best exhibition | ||
they had had since`) | ||
@@ -86,29 +130,29 @@ * Doesn’t warn for initialisms (`D. D. will pop up with…`) | ||
### Messages | ||
## Messages | ||
Each message is emitted as a [`VFileMessage`][message] on `file`, with the | ||
following fields: | ||
Each message is emitted as a [`VFileMessage`][vfile-message] on `file`, with | ||
`source` set to `'retext-repeated-words'`, `ruleId` to the normalized word, | ||
`actual` to both words, and `expected` to suggestions. | ||
###### `message.source` | ||
## Types | ||
Name of this plugin (`'retext-repeated-words'`). | ||
This package is fully typed with [TypeScript][]. | ||
It exports no additional types. | ||
###### `message.ruleId` | ||
## Compatibility | ||
Repeated word (normalized) (`string`, such as `the`). | ||
Projects maintained by the unified collective are compatible with maintained | ||
versions of Node.js. | ||
###### `message.actual` | ||
When we cut a new major release, we drop support for unmaintained versions of | ||
Node. | ||
This means we try to keep the current release line, `retext-repeated-words@^5`, | ||
compatible with Node.js 16. | ||
Current not ok phrase (`string`). | ||
###### `message.expected` | ||
List of suggestions (`Array.<string>`, such as `['the']`). | ||
## Related | ||
* [`retext-indefinite-article`](https://github.com/retextjs/retext-indefinite-article) | ||
— Check if indefinite articles are used correctly | ||
— check if indefinite articles are used correctly | ||
* [`retext-redundant-acronyms`](https://github.com/retextjs/retext-redundant-acronyms) | ||
— Check for redundant acronyms | ||
— check for redundant acronyms | ||
@@ -143,5 +187,5 @@ ## Contribute | ||
[size-badge]: https://img.shields.io/bundlephobia/minzip/retext-repeated-words.svg | ||
[size-badge]: https://img.shields.io/bundlejs/size/retext-repeated-words | ||
[size]: https://bundlephobia.com/result?p=retext-repeated-words | ||
[size]: https://bundlejs.com/?q=retext-repeated-words | ||
@@ -160,9 +204,15 @@ [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg | ||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[esmsh]: https://esm.sh | ||
[typescript]: https://www.typescriptlang.org | ||
[health]: https://github.com/retextjs/.github | ||
[contributing]: https://github.com/retextjs/.github/blob/HEAD/contributing.md | ||
[contributing]: https://github.com/retextjs/.github/blob/main/contributing.md | ||
[support]: https://github.com/retextjs/.github/blob/HEAD/support.md | ||
[support]: https://github.com/retextjs/.github/blob/main/support.md | ||
[coc]: https://github.com/retextjs/.github/blob/HEAD/code-of-conduct.md | ||
[coc]: https://github.com/retextjs/.github/blob/main/code-of-conduct.md | ||
@@ -175,2 +225,8 @@ [license]: license | ||
[message]: https://github.com/vfile/vfile-message | ||
[unified]: https://github.com/unifiedjs/unified | ||
[unified-transformer]: https://github.com/unifiedjs/unified#transformer | ||
[vfile-message]: https://github.com/vfile/vfile-message | ||
[api-retext-repeated-words]: #unifieduseretextrepeatedwords |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
13349
9
7
153
223
1
+ Addedvfile@^6.0.0
+ Added@types/nlcst@2.0.3(transitive)
+ Added@types/unist@3.0.3(transitive)
+ Addednlcst-to-string@4.0.0(transitive)
+ Addedunist-util-is@6.0.0(transitive)
+ Addedunist-util-position@5.0.0(transitive)
+ Addedunist-util-stringify-position@4.0.0(transitive)
+ Addedunist-util-visit@5.0.0(transitive)
+ Addedunist-util-visit-parents@6.0.1(transitive)
+ Addedvfile@6.0.3(transitive)
+ Addedvfile-message@4.0.2(transitive)
- Removedunified@^10.0.0
- Removed@types/nlcst@1.0.4(transitive)
- Removed@types/unist@2.0.11(transitive)
- Removedbail@2.0.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedis-buffer@2.0.5(transitive)
- Removedis-plain-obj@4.1.0(transitive)
- Removednlcst-to-string@3.1.1(transitive)
- Removedtrough@2.2.0(transitive)
- Removedunified@10.1.2(transitive)
- Removedunist-util-is@5.2.1(transitive)
- Removedunist-util-position@4.0.4(transitive)
- Removedunist-util-stringify-position@3.0.3(transitive)
- Removedunist-util-visit@4.1.2(transitive)
- Removedunist-util-visit-parents@5.1.3(transitive)
- Removedvfile@5.3.7(transitive)
- Removedvfile-message@3.1.4(transitive)
Updated@types/nlcst@^2.0.0
Updatednlcst-to-string@^4.0.0
Updatedunist-util-position@^5.0.0
Updatedunist-util-visit@^5.0.0