Skip to content

Commit

Permalink
Add JSDoc based types
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Jul 18, 2021
1 parent 313b5d5 commit 030a210
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 63 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
coverage/
.DS_Store
*.d.ts
*.log
yarn.lock
67 changes: 30 additions & 37 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* @typedef Options
* Configuration.
* @property {string[]} [ignore]
* Phrases *not* to warn about (rule IDs).
*/

import {toString} from 'nlcst-to-string'
import {quotation} from 'quotation'
import {search} from 'nlcst-search'
Expand All @@ -6,52 +13,38 @@ import {patterns} from './patterns.js'

const source = 'retext-simplify'

const list = Object.keys(patterns)

export default function retextSimplify(options) {
const ignore = (options || {}).ignore || []
const keys = Object.keys(patterns)

return transformer
/**
* Plugin to check phrases for simpler alternatives.
*
* @type {import('unified').Plugin<[Options?]>}
*/
export default function retextSimplify(options = {}) {
const ignore = options.ignore || []
const searches =
ignore.length > 0 ? keys.filter((d) => !ignore.includes(d)) : keys

function transformer(tree, file) {
search(tree, list, finder)

function finder(match, index, parent, phrase) {
const id = phrase.replace(/\s+/g, '-').toLowerCase()
return (tree, file) => {
search(tree, searches, (match, _, _1, phrase) => {
const pattern = patterns[phrase]
const expected = pattern.replace
const actual = toString(match)
let reason

if (ignore.includes(id)) {
return
}

if (pattern.omit && expected.length === 0) {
reason = 'Remove ' + quotation(actual, '`')
} else {
reason =
'Replace ' +
quotation(actual, '`') +
' with ' +
quotation(expected, '`').join(', ')

if (pattern.omit) {
reason += ', or remove it'
}
}
const expected = pattern.replace

Object.assign(
file.message(
reason,
{
start: pointStart(match[0]),
end: pointEnd(match[match.length - 1])
},
[source, id].join(':')
pattern.omit && expected.length === 0
? 'Remove ' + quotation(actual, '`')
: 'Replace ' +
quotation(actual, '`') +
' with ' +
quotation(expected, '`').join(', ') +
(pattern.omit ? ', or remove it' : ''),
{start: pointStart(match[0]), end: pointEnd(match[match.length - 1])},
[source, phrase.replace(/\s+/g, '-').toLowerCase()].join(':')
),
{actual, expected}
)
}
})
}
}
17 changes: 16 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,40 @@
"sideEffects": false,
"type": "module",
"main": "index.js",
"types": "index.d.ts",
"files": [
"index.d.ts",
"index.js",
"patterns.d.ts",
"patterns.js"
],
"dependencies": {
"nlcst-search": "^3.0.0",
"nlcst-to-string": "^3.0.0",
"object-keys": "^1.0.9",
"quotation": "^2.0.0",
"unified": "^10.0.0",
"unist-util-position": "^4.0.0"
},
"devDependencies": {
"@types/tape": "^4.0.0",
"c8": "^7.0.0",
"prettier": "^2.0.0",
"remark-cli": "^9.0.0",
"remark-preset-wooorm": "^8.0.0",
"retext": "^8.0.0",
"rimraf": "^3.0.0",
"tape": "^5.0.0",
"type-coverage": "^2.0.0",
"typescript": "^4.0.0",
"xo": "^0.39.0"
},
"scripts": {
"build": "rimraf \"*.d.ts\" && tsc && type-coverage",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"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 format && npm run test-coverage"
"test": "npm run build && npm run format && npm run test-coverage"
},
"prettier": {
"tabWidth": 2,
Expand All @@ -71,5 +80,11 @@
"plugins": [
"preset-wooorm"
]
},
"typeCoverage": {
"atLeast": 100,
"detail": true,
"strict": true,
"ignoreCatch": true
}
}
9 changes: 9 additions & 0 deletions patterns.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/**
* @typedef Pattern
* @property {string[]} replace
* @property {boolean} [omit=false]
*/

/**
* @type {Object.<string, Pattern>}
*/
export const patterns = {
'a number of': {
replace: ['many', 'some']
Expand Down
51 changes: 26 additions & 25 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ test('retext-simplify', (t) => {

retext()
.use(retextSimplify)
.process('You can utilize a shorter word.', (error, file) => {
.process('You can utilize a shorter word.')
.then((file) => {
t.deepEqual(
[error].concat(JSON.parse(JSON.stringify(file.messages))),
JSON.parse(JSON.stringify(file.messages)),
[
null,
{
name: '1:9-1:16',
message: 'Replace `utilize` with `use`',
Expand All @@ -31,43 +31,44 @@ test('retext-simplify', (t) => {
],
'should emit messages'
)
})
}, t.ifErr)

retext()
.use(retextSimplify)
.process('In order for this to work, clap your hands.', (error, file) => {
.process('In order for this to work, clap your hands.')
.then((file) => {
t.deepEqual(
[error].concat(file.messages.map((d) => String(d))),
[null, '1:1-1:13: Replace `In order for` with `for`'],
file.messages.map((d) => String(d)),
['1:1-1:13: Replace `In order for` with `for`'],
'should warn about wordiness'
)
})
}, t.ifErr)

retext()
.use(retextSimplify)
.process(
'You can utilize a shorter word.\nBe advised, don’t do this.\nThat’s the appropriate thing to do.',
(error, file) => {
t.deepEqual(
[error].concat(file.messages.map((d) => String(d))),
[
null,
'1:9-1:16: Replace `utilize` with `use`',
'2:1-2:11: Remove `Be advised`',
'3:12-3:23: Replace `appropriate` with `proper`, `right`, or remove it'
],
'should warn about simpler synonyms'
)
}
'You can utilize a shorter word.\nBe advised, don’t do this.\nThat’s the appropriate thing to do.'
)
.then((file) => {
t.deepEqual(
file.messages.map((d) => String(d)),
[
'1:9-1:16: Replace `utilize` with `use`',
'2:1-2:11: Remove `Be advised`',
'3:12-3:23: Replace `appropriate` with `proper`, `right`, or remove it'
],
'should warn about simpler synonyms'
)
}, t.ifErr)

retext()
.use(retextSimplify, {ignore: ['utilize']})
.process('You can utilize a shorter word.', (error, file) => {
.process('You can utilize a shorter word.')
.then((file) => {
t.deepEqual(
[error].concat(file.messages.map((d) => String(d))),
[null],
file.messages.map((d) => String(d)),
[],
'should not warn for ignored phrases'
)
})
}, t.ifErr)
})
16 changes: 16 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"include": ["*.js"],
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020"],
"module": "ES2020",
"moduleResolution": "node",
"allowJs": true,
"checkJs": true,
"declaration": true,
"emitDeclarationOnly": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"strict": true
}
}

0 comments on commit 030a210

Please sign in to comment.