diff --git a/docs/rules/consistent-assert.md b/docs/rules/consistent-assert.md new file mode 100644 index 0000000000..5a202a66cb --- /dev/null +++ b/docs/rules/consistent-assert.md @@ -0,0 +1,51 @@ +# Enforce consistent assertion style with `node:assert` + +πŸ’Ό This rule is enabled in the βœ… `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs-eslintconfigjs). + +πŸ”§ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). + + + + +Prefer `assert.ok()` over `assert()` for its explicit intent and better readability. It aligns with other assert methods, ensuring consistency and making code easier to maintain and understand. + +## Examples + +```js +import assert from 'node:assert/strict'; + +assert.strictEqual(actual, expected); +assert.deepStrictEqual(actual, expected); + +// ❌ +assert(divide(10, 2) === 5); // Inconsistent with other API styles + +// βœ… +assert.ok(divide(10, 2) === 5); +``` + +```js +import assert from 'node:assert'; + +assert.strictEqual(actual, expected); +assert.deepStrictEqual(actual, expected); + +// ❌ +assert(divide(10, 2) === 5); // Inconsistent with other API styles + +// βœ… +assert.ok(divide(10, 2) === 5); +``` + +```js +import {strict as assert} from 'node:assert'; + +assert.strictEqual(actual, expected); +assert.deepStrictEqual(actual, expected); + +// ❌ +assert(divide(10, 2) === 5); // Inconsistent with other API styles + +// βœ… +assert.ok(divide(10, 2) === 5); +``` diff --git a/readme.md b/readme.md index 2d120a0587..6caab21cca 100644 --- a/readme.md +++ b/readme.md @@ -58,6 +58,7 @@ export default [ | :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | | [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | πŸ”§ | | | [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | βœ… | πŸ”§ | | +| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | βœ… | πŸ”§ | | | [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | πŸ”§ | πŸ’‘ | | [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | βœ… | πŸ”§ | | | [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | βœ… | πŸ”§ | | diff --git a/rules/consistent-assert.js b/rules/consistent-assert.js new file mode 100644 index 0000000000..0f46b7b1fa --- /dev/null +++ b/rules/consistent-assert.js @@ -0,0 +1,98 @@ +const MESSAGE_ID_ERROR = 'consistent-assert/error'; +const messages = { + [MESSAGE_ID_ERROR]: 'Prefer `{{name}}.ok(…)` over `{{name}}(…)`.', +}; + +/** +@param {import('estree').ImportSpecifier | import('estree').ImportDefaultSpecifier | import('estree').ImportSpecifier | import('estree').ImportDeclaration} node +*/ +const isValueImport = node => !node.importKind || node.importKind === 'value'; + +/** +Check if a specifier is `assert` function. + +@param {import('estree').ImportSpecifier | import('estree').ImportDefaultSpecifier} specifier +@param {string} moduleName +*/ +const isAssertFunction = (specifier, moduleName) => + // `import assert from 'node:assert';` + // `import assert from 'node:assert/strict';` + specifier.type === 'ImportDefaultSpecifier' + // `import {default as assert} from 'node:assert';` + // `import {default as assert} from 'node:assert/strict';` + || ( + specifier.type === 'ImportSpecifier' + && specifier.imported.name === 'default' + ) + // `import {strict as assert} from 'node:assert';` + || ( + moduleName === 'assert' + && specifier.type === 'ImportSpecifier' + && specifier.imported.name === 'strict' + ); + +const NODE_PROTOCOL = 'node:'; + +/** @type {import('eslint').Rule.RuleModule['create']} */ +const create = context => ({ + * ImportDeclaration(importDeclaration) { + if (!isValueImport(importDeclaration)) { + return; + } + + let moduleName = importDeclaration.source.value; + + if (moduleName.startsWith(NODE_PROTOCOL)) { + moduleName = moduleName.slice(NODE_PROTOCOL.length); + } + + if (moduleName !== 'assert' && moduleName !== 'assert/strict') { + return; + } + + for (const specifier of importDeclaration.specifiers) { + if (!isValueImport(specifier) || !isAssertFunction(specifier, moduleName)) { + continue; + } + + const variables = context.sourceCode.getDeclaredVariables(specifier); + + /* c8 ignore next 3 */ + if (!Array.isArray(variables) && variables.length === 1) { + continue; + } + + const [variable] = variables; + + for (const {identifier} of variable.references) { + if (!(identifier.parent.type === 'CallExpression' && identifier.parent.callee === identifier)) { + continue; + } + + yield { + node: identifier, + messageId: MESSAGE_ID_ERROR, + data: {name: identifier.name}, + /** @param {import('eslint').Rule.RuleFixer} fixer */ + fix: fixer => fixer.insertTextAfter(identifier, '.ok'), + }; + } + } + }, +}); + +/** @type {import('eslint').Rule.RuleModule} */ +const config = { + create, + meta: { + type: 'problem', + docs: { + description: 'Enforce consistent assertion style with `node:assert`.', + recommended: true, + }, + fixable: 'code', + messages, + }, +}; + +export default config; diff --git a/rules/index.js b/rules/index.js index 2b511e0d41..e9715b326a 100644 --- a/rules/index.js +++ b/rules/index.js @@ -3,6 +3,7 @@ import {createRule} from './utils/rule.js'; import betterRegex from './better-regex.js'; import catchErrorName from './catch-error-name.js'; +import consistentAssert from './consistent-assert.js'; import consistentDestructuring from './consistent-destructuring.js'; import consistentEmptyArraySpread from './consistent-empty-array-spread.js'; import consistentExistenceIndexCheck from './consistent-existence-index-check.js'; @@ -128,6 +129,7 @@ import throwNewError from './throw-new-error.js'; const rules = { 'better-regex': createRule(betterRegex, 'better-regex'), 'catch-error-name': createRule(catchErrorName, 'catch-error-name'), + 'consistent-assert': createRule(consistentAssert, 'consistent-assert'), 'consistent-destructuring': createRule(consistentDestructuring, 'consistent-destructuring'), 'consistent-empty-array-spread': createRule(consistentEmptyArraySpread, 'consistent-empty-array-spread'), 'consistent-existence-index-check': createRule(consistentExistenceIndexCheck, 'consistent-existence-index-check'), diff --git a/test/consistent-assert.js b/test/consistent-assert.js new file mode 100644 index 0000000000..fb3d1176b0 --- /dev/null +++ b/test/consistent-assert.js @@ -0,0 +1,138 @@ +import outdent from 'outdent'; +import {getTester, parsers} from './utils/test.js'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + 'assert(foo)', + 'import assert from "assert";', + // Import but not invoke + outdent` + import assert from 'node:assert'; + assert; + `, + outdent` + import customAssert from 'node:assert'; + assert(foo); + `, + outdent` + function foo (assert) { + assert(bar); + } + `, + outdent` + import assert from 'node:assert'; + + function foo (assert) { + assert(bar); + } + `, + // Invalid named import + outdent` + import {strict} from 'node:assert/strict'; + + strict(foo); + `, + outdent` + import * as assert from 'node:assert'; + assert(foo); + `, + outdent` + export * as assert from 'node:assert'; + assert(foo); + `, + outdent` + export {default as assert} from 'node:assert'; + export {assert as strict} from 'node:assert'; + assert(foo); + `, + outdent` + import assert from 'node:assert/strict'; + console.log(assert) + `, + ...[ + 'import type assert from "node:assert/strict";', + 'import {type strict as assert} from "node:assert/strict";', + 'import type {strict as assert} from "node:assert/strict";', + ].flatMap(code => [code, `${code}\nassert();`]).map(code => ({code, languageOptions: {parser: parsers.typescript}})), + ], + invalid: [ + // Default import + outdent` + import assert from 'assert'; + assert(foo) + `, + outdent` + import assert from 'node:assert'; + assert(foo) + `, + outdent` + import assert from 'assert/strict'; + assert(foo) + `, + outdent` + import assert from 'node:assert/strict'; + assert(foo) + `, + outdent` + import customAssert from 'assert'; + customAssert(foo) + `, + outdent` + import customAssert from 'node:assert'; + customAssert(foo) + `, + // Multiple references + outdent` + import assert from 'assert'; + assert(foo) + assert(bar) + assert(baz) + `, + // Named import + outdent` + import {strict} from 'assert'; + strict(foo) + `, + // Named import with alias + outdent` + import {strict as assert} from 'assert'; + assert(foo) + `, + // All cases + outdent` + import a, {strict as b, default as c} from 'node:assert'; + import d, {strict as e, default as f} from 'assert'; + import g, {default as h} from 'node:assert/strict'; + import i, {default as j} from 'assert/strict'; + a(foo); + b(foo); + c(foo); + d(foo); + e(foo); + f(foo); + g(foo); + h(foo); + i(foo); + j(foo); + `, + // Optional call, not really matters + outdent` + import assert from 'node:assert'; + assert?.(foo) + `, + outdent` + import assert from 'assert'; + + (( + /* comment */ (( + /* comment */ + assert + /* comment */ + )) /* comment */ + (/* comment */ typeof foo === 'string', 'foo must be a string' /** after comment */) + )); + `, + ], +}); diff --git a/test/package.js b/test/package.js index 550f0a9e21..04b018bfd9 100644 --- a/test/package.js +++ b/test/package.js @@ -34,6 +34,7 @@ const RULES_WITHOUT_PASS_FAIL_SECTIONS = new Set([ 'consistent-existence-index-check', 'prefer-global-this', 'no-instanceof-builtin-object', + 'consistent-assert', ]); test('Every rule is defined in index file in alphabetical order', t => { diff --git a/test/snapshots/consistent-assert.js.md b/test/snapshots/consistent-assert.js.md new file mode 100644 index 0000000000..2152cbf624 --- /dev/null +++ b/test/snapshots/consistent-assert.js.md @@ -0,0 +1,559 @@ +# Snapshot report for `test/consistent-assert.js` + +The actual snapshot is saved in `consistent-assert.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## invalid(1): import assert from 'assert'; assert(foo) + +> Input + + `␊ + 1 | import assert from 'assert';␊ + 2 | assert(foo)␊ + ` + +> Output + + `␊ + 1 | import assert from 'assert';␊ + 2 | assert.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import assert from 'assert';␊ + > 2 | assert(foo)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + ` + +## invalid(2): import assert from 'node:assert'; assert(foo) + +> Input + + `␊ + 1 | import assert from 'node:assert';␊ + 2 | assert(foo)␊ + ` + +> Output + + `␊ + 1 | import assert from 'node:assert';␊ + 2 | assert.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import assert from 'node:assert';␊ + > 2 | assert(foo)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + ` + +## invalid(3): import assert from 'assert/strict'; assert(foo) + +> Input + + `␊ + 1 | import assert from 'assert/strict';␊ + 2 | assert(foo)␊ + ` + +> Output + + `␊ + 1 | import assert from 'assert/strict';␊ + 2 | assert.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import assert from 'assert/strict';␊ + > 2 | assert(foo)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + ` + +## invalid(4): import assert from 'node:assert/strict'; assert(foo) + +> Input + + `␊ + 1 | import assert from 'node:assert/strict';␊ + 2 | assert(foo)␊ + ` + +> Output + + `␊ + 1 | import assert from 'node:assert/strict';␊ + 2 | assert.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import assert from 'node:assert/strict';␊ + > 2 | assert(foo)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + ` + +## invalid(5): import customAssert from 'assert'; customAssert(foo) + +> Input + + `␊ + 1 | import customAssert from 'assert';␊ + 2 | customAssert(foo)␊ + ` + +> Output + + `␊ + 1 | import customAssert from 'assert';␊ + 2 | customAssert.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import customAssert from 'assert';␊ + > 2 | customAssert(foo)␊ + | ^^^^^^^^^^^^ Prefer \`customAssert.ok(…)\` over \`customAssert(…)\`.␊ + ` + +## invalid(6): import customAssert from 'node:assert'; customAssert(foo) + +> Input + + `␊ + 1 | import customAssert from 'node:assert';␊ + 2 | customAssert(foo)␊ + ` + +> Output + + `␊ + 1 | import customAssert from 'node:assert';␊ + 2 | customAssert.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import customAssert from 'node:assert';␊ + > 2 | customAssert(foo)␊ + | ^^^^^^^^^^^^ Prefer \`customAssert.ok(…)\` over \`customAssert(…)\`.␊ + ` + +## invalid(7): import assert from 'assert'; assert(foo) assert(bar) assert(baz) + +> Input + + `␊ + 1 | import assert from 'assert';␊ + 2 | assert(foo)␊ + 3 | assert(bar)␊ + 4 | assert(baz)␊ + ` + +> Output + + `␊ + 1 | import assert from 'assert';␊ + 2 | assert.ok(foo)␊ + 3 | assert.ok(bar)␊ + 4 | assert.ok(baz)␊ + ` + +> Error 1/3 + + `␊ + 1 | import assert from 'assert';␊ + > 2 | assert(foo)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + 3 | assert(bar)␊ + 4 | assert(baz)␊ + ` + +> Error 2/3 + + `␊ + 1 | import assert from 'assert';␊ + 2 | assert(foo)␊ + > 3 | assert(bar)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + 4 | assert(baz)␊ + ` + +> Error 3/3 + + `␊ + 1 | import assert from 'assert';␊ + 2 | assert(foo)␊ + 3 | assert(bar)␊ + > 4 | assert(baz)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + ` + +## invalid(8): import {strict} from 'assert'; strict(foo) + +> Input + + `␊ + 1 | import {strict} from 'assert';␊ + 2 | strict(foo)␊ + ` + +> Output + + `␊ + 1 | import {strict} from 'assert';␊ + 2 | strict.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import {strict} from 'assert';␊ + > 2 | strict(foo)␊ + | ^^^^^^ Prefer \`strict.ok(…)\` over \`strict(…)\`.␊ + ` + +## invalid(9): import {strict as assert} from 'assert'; assert(foo) + +> Input + + `␊ + 1 | import {strict as assert} from 'assert';␊ + 2 | assert(foo)␊ + ` + +> Output + + `␊ + 1 | import {strict as assert} from 'assert';␊ + 2 | assert.ok(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import {strict as assert} from 'assert';␊ + > 2 | assert(foo)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + ` + +## invalid(10): import a, {strict as b, default as c} from 'node:assert'; import d, {strict as e, default as f} from 'assert'; import g, {default as h} from 'node:assert/strict'; import i, {default as j} from 'assert/strict'; a(foo); b(foo); c(foo); d(foo); e(foo); f(foo); g(foo); h(foo); i(foo); j(foo); + +> Input + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Output + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a.ok(foo);␊ + 6 | b.ok(foo);␊ + 7 | c.ok(foo);␊ + 8 | d.ok(foo);␊ + 9 | e.ok(foo);␊ + 10 | f.ok(foo);␊ + 11 | g.ok(foo);␊ + 12 | h.ok(foo);␊ + 13 | i.ok(foo);␊ + 14 | j.ok(foo);␊ + ` + +> Error 1/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + > 5 | a(foo);␊ + | ^ Prefer \`a.ok(…)\` over \`a(…)\`.␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 2/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + > 6 | b(foo);␊ + | ^ Prefer \`b.ok(…)\` over \`b(…)\`.␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 3/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + > 7 | c(foo);␊ + | ^ Prefer \`c.ok(…)\` over \`c(…)\`.␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 4/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + > 8 | d(foo);␊ + | ^ Prefer \`d.ok(…)\` over \`d(…)\`.␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 5/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + > 9 | e(foo);␊ + | ^ Prefer \`e.ok(…)\` over \`e(…)\`.␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 6/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + > 10 | f(foo);␊ + | ^ Prefer \`f.ok(…)\` over \`f(…)\`.␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 7/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + > 11 | g(foo);␊ + | ^ Prefer \`g.ok(…)\` over \`g(…)\`.␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 8/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + > 12 | h(foo);␊ + | ^ Prefer \`h.ok(…)\` over \`h(…)\`.␊ + 13 | i(foo);␊ + 14 | j(foo);␊ + ` + +> Error 9/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + > 13 | i(foo);␊ + | ^ Prefer \`i.ok(…)\` over \`i(…)\`.␊ + 14 | j(foo);␊ + ` + +> Error 10/10 + + `␊ + 1 | import a, {strict as b, default as c} from 'node:assert';␊ + 2 | import d, {strict as e, default as f} from 'assert';␊ + 3 | import g, {default as h} from 'node:assert/strict';␊ + 4 | import i, {default as j} from 'assert/strict';␊ + 5 | a(foo);␊ + 6 | b(foo);␊ + 7 | c(foo);␊ + 8 | d(foo);␊ + 9 | e(foo);␊ + 10 | f(foo);␊ + 11 | g(foo);␊ + 12 | h(foo);␊ + 13 | i(foo);␊ + > 14 | j(foo);␊ + | ^ Prefer \`j.ok(…)\` over \`j(…)\`.␊ + ` + +## invalid(11): import assert from 'node:assert'; assert?.(foo) + +> Input + + `␊ + 1 | import assert from 'node:assert';␊ + 2 | assert?.(foo)␊ + ` + +> Output + + `␊ + 1 | import assert from 'node:assert';␊ + 2 | assert.ok?.(foo)␊ + ` + +> Error 1/1 + + `␊ + 1 | import assert from 'node:assert';␊ + > 2 | assert?.(foo)␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + ` + +## invalid(12): import assert from 'assert'; (( /* comment */ (( /* comment */ assert /* comment */ )) /* comment */ (/* comment */ typeof foo === 'string', 'foo must be a string' /** after comment */) )); + +> Input + + `␊ + 1 | import assert from 'assert';␊ + 2 |␊ + 3 | ((␊ + 4 | /* comment */ ((␊ + 5 | /* comment */␊ + 6 | assert␊ + 7 | /* comment */␊ + 8 | )) /* comment */␊ + 9 | (/* comment */ typeof foo === 'string', 'foo must be a string' /** after comment */)␊ + 10 | ));␊ + ` + +> Output + + `␊ + 1 | import assert from 'assert';␊ + 2 |␊ + 3 | ((␊ + 4 | /* comment */ ((␊ + 5 | /* comment */␊ + 6 | assert.ok␊ + 7 | /* comment */␊ + 8 | )) /* comment */␊ + 9 | (/* comment */ typeof foo === 'string', 'foo must be a string' /** after comment */)␊ + 10 | ));␊ + ` + +> Error 1/1 + + `␊ + 1 | import assert from 'assert';␊ + 2 |␊ + 3 | ((␊ + 4 | /* comment */ ((␊ + 5 | /* comment */␊ + > 6 | assert␊ + | ^^^^^^ Prefer \`assert.ok(…)\` over \`assert(…)\`.␊ + 7 | /* comment */␊ + 8 | )) /* comment */␊ + 9 | (/* comment */ typeof foo === 'string', 'foo must be a string' /** after comment */)␊ + 10 | ));␊ + ` diff --git a/test/snapshots/consistent-assert.js.snap b/test/snapshots/consistent-assert.js.snap new file mode 100644 index 0000000000..63fd773eb1 Binary files /dev/null and b/test/snapshots/consistent-assert.js.snap differ