forked from vercel/next.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
no-typos.js
108 lines (94 loc) · 2.49 KB
/
no-typos.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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]
}
/* eslint-disable eslint-plugin/require-meta-docs-url */
module.exports = {
meta: {
docs: {
description: 'Prevent common typos in Next.js data fetching functions.',
recommended: true,
},
type: 'problem',
schema: [],
},
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
},
}
},
}