UNPKG

2.36 kBJavaScriptView Raw
1'use strict';
2
3const {isDeepStrictEqual} = require('node:util');
4const espree = require('espree');
5const espurify = require('espurify');
6const {visitIf} = require('enhance-visitors');
7const util = require('../util');
8const createAvaRule = require('../create-ava-rule');
9
10const booleanBinaryOperators = new Set([
11 '==',
12 '===',
13 '!=',
14 '!==',
15 '<',
16 '<=',
17 '>',
18 '>=',
19]);
20
21const knownBooleanSignatures = [
22 'isFinite()',
23 'isNaN()',
24 'Object.is()',
25 'Object.isExtensible()',
26 'Object.isFrozen()',
27 'Object.isSealed()',
28 'Boolean()',
29 'Number.isNaN()',
30 'Number.isFinite()',
31 'Number.isInteger()',
32 'Number.isSafeInteger()',
33 'Array.isArray()',
34 'ArrayBuffer.isView()',
35 'SharedArrayBuffer.isView()',
36 'Reflect.has()',
37 'Reflect.isExtensible()',
38].map(signature => espurify(espree.parse(signature).body[0].expression.callee));
39
40function matchesKnownBooleanExpression(argument) {
41 if (argument.type !== 'CallExpression') {
42 return false;
43 }
44
45 const callee = espurify(argument.callee);
46
47 return knownBooleanSignatures.some(signature => isDeepStrictEqual(callee, signature));
48}
49
50const create = context => {
51 const ava = createAvaRule();
52
53 return ava.merge({
54 CallExpression: visitIf([
55 ava.isInTestFile,
56 ava.isInTestNode,
57 ])(node => {
58 if (
59 node.callee.type === 'MemberExpression'
60 && (node.callee.property.name === 'truthy' || node.callee.property.name === 'falsy')
61 && node.callee.object.name === 't'
62 ) {
63 const argument = node.arguments[0];
64
65 if (argument
66 && ((argument.type === 'BinaryExpression' && booleanBinaryOperators.has(argument.operator))
67 || (argument.type === 'UnaryExpression' && argument.operator === '!')
68 || (argument.type === 'Literal' && argument.value === Boolean(argument.value))
69 || (matchesKnownBooleanExpression(argument)))
70 ) {
71 if (node.callee.property.name === 'falsy') {
72 context.report({
73 node,
74 message: '`t.false()` should be used instead of `t.falsy()`.',
75 });
76 } else {
77 context.report({
78 node,
79 message: '`t.true()` should be used instead of `t.truthy()`.',
80 });
81 }
82 }
83 }
84 }),
85 });
86};
87
88module.exports = {
89 create,
90 meta: {
91 type: 'suggestion',
92 docs: {
93 description: 'Ensure that `t.true()`/`t.false()` are used instead of `t.truthy()`/`t.falsy()`.',
94 url: util.getDocsUrl(__filename),
95 },
96 schema: [],
97 },
98};