rsnext/packages/eslint-plugin-next/lib/rules/no-typos.js
kaykdm 3b2732bc36
[ESLint] add no-typos rule to eslint (#26650)
* add no-typos rule to eslint

* return early when function name is correct

* Handle null decl.type

* update check

Co-authored-by: JJ Kasper <jj@jjsweb.site>
2021-07-24 22:22:19 -05:00

107 lines
2.4 KiB
JavaScript

const path = require('path')
const NEXT_EXPORT_FUNCTIONS = [
'getStaticProps',
'getStaticPaths',
'getServerSideProps',
]
// 0 is the exact match
const THRESHOLD = 1
// the minimum number of operations required to convert string a to string b.
function minDistance(a, b) {
const m = a.length
const n = b.length
if (m < n) {
return minDistance(b, a)
}
if (n === 0) {
return m
}
let previousRow = Array.from({ length: n + 1 }, (_, i) => i)
for (let i = 0; i < m; i++) {
const s1 = a[i]
let currentRow = [i + 1]
for (let j = 0; j < n; j++) {
const s2 = b[j]
const insertions = previousRow[j + 1] + 1
const deletions = currentRow[j] + 1
const substitutions = previousRow[j] + Number(s1 !== s2)
currentRow.push(Math.min(insertions, deletions, substitutions))
}
previousRow = currentRow
}
return previousRow[previousRow.length - 1]
}
module.exports = {
meta: {
docs: {
description: 'Prevent common typos',
category: 'Stylistic Issues',
recommended: true,
},
fixable: null,
},
create: function (context) {
function checkTypos(node, name) {
if (NEXT_EXPORT_FUNCTIONS.includes(name)) {
return
}
const potentialTypos = NEXT_EXPORT_FUNCTIONS.map((o) => ({
option: o,
distance: minDistance(o, name),
}))
.filter(({ distance }) => distance <= THRESHOLD && distance > 0)
.sort((a, b) => a.distance - b.distance)
if (potentialTypos.length) {
context.report({
node,
message: `${name} may be a typo. Did you mean ${potentialTypos[0].option}?`,
})
}
}
return {
ExportNamedDeclaration(node) {
const page = context.getFilename().split('pages')[1]
if (!page || path.parse(page).dir.startsWith('/api')) {
return
}
const decl = node.declaration
if (!decl) {
return
}
switch (decl.type) {
case 'FunctionDeclaration': {
checkTypos(node, decl.id.name)
break
}
case 'VariableDeclaration': {
decl.declarations.forEach((d) => {
if (d.id.type !== 'Identifier') {
return
}
checkTypos(node, d.id.name)
})
break
}
default: {
break
}
}
return
},
}
},
}