eslint-node-test 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/configs/core-rule-replacements.js +9 -0
  2. package/configs/flat-config-base.js +9 -0
  3. package/index.d.ts +11 -0
  4. package/index.js +51 -0
  5. package/license +9 -0
  6. package/package.json +106 -0
  7. package/readme.md +143 -0
  8. package/rules/assertion-arguments.js +134 -0
  9. package/rules/ast/call-or-new-expression.js +100 -0
  10. package/rules/ast/function-types.js +7 -0
  11. package/rules/ast/index.js +17 -0
  12. package/rules/ast/is-expression-statement.js +7 -0
  13. package/rules/ast/is-function.js +5 -0
  14. package/rules/ast/is-loop.js +5 -0
  15. package/rules/ast/is-member-expression.js +98 -0
  16. package/rules/ast/is-method-call.js +62 -0
  17. package/rules/ast/literal.js +32 -0
  18. package/rules/ast/loop-types.js +9 -0
  19. package/rules/consistent-modifier-style.js +95 -0
  20. package/rules/consistent-test-context-name.js +75 -0
  21. package/rules/consistent-test-filename.js +70 -0
  22. package/rules/consistent-test-it.js +86 -0
  23. package/rules/fix/index.js +5 -0
  24. package/rules/fix/remove-argument.js +58 -0
  25. package/rules/fix/replace-member-expression-property.js +25 -0
  26. package/rules/hooks-order.js +132 -0
  27. package/rules/index.js +66 -0
  28. package/rules/max-assertions.js +87 -0
  29. package/rules/max-nested-describe.js +70 -0
  30. package/rules/no-assert-in-describe.js +51 -0
  31. package/rules/no-assert-in-hook.js +51 -0
  32. package/rules/no-assert-throws-async.js +114 -0
  33. package/rules/no-assert-throws-string.js +65 -0
  34. package/rules/no-async-describe.js +50 -0
  35. package/rules/no-async-fn-without-await.js +74 -0
  36. package/rules/no-callback-and-promise.js +56 -0
  37. package/rules/no-commented-tests.js +59 -0
  38. package/rules/no-conditional-assertion.js +101 -0
  39. package/rules/no-conditional-in-test.js +66 -0
  40. package/rules/no-conditional-tests.js +75 -0
  41. package/rules/no-conflicting-modifiers.js +73 -0
  42. package/rules/no-done-callback.js +58 -0
  43. package/rules/no-duplicate-hooks.js +75 -0
  44. package/rules/no-export.js +79 -0
  45. package/rules/no-identical-assertion-arguments.js +71 -0
  46. package/rules/no-identical-title.js +101 -0
  47. package/rules/no-incorrect-deep-equal.js +100 -0
  48. package/rules/no-incorrect-strict-equal.js +86 -0
  49. package/rules/no-loop-static-title.js +93 -0
  50. package/rules/no-misused-concurrency.js +85 -0
  51. package/rules/no-mock-timers-destructured-import.js +150 -0
  52. package/rules/no-nested-tests.js +71 -0
  53. package/rules/no-only-test.js +11 -0
  54. package/rules/no-skip-test.js +11 -0
  55. package/rules/no-skip-without-reason.js +88 -0
  56. package/rules/no-skip-without-return.js +127 -0
  57. package/rules/no-standalone-assert.js +51 -0
  58. package/rules/no-test-inside-hook.js +68 -0
  59. package/rules/no-test-return-statement.js +114 -0
  60. package/rules/no-todo-test.js +11 -0
  61. package/rules/no-unawaited-rejects.js +74 -0
  62. package/rules/no-unawaited-subtest.js +66 -0
  63. package/rules/no-unknown-test-options.js +77 -0
  64. package/rules/no-useless-assertion.js +47 -0
  65. package/rules/prefer-assert-match.js +245 -0
  66. package/rules/prefer-assert-throws.js +90 -0
  67. package/rules/prefer-async-await.js +203 -0
  68. package/rules/prefer-context-mock.js +59 -0
  69. package/rules/prefer-diagnostic.js +94 -0
  70. package/rules/prefer-equality-assertion.js +101 -0
  71. package/rules/prefer-hooks-on-top.js +73 -0
  72. package/rules/prefer-lowercase-title.js +119 -0
  73. package/rules/prefer-mock-method.js +115 -0
  74. package/rules/prefer-strict-assert.js +69 -0
  75. package/rules/prefer-test-context-assert.js +125 -0
  76. package/rules/prefer-todo.js +98 -0
  77. package/rules/require-assertion.js +92 -0
  78. package/rules/require-await-concurrent-subtests.js +119 -0
  79. package/rules/require-context-assert-with-plan.js +127 -0
  80. package/rules/require-hook.js +108 -0
  81. package/rules/require-throws-expectation.js +52 -0
  82. package/rules/require-top-level-describe.js +89 -0
  83. package/rules/rule/index.js +9 -0
  84. package/rules/rule/to-eslint-create.js +37 -0
  85. package/rules/rule/to-eslint-listener.js +40 -0
  86. package/rules/rule/to-eslint-problem.js +38 -0
  87. package/rules/rule/to-eslint-rule-fixer.js +49 -0
  88. package/rules/rule/to-eslint-rule.js +38 -0
  89. package/rules/rule/to-eslint-rules.js +10 -0
  90. package/rules/rule/unicorn-context.js +36 -0
  91. package/rules/rule/unicorn-listeners.js +65 -0
  92. package/rules/rule/utilities.js +26 -0
  93. package/rules/shared/test-modifier-rule.js +92 -0
  94. package/rules/test-title-format.js +86 -0
  95. package/rules/test-title.js +139 -0
  96. package/rules/utils/contains-suspension-point.js +35 -0
  97. package/rules/utils/escape-string.js +24 -0
  98. package/rules/utils/get-comments.js +15 -0
  99. package/rules/utils/get-documentation-url.js +9 -0
  100. package/rules/utils/get-enclosing-function.js +18 -0
  101. package/rules/utils/index.js +16 -0
  102. package/rules/utils/is-conditional-branch.js +37 -0
  103. package/rules/utils/is-promise-type.js +28 -0
  104. package/rules/utils/is-same-reference.js +179 -0
  105. package/rules/utils/is-value-not-usable.js +5 -0
  106. package/rules/utils/node-test.js +713 -0
  107. package/rules/utils/parentheses/get-parent-syntax-opening-parenthesis.js +80 -0
  108. package/rules/utils/parentheses/iterate-surrounding-parentheses.js +82 -0
  109. package/rules/utils/parentheses/parentheses.js +69 -0
  110. package/rules/utils/types.js +5 -0
  111. package/rules/utils/unwrap-typescript-expression.js +16 -0
  112. package/rules/valid-describe-callback.js +63 -0
