Skip to content

Commit 381beee

Browse files
committed
pong
1 parent 946bc97 commit 381beee

File tree

2 files changed

+79
-192
lines changed

2 files changed

+79
-192
lines changed

rules/use-t-well.js

Lines changed: 74 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -3,100 +3,33 @@ const {visitIf} = require('enhance-visitors');
33
const util = require('../util');
44
const createAvaRule = require('../create-ava-rule');
55

6-
class MicroCorrecter {
7-
constructor(words) {
8-
this.words = new Set(words);
9-
10-
const letters = new Set();
11-
words.forEach(word => word.split('').forEach(letter => letters.add(letter)));
12-
this.letters = [...letters];
13-
}
14-
15-
edits(word) {
16-
const edits = [];
17-
const {length} = word;
18-
const {letters} = this;
19-
20-
for (let i = 0; i < length; i++) {
21-
edits.push(word.slice(0, i) + word.slice(i + 1)); // Skip
22-
for (const letter of letters) {
23-
edits.push(word.slice(0, i) + letter + word.slice(i + 1)); // Replace
24-
}
25-
}
26-
27-
for (let i = 1; i < length; i++) {
28-
edits.push(word.slice(0, i - 1) + word[i] + word[i - 1] + word.slice(i + 1)); // Transposition
29-
}
30-
31-
for (let i = 0; i <= length; i++) {
32-
for (const letter of letters) {
33-
edits.push(word.slice(0, i) + letter + word.slice(i)); // Addition
34-
}
35-
}
36-
37-
return edits;
38-
}
39-
40-
correct(word, distance) {
41-
const {words} = this;
42-
43-
if (words.has(word)) {
44-
return word;
45-
}
46-
47-
if (distance > 0) {
48-
const edits = this.edits(word);
49-
50-
for (const edit of edits) {
51-
if (words.has(edit)) {
52-
return edit;
53-
}
54-
}
55-
56-
if (distance > 1) {
57-
for (const edit of edits) {
58-
const correction = this.correct(edit, distance - 1);
59-
if (correction !== undefined) {
60-
return correction;
61-
}
62-
}
63-
}
64-
}
65-
}
66-
}
67-
68-
const nonMethods = new Set([
69-
'context',
70-
'title'
71-
]);
72-
73-
const properties = new Set([
74-
...nonMethods,
75-
...util.executionMethods,
76-
'skip'
77-
]);
78-
79-
const correcter = new MicroCorrecter([...properties]);
6+
const isMethod = name => util.executionMethods.has(name);
807

818
const isCallExpression = node =>
829
node.parent.type === 'CallExpression' &&
8310
node.parent.callee === node;
8411

85-
const correctIfNeeded = (name, context, node) => {
86-
const correction = correcter.correct(name, Math.max(0, Math.min(name.length - 2, 2)));
87-
if (correction === undefined) {
88-
return undefined;
89-
}
90-
91-
if (correction !== name) {
92-
context.report({
93-
node,
94-
message: `Misspelled \`.${correction}\` as \`.${name}\`.`,
95-
fix: fixer => fixer.replaceText(node.property, correction)
96-
});
97-
}
12+
const getMemberStats = members => {
13+
const initial = {
14+
skip: [],
15+
falsey: [],
16+
method: [],
17+
other: []
18+
};
19+
20+
return members.reduce((res, member) => {
21+
if (member === 'skip') {
22+
res.skip.push(member);
23+
} else if (member === 'falsey') {
24+
res.falsey.push(member);
25+
} else if (isMethod(member)) {
26+
res.method.push(member);
27+
} else {
28+
res.other.push(member);
29+
}
9830

99-
return correction;
31+
return res;
32+
}, initial);
10033
};
10134

10235
const create = context => {
@@ -125,62 +58,66 @@ const create = context => {
12558
}
12659

12760
const members = util.getMembers(node);
61+
const stats = getMemberStats(members);
62+
63+
if (members[0] === 'context') {
64+
// Anything is fine when of the form `t.context...`
65+
if (members.length === 1 && isCallExpression(node)) {
66+
// Except `t.context()`
67+
context.report({
68+
node,
69+
message: 'Unknown assertion method `.context`.'
70+
});
71+
}
12872

129-
let hadSkip = false;
130-
let hadCall = false;
131-
let needCall = true;
132-
for (const [i, member] of members.entries()) {
133-
const corrected = correctIfNeeded(member, context, node);
134-
if (corrected === undefined) {
135-
needCall = false;
136-
if (isCallExpression(node)) {
137-
context.report({
138-
node,
139-
message: `Unknown assertion method \`.${member}\`.`
140-
});
141-
} else {
142-
context.report({
143-
node,
144-
message: `Unknown member \`.${member}\`. Use \`.context.${member}\` instead.`
145-
});
146-
}
147-
148-
break;
149-
} else if (i === 0 && nonMethods.has(corrected)) {
150-
needCall = false;
151-
if (members.length === 1 && isCallExpression(node)) {
152-
context.report({
153-
node,
154-
message: `Unknown assertion method \`.${member}\`.`
155-
});
156-
}
157-
158-
break;
159-
} else if (corrected === 'skip') {
160-
if (hadSkip) {
161-
context.report({
162-
node,
163-
message: 'Too many chained uses of `.skip`.'
164-
});
165-
}
166-
167-
hadSkip = true;
168-
} else {
169-
if (hadCall) {
170-
context.report({
171-
node,
172-
message: 'Can\'t chain assertion methods.'
173-
});
174-
}
73+
return;
74+
}
17575

176-
hadCall = true;
76+
if (members[0] === 'title') {
77+
// Anything is fine when of the form `t.title...`
78+
if (members.length === 1 && isCallExpression(node)) {
79+
// Except `t.title()`
80+
context.report({
81+
node,
82+
message: 'Unknown assertion method `.title`.'
83+
});
17784
}
85+
86+
return;
17887
}
17988

180-
if (needCall && !hadCall) {
89+
if (isCallExpression(node)) {
90+
if (stats.other.length > 0) {
91+
context.report({
92+
node,
93+
message: `Unknown assertion method \`.${stats.other[0]}\`.`
94+
});
95+
} else if (stats.skip.length > 1) {
96+
context.report({
97+
node,
98+
message: 'Too many chained uses of `.skip`.'
99+
});
100+
} else if (stats.falsey.length > 0) {
101+
context.report({
102+
node,
103+
message: 'Misspelled `.falsy` as `.falsey`.',
104+
fix: fixer => fixer.replaceText(node.property, 'falsy')
105+
});
106+
} else if (stats.method.length > 1) {
107+
context.report({
108+
node,
109+
message: 'Can\'t chain assertion methods.'
110+
});
111+
} else if (stats.method.length === 0) {
112+
context.report({
113+
node,
114+
message: 'Missing assertion method.'
115+
});
116+
}
117+
} else if (stats.other.length > 0) {
181118
context.report({
182119
node,
183-
message: 'Missing assertion method.'
120+
message: `Unknown member \`.${stats.other[0]}\`. Use \`.context.${stats.other[0]}\` instead.`
184121
});
185122
}
186123
})

test/use-t-well.js

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,15 @@ ruleTester.run('use-t-well', rule, {
7979
},
8080
{
8181
code: testCase('t.depEqual(a, a);'),
82-
errors: [error('Misspelled `.deepEqual` as `.depEqual`.')]
82+
errors: [error('Unknown assertion method `.depEqual`.')]
8383
},
8484
{
8585
code: testCase('t.deepEqual.skp(a, a);'),
86-
errors: [error('Misspelled `.skip` as `.skp`.')]
86+
errors: [error('Unknown assertion method `.skp`.')]
8787
},
8888
{
8989
code: testCase('t.skp.deepEqual(a, a);'),
90-
errors: [error('Misspelled `.skip` as `.skp`.')]
90+
errors: [error('Unknown assertion method `.skp`.')]
9191
},
9292
{
9393
code: testCase('t.context();'),
@@ -107,15 +107,15 @@ ruleTester.run('use-t-well', rule, {
107107
},
108108
{
109109
code: testCase('t.deepEqu;'),
110-
errors: [error('Misspelled `.deepEqual` as `.deepEqu`.')]
110+
errors: [error('Unknown member `.deepEqu`. Use `.context.deepEqu` instead.')]
111111
},
112112
{
113113
code: testCase('t.deepEqual.is(a, a);'),
114114
errors: [error('Can\'t chain assertion methods.')]
115115
},
116116
{
117117
code: testCase('t.paln(1);'),
118-
errors: [error('Misspelled `.plan` as `.paln`.')]
118+
errors: [error('Unknown assertion method `.paln`.')]
119119
},
120120
{
121121
code: testCase('t.skip();'),
@@ -129,56 +129,6 @@ ruleTester.run('use-t-well', rule, {
129129
code: testCase('t.falsey(a);'),
130130
output: testCase('t.falsy(a);'),
131131
errors: [error('Misspelled `.falsy` as `.falsey`.')]
132-
},
133-
{
134-
code: testCase('t.truthey(a);'),
135-
output: testCase('t.truthy(a);'),
136-
errors: [error('Misspelled `.truthy` as `.truthey`.')]
137-
},
138-
{
139-
code: testCase('t.deepequal(a, {});'),
140-
output: testCase('t.deepEqual(a, {});'),
141-
errors: [error('Misspelled `.deepEqual` as `.deepequal`.')]
142-
},
143-
{
144-
code: testCase('t.contxt;'),
145-
output: testCase('t.context;'),
146-
errors: [error('Misspelled `.context` as `.contxt`.')]
147-
},
148-
{
149-
code: testCase('t.notdeepEqual(a, {});'),
150-
output: testCase('t.notDeepEqual(a, {});'),
151-
errors: [error('Misspelled `.notDeepEqual` as `.notdeepEqual`.')]
152-
},
153-
{
154-
code: testCase('t.throw(a);'),
155-
output: testCase('t.throws(a);'),
156-
errors: [error('Misspelled `.throws` as `.throw`.')]
157-
},
158-
{
159-
code: testCase('t.notThrow(a);'),
160-
output: testCase('t.notThrows(a);'),
161-
errors: [error('Misspelled `.notThrows` as `.notThrow`.')]
162-
},
163-
{
164-
code: testCase('t.throwAsync(a);'),
165-
output: testCase('t.throwsAsync(a);'),
166-
errors: [error('Misspelled `.throwsAsync` as `.throwAsync`.')]
167-
},
168-
{
169-
code: testCase('t.notthrowAsync(a);'),
170-
output: testCase('t.notThrowsAsync(a);'),
171-
errors: [error('Misspelled `.notThrowsAsync` as `.notthrowAsync`.')]
172-
},
173-
{
174-
code: testCase('t.regexp(a, /r/);'),
175-
output: testCase('t.regex(a, /r/);'),
176-
errors: [error('Misspelled `.regex` as `.regexp`.')]
177-
},
178-
{
179-
code: testCase('t.notregexp(a, /r/);'),
180-
output: testCase('t.notRegex(a, /r/);'),
181-
errors: [error('Misspelled `.notRegex` as `.notregexp`.')]
182132
}
183133
]
184134
});

0 commit comments

Comments
 (0)