@@ -0,0 +1,80 @@
1
+ import {isOpeningParenToken as isOpeningParenthesisToken} from '@eslint-community/eslint-utils';
2
+
3
+ /**
4
+ @import {TSESTree as ESTree} from '@typescript-eslint/types';
5
+ @import * as ESLint from 'eslint';
6
+ @import {
7
+ OpeningParenToken as OpeningParenthesisToken,
8
+ } from '@eslint-community/eslint-utils';
9
+ */
10
+
11
+ /**
12
+ Get the opening parenthesis of the parent node syntax if it exists.
13
+ E.g., `if (a) {}` then the `(`.
14
+ @param {ESTree.Node} node The AST node to check.
15
+ @param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
16
+ @returns {OpeningParenthesisToken | void} The left parenthesis of the parent node syntax
17
+ */
18
+ function getParentSyntaxOpeningParenthesis(node, context) {
19
+ const {parent} = node;
20
+
21
+ switch (parent.type) {
22
+ case 'CallExpression':
23
+ case 'NewExpression': {
24
+ if (parent.arguments.length === 1 && parent.arguments[0] === node) {
25
+ return context.sourceCode.getTokenAfter(
26
+ parent.typeArguments ?? parent.callee,
27
+ isOpeningParenthesisToken,
28
+ );
29
+ }
30
+
31
+ return;
32
+ }
33
+
34
+ case 'DoWhileStatement': {
35
+ if (parent.test === node) {
36
+ return context.sourceCode.getTokenAfter(
37
+ parent.body,
38
+ isOpeningParenthesisToken,
39
+ );
40
+ }
41
+
42
+ return;
43
+ }
44
+
45
+ case 'IfStatement':
46
+ case 'WhileStatement': {
47
+ if (parent.test === node) {
48
+ return context.sourceCode.getFirstToken(parent, 1);
49
+ }
50
+
51
+ return;
52
+ }
53
+
54
+ case 'ImportExpression': {
55
+ if (parent.source === node) {
56
+ return context.sourceCode.getFirstToken(parent, 1);
57
+ }
58
+
59
+ return;
60
+ }
61
+
62
+ case 'SwitchStatement': {
63
+ if (parent.discriminant === node) {
64
+ return context.sourceCode.getFirstToken(parent, 1);
65
+ }
66
+
67
+ return;
68
+ }
69
+
70
+ case 'WithStatement': {
71
+ if (parent.object === node) {
72
+ return context.sourceCode.getFirstToken(parent, 1);
73
+ }
74
+ }
75
+
76
+ // No default
77
+ }
78
+ }
79
+
80
+ export default getParentSyntaxOpeningParenthesis;
@@ -0,0 +1,82 @@
1
+ // Based on https://github.com/eslint-community/eslint-utils/blob/1da21d4440028679f3c8d5841b85f9d97ca7f0f7/src/is-parenthesized.mjs#L1
2
+
3
+ import {
4
+ isOpeningParenToken as isOpeningParenthesisToken,
5
+ isClosingParenToken as isClosingParenthesisToken,
6
+ } from '@eslint-community/eslint-utils';
7
+ import getParentSyntaxOpeningParenthesis from './get-parent-syntax-opening-parenthesis.js';
8
+
9
+ /**
10
+ @import {TSESTree as ESTree} from '@typescript-eslint/types';
11
+ @import * as ESLint from 'eslint';
12
+ @import {
13
+ OpeningParenToken as OpeningParenthesisToken,
14
+ ClosingParenToken as ClosingParenthesisToken,
15
+ } from '@eslint-community/eslint-utils';
16
+ */
17
+
18
+ /**
19
+ @typedef {[OpeningParenthesisToken, ClosingParenthesisToken]} ParenthesisTokenPair
20
+ */
21
+
22
+ /**
23
+ Get surrounding parenthesis of the tokens or nodes.
24
+
25
+ @param {[ESTree.Node | OpeningParenthesisToken, ESTree.Node | ClosingParenthesisToken]} param0
26
+ @param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
27
+ @returns [ParenthesisTokenPair | void]
28
+ */
29
+ function getSurroundingParentheses([head, tail], context) {
30
+ const tokenBefore = context.sourceCode.getTokenBefore(head);
31
+
32
+ if (!tokenBefore || !isOpeningParenthesisToken(tokenBefore)) {
33
+ return;
34
+ }
35
+
36
+ const tokenAfter = context.sourceCode.getTokenAfter(tail);
37
+
38
+ if (!tokenAfter || !isClosingParenthesisToken(tokenAfter)) {
39
+ return;
40
+ }
41
+
42
+ return [tokenBefore, tokenAfter];
43
+ }
44
+
45
+ const SYNTAX_OPENING_PARENTHESIS_INITIAL_VALUE = Symbol('SYNTAX_OPENING_PARENTHESIS_INITIAL_VALUE');
46
+
47
+ /**
48
+ Iterate surrounding parenthesis of the node.
49
+
50
+ @param {ESTree.Node} node
51
+ @param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
52
+ @returns {IterableIterator<ParenthesisTokenPair>}
53
+ */
54
+ function * iterateSurroundingParentheses(node, context) {
55
+ if (
56
+ !node
57
+ // `Program` can't be parenthesized
58
+ || !node.parent
59
+ // `CatchClause.param` can't be parenthesized, example `try {} catch (error) {}`
60
+ || (node.parent.type === 'CatchClause' && node.parent.param === node)
61
+ ) {
62
+ return;
63
+ }
64
+
65
+ let syntaxOpeningParenthesis = SYNTAX_OPENING_PARENTHESIS_INITIAL_VALUE;
66
+ let parentheses = [node, node];
67
+ while ((parentheses = getSurroundingParentheses(parentheses, context))) {
68
+ const [openingParenthesisToken] = parentheses;
69
+
70
+ if (syntaxOpeningParenthesis === SYNTAX_OPENING_PARENTHESIS_INITIAL_VALUE) {
71
+ syntaxOpeningParenthesis = getParentSyntaxOpeningParenthesis(node, context);
72
+ }
73
+
74
+ if (openingParenthesisToken === syntaxOpeningParenthesis) {
75
+ break;
76
+ }
77
+
78
+ yield parentheses;
79
+ }
80
+ }
81
+
82
+ export default iterateSurroundingParentheses;
@@ -0,0 +1,69 @@
1
+ import iterateSurroundingParentheses from './iterate-surrounding-parentheses.js';
2
+
3
+ /**
4
+ @import {TSESTree as ESTree} from '@typescript-eslint/types';
5
+ @import * as ESLint from 'eslint';
6
+ @import {
7
+ OpeningParenToken as OpeningParenthesisToken,
8
+ ClosingParenToken as ClosingParenthesisToken,
9
+ } from '@eslint-community/eslint-utils';
10
+ */
11
+
12
+ /** @typedef {WeakMap<ESTree.Node, (OpeningParenthesisToken | ClosingParenthesisToken)[]>} */
13
+ const parenthesesCache = new WeakMap();
14
+
15
+ /**
16
+ Get surrounding parenthesis of the node.
17
+
18
+ @param {ESTree.Node} node
19
+ @param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
20
+ @returns [(OpeningParenthesisToken | ClosingParenthesisToken)[]]
21
+ */
22
+ export function getParentheses(node, context) {
23
+ if (!node || !parenthesesCache.has(node)) {
24
+ const parenthesis = [];
25
+ for (const [openingParenthesisToken, closingParenthesisToken] of iterateSurroundingParentheses(node, context)) {
26
+ parenthesis.unshift(openingParenthesisToken);
27
+ parenthesis.push(closingParenthesisToken);
28
+ }
29
+
30
+ parenthesesCache.set(node, parenthesis);
31
+ }
32
+
33
+ return parenthesesCache.get(node);
34
+ }
35
+
36
+ /*
37
+ Get the parenthesized range of the node.
38
+
39
+ @param {ESTree.Node} node - The node to be checked.
40
+ @param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
41
+ @returns {number[]}
42
+ */
43
+ export function getParenthesizedRange(node, context) {
44
+ const parentheses = getParentheses(node, context);
45
+ const [start] = context.sourceCode.getRange(parentheses[0] ?? node);
46
+ const [, end] = context.sourceCode.getRange(parentheses.at(-1) ?? node);
47
+ return [start, end];
48
+ }
49
+
50
+ /**
51
+ Check whether a given node is parenthesized or not.
52
+
53
+ @param {ESTree.Node} node The AST node to check.
54
+ @param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
55
+ @returns {boolean} `true` if the node is parenthesized.
56
+ */
57
+ export function isParenthesized(node, context) {
58
+ if (parenthesesCache.has(node)) {
59
+ return parenthesesCache.get(node).length > 0;
60
+ }
61
+
62
+ const isNotParenthesized = iterateSurroundingParentheses(node, context).next().done;
63
+
64
+ if (isNotParenthesized) {
65
+ parenthesesCache.set(node, []);
66
+ }
67
+
68
+ return !isNotParenthesized;
69
+ }
@@ -0,0 +1,5 @@
1
+ const unknownTypeNames = new Set(['any', 'error', 'unknown']);
2
+
3
+ const isUnknownType = type => unknownTypeNames.has(type.intrinsicName);
4
+
5
+ export {isUnknownType};
@@ -0,0 +1,16 @@
1
+ const typeScriptExpressionWrapperTypes = new Set([
2
+ 'TSAsExpression',
3
+ 'TSSatisfiesExpression',
4
+ 'TSNonNullExpression',
5
+ 'TSTypeAssertion',
6
+ ]);
7
+
8
+ export const isTypeScriptExpressionWrapper = node => typeScriptExpressionWrapperTypes.has(node?.type);
9
+
10
+ export default function unwrapTypeScriptExpression(node) {
11
+ while (isTypeScriptExpressionWrapper(node)) {
12
+ node = node.expression;
13
+ }
14
+
15
+ return node;
16
+ }
@@ -0,0 +1,63 @@
1
+ import {resolveImports, parseTestCall, getTestCallback} from './utils/node-test.js';
2
+
3
+ const MESSAGE_ID_PARAMETER = 'valid-describe-callback/parameter';
4
+ const MESSAGE_ID_RETURN = 'valid-describe-callback/return';
5
+
6
+ const messages = {
7
+ [MESSAGE_ID_PARAMETER]: 'The `{{name}}` callback is called with no arguments. The test context is only passed to `test`/`it` callbacks.',
8
+ [MESSAGE_ID_RETURN]: 'The `{{name}}` callback should not return a value, `node:test` ignores it. Use a block body.',
9
+ };
10
+
11
+ /** @param {import('eslint').Rule.RuleContext} context */
12
+ const create = context => {
13
+ const imports = resolveImports(context);
14
+ if (!imports.isTestFile) {
15
+ return;
16
+ }
17
+
18
+ context.on('CallExpression', function * (node) {
19
+ const parsed = parseTestCall(node, imports);
20
+ if (parsed?.kind !== 'suite') {
21
+ return;
22
+ }
23
+
24
+ const callback = getTestCallback(node);
25
+ if (!callback) {
26
+ return;
27
+ }
28
+
29
+ if (callback.params.length > 0) {
30
+ yield {
31
+ node: callback.params[0],
32
+ messageId: MESSAGE_ID_PARAMETER,
33
+ data: {name: parsed.name},
34
+ };
35
+ }
36
+
37
+ // An arrow with an expression body implicitly returns a value.
38
+ if (callback.type === 'ArrowFunctionExpression' && callback.body.type !== 'BlockStatement') {
39
+ yield {
40
+ node: callback.body,
41
+ messageId: MESSAGE_ID_RETURN,
42
+ data: {name: parsed.name},
43
+ };
44
+ }
45
+ });
46
+ };
47
+
48
+ /** @type {import('eslint').Rule.RuleModule} */
49
+ const config = {
50
+ create,
51
+ meta: {
52
+ type: 'problem',
53
+ docs: {
54
+ description: 'Enforce valid `describe` callbacks.',
55
+ recommended: 'unopinionated',
56
+ },
57
+ schema: [],
58
+ messages,
59
+ languages: ['js/js'],
60
+ },
61
+ };
62
+
63
+ export default config;