From c035216f1ed6e3e82b985e057d06bd0dabab0513 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Fri, 9 Feb 2024 19:01:12 +0800 Subject: [PATCH] Add `no-anonymous-default-export` rule (#2273) --- configs/recommended.js | 1 + docs/rules/no-anonymous-default-export.md | 64 + package.json | 3 +- readme.md | 1 + rules/no-anonymous-default-export.js | 212 +++ rules/utils/avoid-capture.js | 3 +- rules/utils/cartesian-product-samples.js | 2 +- rules/utils/escape-string.js | 2 +- rules/utils/escape-template-element-raw.js | 3 +- rules/utils/get-documentation-url.js | 2 +- rules/utils/get-variable-identifiers.js | 3 +- rules/utils/has-same-range.js | 3 +- rules/utils/is-object-method.js | 2 +- rules/utils/is-value-not-usable.js | 3 +- rules/utils/resolve-variable-name.js | 2 +- scripts/internal-rules/fix-snapshot-test.js | 2 +- test/no-anonymous-default-export.mjs | 320 ++++ .../no-anonymous-default-export.mjs.md | 1435 +++++++++++++++++ .../no-anonymous-default-export.mjs.snap | Bin 0 -> 2613 bytes 19 files changed, 2051 insertions(+), 12 deletions(-) create mode 100644 docs/rules/no-anonymous-default-export.md create mode 100644 rules/no-anonymous-default-export.js create mode 100644 test/no-anonymous-default-export.mjs create mode 100644 test/snapshots/no-anonymous-default-export.mjs.md create mode 100644 test/snapshots/no-anonymous-default-export.mjs.snap diff --git a/configs/recommended.js b/configs/recommended.js index a807c50b02..67f99a8472 100644 --- a/configs/recommended.js +++ b/configs/recommended.js @@ -14,6 +14,7 @@ module.exports = { 'unicorn/import-style': 'error', 'unicorn/new-for-builtins': 'error', 'unicorn/no-abusive-eslint-disable': 'error', + 'unicorn/no-anonymous-default-export': 'error', 'unicorn/no-array-callback-reference': 'error', 'unicorn/no-array-for-each': 'error', 'unicorn/no-array-method-this-argument': 'error', diff --git a/docs/rules/no-anonymous-default-export.md b/docs/rules/no-anonymous-default-export.md new file mode 100644 index 0000000000..8ac3c117fe --- /dev/null +++ b/docs/rules/no-anonymous-default-export.md @@ -0,0 +1,64 @@ +# Disallow anonymous functions and classes as the default export + +πŸ’Ό This rule is enabled in the βœ… `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). + +πŸ’‘ This rule is manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). + + + + +Naming default exports improves codebase searchability by ensuring consistent identifier use for a module's default export, both where it's declared and where it's imported. + +## Fail + +```js +export default class {} +``` + +```js +export default function () {} +``` + +```js +export default () => {}; +``` + +```js +module.exports = class {}; +``` + +```js +module.exports = function () {}; +``` + +```js +module.exports = () => {}; +``` + +## Pass + +```js +export default class Foo {} +``` + +```js +export default function foo () {} +``` + +```js +const foo = () => {}; +export default foo; +``` + +```js +module.exports = class Foo {}; +``` + +```js +module.exports = function foo () {}; +``` + +```js +const foo = () => {}; +module.exports = foo; +``` diff --git a/package.json b/package.json index ca9b8fd293..46e0f0aa7f 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,8 @@ ] } ], - "import/order": "off" + "import/order": "off", + "func-names": "off" }, "overrides": [ { diff --git a/readme.md b/readme.md index 506f43f92f..47c31feef5 100644 --- a/readme.md +++ b/readme.md @@ -124,6 +124,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c | [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | βœ… | | | | [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | βœ… | πŸ”§ | | | [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | βœ… | | | +| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | βœ… | | πŸ’‘ | | [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | βœ… | | πŸ’‘ | | [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | βœ… | πŸ”§ | πŸ’‘ | | [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | βœ… | πŸ”§ | πŸ’‘ | diff --git a/rules/no-anonymous-default-export.js b/rules/no-anonymous-default-export.js new file mode 100644 index 0000000000..f520801af5 --- /dev/null +++ b/rules/no-anonymous-default-export.js @@ -0,0 +1,212 @@ +'use strict'; + +const path = require('node:path'); +const { + getFunctionHeadLocation, + getFunctionNameWithKind, + isOpeningParenToken, +} = require('@eslint-community/eslint-utils'); +const { + isIdentifierName, +} = require('@babel/helper-validator-identifier'); +const getClassHeadLocation = require('./utils/get-class-head-location.js'); +const {upperFirst, camelCase} = require('./utils/lodash.js'); +const {getParenthesizedRange} = require('./utils/parentheses.js'); +const { + getScopes, + avoidCapture, +} = require('./utils/index.js'); +const {isMemberExpression} = require('./ast/index.js'); + +const MESSAGE_ID_ERROR = 'no-anonymous-default-export/error'; +const MESSAGE_ID_SUGGESTION = 'no-anonymous-default-export/suggestion'; +const messages = { + [MESSAGE_ID_ERROR]: 'The {{description}} should be named.', + [MESSAGE_ID_SUGGESTION]: 'Name it as `{{name}}`.', +}; + +const isClassKeywordToken = token => token.type === 'Keyword' && token.value === 'class'; +const isAnonymousClassOrFunction = node => + ( + ( + node.type === 'FunctionDeclaration' + || node.type === 'FunctionExpression' + || node.type === 'ClassDeclaration' + || node.type === 'ClassExpression' + ) + && !node.id + ) + || node.type === 'ArrowFunctionExpression'; + +function getSuggestionName(node, filename, sourceCode) { + if (filename === '' || filename === '') { + return; + } + + let [name] = path.basename(filename).split('.'); + name = camelCase(name); + + if (!isIdentifierName(name)) { + return; + } + + name = node.type === 'ClassDeclaration' ? upperFirst(name) : name; + name = avoidCapture(name, getScopes(sourceCode.getScope(node))); + + return name; +} + +function addName(fixer, node, name, sourceCode) { + switch (node.type) { + case 'ClassDeclaration': + case 'ClassExpression': { + const lastDecorator = node.decorators?.at(-1); + const classToken = lastDecorator + ? sourceCode.getTokenAfter(lastDecorator, isClassKeywordToken) + : sourceCode.getFirstToken(node, isClassKeywordToken); + return fixer.insertTextAfter(classToken, ` ${name}`); + } + + case 'FunctionDeclaration': + case 'FunctionExpression': { + const openingParenthesisToken = sourceCode.getFirstToken( + node, + isOpeningParenToken, + ); + return fixer.insertTextBefore( + openingParenthesisToken, + `${sourceCode.text.charAt(openingParenthesisToken.range[0] - 1) === ' ' ? '' : ' '}${name} `, + ); + } + + case 'ArrowFunctionExpression': { + const [exportDeclarationStart, exportDeclarationEnd] + = node.parent.type === 'ExportDefaultDeclaration' + ? node.parent.range + : node.parent.parent.range; + const [arrowFunctionStart, arrowFunctionEnd] = getParenthesizedRange(node, sourceCode); + + let textBefore = sourceCode.text.slice(exportDeclarationStart, arrowFunctionStart); + let textAfter = sourceCode.text.slice(arrowFunctionEnd, exportDeclarationEnd); + + textBefore = `\n${textBefore}`; + if (!/\s$/.test(textBefore)) { + textBefore = `${textBefore} `; + } + + if (!textAfter.endsWith(';')) { + textAfter = `${textAfter};`; + } + + return [ + fixer.replaceTextRange( + [exportDeclarationStart, arrowFunctionStart], + `const ${name} = `, + ), + fixer.replaceTextRange( + [arrowFunctionEnd, exportDeclarationEnd], + ';', + ), + fixer.insertTextAfterRange( + [exportDeclarationEnd, exportDeclarationEnd], + `${textBefore}${name}${textAfter}`, + ), + ]; + } + + // No default + } +} + +function getProblem(node, context) { + const {sourceCode, physicalFilename} = context; + + const suggestionName = getSuggestionName(node, physicalFilename, sourceCode); + + let loc; + let description; + if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') { + loc = getClassHeadLocation(node, sourceCode); + description = 'class'; + } else { + loc = getFunctionHeadLocation(node, sourceCode); + // [TODO: @fisker]: Ask `@eslint-community/eslint-utils` to expose `getFunctionKind` + const nameWithKind = getFunctionNameWithKind(node); + description = nameWithKind.replace(/ '.*?'$/, ''); + } + + const problem = { + node, + loc, + messageId: MESSAGE_ID_ERROR, + data: { + description, + }, + }; + + if (!suggestionName) { + return problem; + } + + problem.suggest = [ + { + messageId: MESSAGE_ID_SUGGESTION, + data: { + name: suggestionName, + }, + fix: fixer => addName(fixer, node, suggestionName, sourceCode), + }, + ]; + + return problem; +} + +/** @param {import('eslint').Rule.RuleContext} context */ +const create = context => { + context.on('ExportDefaultDeclaration', node => { + if (!isAnonymousClassOrFunction(node.declaration)) { + return; + } + + return getProblem(node.declaration, context); + }); + + context.on('AssignmentExpression', node => { + if ( + !isAnonymousClassOrFunction(node.right) + || !( + node.parent.type === 'ExpressionStatement' + && node.parent.expression === node + ) + || !( + isMemberExpression(node.left, { + object: 'module', + property: 'exports', + computed: false, + optional: false, + }) + || ( + node.left.type === 'Identifier', + node.left.name === 'exports' + ) + ) + ) { + return; + } + + return getProblem(node.right, context); + }); +}; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + create, + meta: { + type: 'suggestion', + docs: { + description: 'Disallow anonymous functions and classes as the default export.', + }, + hasSuggestions: true, + messages, + }, +}; diff --git a/rules/utils/avoid-capture.js b/rules/utils/avoid-capture.js index 9a1f9faa42..1de17b16c1 100644 --- a/rules/utils/avoid-capture.js +++ b/rules/utils/avoid-capture.js @@ -129,7 +129,7 @@ Useful when you want to rename a variable (or create a new variable) while being @param {isSafe} [isSafe] - Rule-specific name check function. @returns {string} - Either `name` as is, or a string like `${name}_` suffixed with underscores to make the name unique. */ -module.exports = (name, scopes, isSafe = alwaysTrue) => { +module.exports = function avoidCapture(name, scopes, isSafe = alwaysTrue) { if (!isValidIdentifier(name)) { name += '_'; @@ -144,3 +144,4 @@ module.exports = (name, scopes, isSafe = alwaysTrue) => { return name; }; + diff --git a/rules/utils/cartesian-product-samples.js b/rules/utils/cartesian-product-samples.js index 726b37ec87..e20926b265 100644 --- a/rules/utils/cartesian-product-samples.js +++ b/rules/utils/cartesian-product-samples.js @@ -1,6 +1,6 @@ 'use strict'; -module.exports = (combinations, length = Number.POSITIVE_INFINITY) => { +module.exports = function cartesianProductSamples(combinations, length = Number.POSITIVE_INFINITY) { const total = combinations.reduce((total, {length}) => total * length, 1); const samples = Array.from({length: Math.min(total, length)}, (_, sampleIndex) => { diff --git a/rules/utils/escape-string.js b/rules/utils/escape-string.js index be0ffc85ec..06c4ff04bb 100644 --- a/rules/utils/escape-string.js +++ b/rules/utils/escape-string.js @@ -9,7 +9,7 @@ Escape string and wrap the result in quotes. @param {string} [quote] - The quote character. @returns {string} - The quoted and escaped string. */ -module.exports = (string, quote = '\'') => { +module.exports = function escapeString(string, quote = '\'') { /* c8 ignore start */ if (typeof string !== 'string') { throw new TypeError('Unexpected string.'); diff --git a/rules/utils/escape-template-element-raw.js b/rules/utils/escape-template-element-raw.js index 1fdcbf7e27..14bc08c40a 100644 --- a/rules/utils/escape-template-element-raw.js +++ b/rules/utils/escape-template-element-raw.js @@ -1,6 +1,7 @@ 'use strict'; -module.exports = string => string.replaceAll( +const escapeTemplateElementRaw = string => string.replaceAll( /(?<=(?:^|[^\\])(?:\\\\)*)(?(?:`|\$(?={)))/g, '\\$', ); +module.exports = escapeTemplateElementRaw; diff --git a/rules/utils/get-documentation-url.js b/rules/utils/get-documentation-url.js index 3128369df3..0b1c9738f7 100644 --- a/rules/utils/get-documentation-url.js +++ b/rules/utils/get-documentation-url.js @@ -4,7 +4,7 @@ const packageJson = require('../../package.json'); const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn'; -module.exports = filename => { +module.exports = function getDocumentationUrl(filename) { const ruleName = path.basename(filename, '.js'); return `${repoUrl}/blob/v${packageJson.version}/docs/rules/${ruleName}.md`; }; diff --git a/rules/utils/get-variable-identifiers.js b/rules/utils/get-variable-identifiers.js index 5a2617655d..816d5e6b40 100644 --- a/rules/utils/get-variable-identifiers.js +++ b/rules/utils/get-variable-identifiers.js @@ -1,7 +1,8 @@ 'use strict'; // Get identifiers of given variable -module.exports = ({identifiers, references}) => [...new Set([ +const getVariableIdentifiers = ({identifiers, references}) => [...new Set([ ...identifiers, ...references.map(({identifier}) => identifier), ])]; +module.exports = getVariableIdentifiers; diff --git a/rules/utils/has-same-range.js b/rules/utils/has-same-range.js index 07227b18e2..7018ffc159 100644 --- a/rules/utils/has-same-range.js +++ b/rules/utils/has-same-range.js @@ -1,7 +1,8 @@ 'use strict'; -module.exports = (node1, node2) => +const hasSameRange = (node1, node2) => node1 && node2 && node1.range[0] === node2.range[0] && node1.range[1] === node2.range[1]; +module.exports = hasSameRange; diff --git a/rules/utils/is-object-method.js b/rules/utils/is-object-method.js index c82184f277..f4df81a2dc 100644 --- a/rules/utils/is-object-method.js +++ b/rules/utils/is-object-method.js @@ -1,5 +1,5 @@ 'use strict'; -module.exports = (node, object, method) => { +module.exports = function isObjectMethod(node, object, method) { const {callee} = node; return ( callee.type === 'MemberExpression' diff --git a/rules/utils/is-value-not-usable.js b/rules/utils/is-value-not-usable.js index a838ffd926..88c5df827f 100644 --- a/rules/utils/is-value-not-usable.js +++ b/rules/utils/is-value-not-usable.js @@ -2,4 +2,5 @@ const {isExpressionStatement} = require('../ast/index.js'); -module.exports = node => isExpressionStatement(node.parent); +const isValueNotUsable = node => isExpressionStatement(node.parent); +module.exports = isValueNotUsable; diff --git a/rules/utils/resolve-variable-name.js b/rules/utils/resolve-variable-name.js index 09784128ff..f5b50d126a 100644 --- a/rules/utils/resolve-variable-name.js +++ b/rules/utils/resolve-variable-name.js @@ -7,7 +7,7 @@ Finds a variable named `name` in the scope `scope` (or it's parents). @param {Scope} scope - The scope to look for the variable in. @returns {Variable?} - The found variable, if any. */ -module.exports = (name, scope) => { +module.exports = function resolveVariableName(name, scope) { while (scope) { const variable = scope.set.get(name); diff --git a/scripts/internal-rules/fix-snapshot-test.js b/scripts/internal-rules/fix-snapshot-test.js index 1699b0719a..9e206494f0 100644 --- a/scripts/internal-rules/fix-snapshot-test.js +++ b/scripts/internal-rules/fix-snapshot-test.js @@ -101,7 +101,7 @@ function checkInvalidCases(node, context) { } for (const propertyNode of testCaseNode.properties) { - if (propertyNode.computed || propertyNode.key.type !== 'Identifier') { + if (propertyNode.type !== 'Property' || propertyNode.computed || propertyNode.key.type !== 'Identifier') { continue; } diff --git a/test/no-anonymous-default-export.mjs b/test/no-anonymous-default-export.mjs new file mode 100644 index 0000000000..c9be26d50d --- /dev/null +++ b/test/no-anonymous-default-export.mjs @@ -0,0 +1,320 @@ +import outdent from 'outdent'; +import {getTester, parsers} from './utils/test.mjs'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + 'export default function named() {}', + 'export default class named {}', + 'export default []', + 'export default {}', + 'export default 1', + 'export default false', + 'export default 0n', + 'notExports = class {}', + 'notModule.exports = class {}', + 'module.notExports = class {}', + 'module.exports.foo = class {}', + 'alert(exports = class {})', + 'foo = module.exports = class {}', + ], + invalid: [ + 'export default function () {}', + 'export default class {}', + 'export default () => {}', + 'export default function * () {}', + 'export default async function () {}', + 'export default async function * () {}', + 'export default async () => {}', + + // `ClassDeclaration` + { + code: 'export default class {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default class extends class {} {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default class{}', + filename: '/path/to/foo.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo-bar.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo_bar.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo+bar.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo+bar123.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo*.js', + }, + { + code: 'export default class {}', + filename: '/path/to/[foo].js', + }, + { + code: 'export default class {}', + filename: '/path/to/class.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo.helper.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo.bar.js', + }, + { + code: 'export default class {}', + filename: '/path/to/foo.test.js', + }, + { + code: 'export default class {}', + filename: '/path/to/.foo.js', + }, + { + code: outdent` + let Foo, Foo_, foo, foo_ + export default class {} + `, + filename: '/path/to/foo.js', + }, + + // `ClassExpression` + { + code: outdent` + let Foo, Foo_, foo, foo_ + export default (class{}) + `, + filename: '/path/to/foo.js', + }, + { + code: 'export default (class extends class {} {})', + filename: '/path/to/foo.js', + }, + { + code: outdent` + let Exports, Exports_, exports, exports_ + exports = class {} + `, + filename: '/path/to/exports.js', + }, + { + code: 'module.exports = class {}', + filename: '/path/to/module.js', + }, + + // `FunctionDeclaration` + { + code: 'export default function () {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default function* () {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default async function* () {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default async function*() {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default async function *() {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default async function * () {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default async function * /* comment */ () {}', + filename: '/path/to/foo.js', + }, + { + code: outdent` + export default async function * // comment + () {} + `, + filename: '/path/to/foo.js', + }, + { + code: outdent` + let Foo, Foo_, foo, foo_ + export default async function * () {} + `, + filename: '/path/to/foo.js', + }, + + // `FunctionExpression` + { + code: outdent` + let Foo, Foo_, foo, foo_ + export default (async function * () {}) + `, + filename: '/path/to/foo.js', + }, + { + code: outdent` + let Exports, Exports_, exports, exports_ + exports = function() {} + `, + filename: '/path/to/exports.js', + }, + { + code: 'module.exports = function() {}', + filename: '/path/to/module.js', + }, + + // `ArrowFunctionExpression` + { + code: 'export default () => {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default async () => {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default () => {};', + filename: '/path/to/foo.js', + }, + { + code: 'export default() => {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default foo => {}', + filename: '/path/to/foo.js', + }, + { + code: 'export default (( () => {} ))', + filename: '/path/to/foo.js', + }, + { + code: '/* comment 1 */ export /* comment 2 */ default /* comment 3 */ () => {}', + filename: '/path/to/foo.js', + }, + { + code: outdent` + // comment 1 + export + // comment 2 + default + // comment 3 + () => {} + `, + filename: '/path/to/foo.js', + }, + { + code: outdent` + let Foo, Foo_, foo, foo_ + export default async () => {} + `, + filename: '/path/to/foo.js', + }, + { + code: outdent` + let Exports, Exports_, exports, exports_ + exports = (( () => {} )) + `, + filename: '/path/to/exports.js', + }, + { + code: outdent` + // comment 1 + module + // comment 2 + .exports + // comment 3 + = + // comment 4 + () => {}; + `, + filename: '/path/to/module.js', + }, + { + code: '(( exports = (( () => {} )) ))', + filename: '/path/to/foo.js', + }, + { + code: '(( module.exports = (( () => {} )) ))', + filename: '/path/to/foo.js', + }, + { + code: '(( exports = (( () => {} )) ));', + filename: '/path/to/foo.js', + }, + { + code: '(( module.exports = (( () => {} )) ));', + filename: '/path/to/foo.js', + }, + ], +}); + +// Decorators +const decoratorsBeforeExportOptions = { + parser: parsers.babel, + parserOptions: { + babelOptions: { + parserOpts: { + plugins: [ + ['decorators', {decoratorsBeforeExport: true}], + ], + }, + }, + }, +}; +const decoratorsAfterExportOptions = { + parser: parsers.babel, + parserOptions: { + babelOptions: { + parserOpts: { + plugins: [ + ['decorators', {decoratorsBeforeExport: false}], + ], + }, + }, + }, +}; +test.snapshot({ + valid: [], + invalid: [ + { + code: '@decorator export default class {}', + filename: '/path/to/foo.js', + ...decoratorsBeforeExportOptions, + }, + { + code: 'export default @decorator(class {}) class extends class {} {}', + filename: '/path/to/foo.js', + ...decoratorsAfterExportOptions, + }, + { + code: 'module.exports = @decorator(class {}) class extends class {} {}', + filename: '/path/to/foo.js', + ...decoratorsAfterExportOptions, + }, + { + code: '@decorator @decorator(class {}) export default class {}', + filename: '/path/to/foo.js', + ...decoratorsBeforeExportOptions, + }, + ], +}); + diff --git a/test/snapshots/no-anonymous-default-export.mjs.md b/test/snapshots/no-anonymous-default-export.mjs.md new file mode 100644 index 0000000000..d016aec97d --- /dev/null +++ b/test/snapshots/no-anonymous-default-export.mjs.md @@ -0,0 +1,1435 @@ +# Snapshot report for `test/no-anonymous-default-export.mjs` + +The actual snapshot is saved in `no-anonymous-default-export.mjs.snap`. + +Generated by [AVA](https://avajs.dev). + +## invalid(1): export default function () {} + +> Input + + `␊ + 1 | export default function () {}␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default function () {}␊ + | ^^^^^^^^^ The function should be named.␊ + ` + +## invalid(2): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ` + +## invalid(3): export default () => {} + +> Input + + `␊ + 1 | export default () => {}␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default () => {}␊ + | ^^ The arrow function should be named.␊ + ` + +## invalid(4): export default function * () {} + +> Input + + `␊ + 1 | export default function * () {}␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default function * () {}␊ + | ^^^^^^^^^^^ The generator function should be named.␊ + ` + +## invalid(5): export default async function () {} + +> Input + + `␊ + 1 | export default async function () {}␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function () {}␊ + | ^^^^^^^^^^^^^^^ The async function should be named.␊ + ` + +## invalid(6): export default async function * () {} + +> Input + + `␊ + 1 | export default async function * () {}␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function * () {}␊ + | ^^^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ` + +## invalid(7): export default async () => {} + +> Input + + `␊ + 1 | export default async () => {}␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async () => {}␊ + | ^^ The async arrow function should be named.␊ + ` + +## invalid(8): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo {}␊ + ` + +## invalid(9): export default class extends class {} {} + +> Input + + `␊ + 1 | export default class extends class {} {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class extends class {} {}␊ + | ^^^^^^^^^^^^^^^^^^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo extends class {} {}␊ + ` + +## invalid(10): export default class{} + +> Input + + `␊ + 1 | export default class{}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class{}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo{}␊ + ` + +## invalid(11): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo-bar.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`FooBar\`.␊ + 1 | export default class FooBar {}␊ + ` + +## invalid(12): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo_bar.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`FooBar\`.␊ + 1 | export default class FooBar {}␊ + ` + +## invalid(13): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo+bar.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`FooBar\`.␊ + 1 | export default class FooBar {}␊ + ` + +## invalid(14): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo+bar123.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`FooBar123\`.␊ + 1 | export default class FooBar123 {}␊ + ` + +## invalid(15): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo*.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo {}␊ + ` + +## invalid(16): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/[foo].js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo {}␊ + ` + +## invalid(17): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/class.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Class\`.␊ + 1 | export default class Class {}␊ + ` + +## invalid(18): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo.helper.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo {}␊ + ` + +## invalid(19): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo.bar.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo {}␊ + ` + +## invalid(20): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo.test.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default class Foo {}␊ + ` + +## invalid(21): export default class {} + +> Input + + `␊ + 1 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/.foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ` + +## invalid(22): let Foo, Foo_, foo, foo_ export default class {} + +> Input + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + > 2 | export default class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo__\`.␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default class Foo__ {}␊ + ` + +## invalid(23): let Foo, Foo_, foo, foo_ export default (class{}) + +> Input + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default (class{})␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + > 2 | export default (class{})␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo__\`.␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default (class foo__{})␊ + ` + +## invalid(24): export default (class extends class {} {}) + +> Input + + `␊ + 1 | export default (class extends class {} {})␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default (class extends class {} {})␊ + | ^^^^^^^^^^^^^^^^^^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default (class foo extends class {} {})␊ + ` + +## invalid(25): let Exports, Exports_, exports, exports_ exports = class {} + +> Input + + `␊ + 1 | let Exports, Exports_, exports, exports_␊ + 2 | exports = class {}␊ + ` + +> Filename + + `␊ + /path/to/exports.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Exports, Exports_, exports, exports_␊ + > 2 | exports = class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`exports__\`.␊ + 1 | let Exports, Exports_, exports, exports_␊ + 2 | exports = class exports__ {}␊ + ` + +## invalid(26): module.exports = class {} + +> Input + + `␊ + 1 | module.exports = class {}␊ + ` + +> Filename + + `␊ + /path/to/module.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | module.exports = class {}␊ + | ^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`module_\`.␊ + 1 | module.exports = class module_ {}␊ + ` + +## invalid(27): export default function () {} + +> Input + + `␊ + 1 | export default function () {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default function () {}␊ + | ^^^^^^^^^ The function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default function foo () {}␊ + ` + +## invalid(28): export default function* () {} + +> Input + + `␊ + 1 | export default function* () {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default function* () {}␊ + | ^^^^^^^^^^ The generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default function* foo () {}␊ + ` + +## invalid(29): export default async function* () {} + +> Input + + `␊ + 1 | export default async function* () {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function* () {}␊ + | ^^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default async function* foo () {}␊ + ` + +## invalid(30): export default async function*() {} + +> Input + + `␊ + 1 | export default async function*() {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function*() {}␊ + | ^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default async function* foo () {}␊ + ` + +## invalid(31): export default async function *() {} + +> Input + + `␊ + 1 | export default async function *() {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function *() {}␊ + | ^^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default async function * foo () {}␊ + ` + +## invalid(32): export default async function * () {} + +> Input + + `␊ + 1 | export default async function * () {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function * () {}␊ + | ^^^^^^^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default async function * foo () {}␊ + ` + +## invalid(33): export default async function * /* comment */ () {} + +> Input + + `␊ + 1 | export default async function * /* comment */ () {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function * /* comment */ () {}␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default async function * /* comment */ foo () {}␊ + ` + +## invalid(34): export default async function * // comment () {} + +> Input + + `␊ + 1 | export default async function * // comment␊ + 2 | () {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async function * // comment␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 2 | () {}␊ + | ^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | export default async function * // comment␊ + 2 | foo () {}␊ + ` + +## invalid(35): let Foo, Foo_, foo, foo_ export default async function * () {} + +> Input + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default async function * () {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + > 2 | export default async function * () {}␊ + | ^^^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo__\`.␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default async function * foo__ () {}␊ + ` + +## invalid(36): let Foo, Foo_, foo, foo_ export default (async function * () {}) + +> Input + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default (async function * () {})␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + > 2 | export default (async function * () {})␊ + | ^^^^^^^^^^^^^^^^^ The async generator function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo__\`.␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default (async function * foo__ () {})␊ + ` + +## invalid(37): let Exports, Exports_, exports, exports_ exports = function() {} + +> Input + + `␊ + 1 | let Exports, Exports_, exports, exports_␊ + 2 | exports = function() {}␊ + ` + +> Filename + + `␊ + /path/to/exports.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Exports, Exports_, exports, exports_␊ + > 2 | exports = function() {}␊ + | ^^^^^^^^ The function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`exports__\`.␊ + 1 | let Exports, Exports_, exports, exports_␊ + 2 | exports = function exports__ () {}␊ + ` + +## invalid(38): module.exports = function() {} + +> Input + + `␊ + 1 | module.exports = function() {}␊ + ` + +> Filename + + `␊ + /path/to/module.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | module.exports = function() {}␊ + | ^^^^^^^^ The function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`module_\`.␊ + 1 | module.exports = function module_ () {}␊ + ` + +## invalid(39): export default () => {} + +> Input + + `␊ + 1 | export default () => {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default () => {}␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = () => {};␊ + 2 | export default foo;␊ + ` + +## invalid(40): export default async () => {} + +> Input + + `␊ + 1 | export default async () => {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default async () => {}␊ + | ^^ The async arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = async () => {};␊ + 2 | export default foo;␊ + ` + +## invalid(41): export default () => {}; + +> Input + + `␊ + 1 | export default () => {};␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default () => {};␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = () => {};␊ + 2 | export default foo;␊ + ` + +## invalid(42): export default() => {} + +> Input + + `␊ + 1 | export default() => {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default() => {}␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = () => {};␊ + 2 | export default foo;␊ + ` + +## invalid(43): export default foo => {} + +> Input + + `␊ + 1 | export default foo => {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default foo => {}␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo_\`.␊ + 1 | const foo_ = foo => {};␊ + 2 | export default foo_;␊ + ` + +## invalid(44): export default (( () => {} )) + +> Input + + `␊ + 1 | export default (( () => {} ))␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default (( () => {} ))␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = (( () => {} ));␊ + 2 | export default foo;␊ + ` + +## invalid(45): /* comment 1 */ export /* comment 2 */ default /* comment 3 */ () => {} + +> Input + + `␊ + 1 | /* comment 1 */ export /* comment 2 */ default /* comment 3 */ () => {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | /* comment 1 */ export /* comment 2 */ default /* comment 3 */ () => {}␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | /* comment 1 */ const foo = () => {};␊ + 2 | export /* comment 2 */ default /* comment 3 */ foo;␊ + ` + +## invalid(46): // comment 1 export // comment 2 default // comment 3 () => {} + +> Input + + `␊ + 1 | // comment 1␊ + 2 | export␊ + 3 | // comment 2␊ + 4 | default␊ + 5 | // comment 3␊ + 6 | () => {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + 1 | // comment 1␊ + 2 | export␊ + 3 | // comment 2␊ + 4 | default␊ + 5 | // comment 3␊ + > 6 | () => {}␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | // comment 1␊ + 2 | const foo = () => {};␊ + 3 | export␊ + 4 | // comment 2␊ + 5 | default␊ + 6 | // comment 3␊ + 7 | foo;␊ + ` + +## invalid(47): let Foo, Foo_, foo, foo_ export default async () => {} + +> Input + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | export default async () => {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Foo, Foo_, foo, foo_␊ + > 2 | export default async () => {}␊ + | ^^ The async arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo__\`.␊ + 1 | let Foo, Foo_, foo, foo_␊ + 2 | const foo__ = async () => {};␊ + 3 | export default foo__;␊ + ` + +## invalid(48): let Exports, Exports_, exports, exports_ exports = (( () => {} )) + +> Input + + `␊ + 1 | let Exports, Exports_, exports, exports_␊ + 2 | exports = (( () => {} ))␊ + ` + +> Filename + + `␊ + /path/to/exports.js␊ + ` + +> Error 1/1 + + `␊ + 1 | let Exports, Exports_, exports, exports_␊ + > 2 | exports = (( () => {} ))␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`exports__\`.␊ + 1 | let Exports, Exports_, exports, exports_␊ + 2 | const exports__ = (( () => {} ));␊ + 3 | exports = exports__;␊ + ` + +## invalid(49): // comment 1 module // comment 2 .exports // comment 3 = // comment 4 () => {}; + +> Input + + `␊ + 1 | // comment 1␊ + 2 | module␊ + 3 | // comment 2␊ + 4 | .exports␊ + 5 | // comment 3␊ + 6 | =␊ + 7 | // comment 4␊ + 8 | () => {};␊ + ` + +> Filename + + `␊ + /path/to/module.js␊ + ` + +> Error 1/1 + + `␊ + 1 | // comment 1␊ + 2 | module␊ + 3 | // comment 2␊ + 4 | .exports␊ + 5 | // comment 3␊ + 6 | =␊ + 7 | // comment 4␊ + > 8 | () => {};␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`module_\`.␊ + 1 | // comment 1␊ + 2 | const module_ = () => {};␊ + 3 | module␊ + 4 | // comment 2␊ + 5 | .exports␊ + 6 | // comment 3␊ + 7 | =␊ + 8 | // comment 4␊ + 9 | module_;␊ + ` + +## invalid(50): (( exports = (( () => {} )) )) + +> Input + + `␊ + 1 | (( exports = (( () => {} )) ))␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | (( exports = (( () => {} )) ))␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = (( () => {} ));␊ + 2 | (( exports = foo ));␊ + ` + +## invalid(51): (( module.exports = (( () => {} )) )) + +> Input + + `␊ + 1 | (( module.exports = (( () => {} )) ))␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | (( module.exports = (( () => {} )) ))␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = (( () => {} ));␊ + 2 | (( module.exports = foo ));␊ + ` + +## invalid(52): (( exports = (( () => {} )) )); + +> Input + + `␊ + 1 | (( exports = (( () => {} )) ));␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | (( exports = (( () => {} )) ));␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = (( () => {} ));␊ + 2 | (( exports = foo ));␊ + ` + +## invalid(53): (( module.exports = (( () => {} )) )); + +> Input + + `␊ + 1 | (( module.exports = (( () => {} )) ));␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | (( module.exports = (( () => {} )) ));␊ + | ^^ The arrow function should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | const foo = (( () => {} ));␊ + 2 | (( module.exports = foo ));␊ + ` + +## invalid(1): @decorator export default class {} + +> Input + + `␊ + 1 | @decorator export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | @decorator export default class {}␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | @decorator export default class Foo {}␊ + ` + +## invalid(2): export default @decorator(class {}) class extends class {} {} + +> Input + + `␊ + 1 | export default @decorator(class {}) class extends class {} {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | export default @decorator(class {}) class extends class {} {}␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | export default @decorator(class {}) class Foo extends class {} {}␊ + ` + +## invalid(3): module.exports = @decorator(class {}) class extends class {} {} + +> Input + + `␊ + 1 | module.exports = @decorator(class {}) class extends class {} {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | module.exports = @decorator(class {}) class extends class {} {}␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`foo\`.␊ + 1 | module.exports = @decorator(class {}) class foo extends class {} {}␊ + ` + +## invalid(4): @decorator @decorator(class {}) export default class {} + +> Input + + `␊ + 1 | @decorator @decorator(class {}) export default class {}␊ + ` + +> Filename + + `␊ + /path/to/foo.js␊ + ` + +> Error 1/1 + + `␊ + > 1 | @decorator @decorator(class {}) export default class {}␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The class should be named.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Name it as \`Foo\`.␊ + 1 | @decorator @decorator(class {}) export default class Foo {}␊ + ` diff --git a/test/snapshots/no-anonymous-default-export.mjs.snap b/test/snapshots/no-anonymous-default-export.mjs.snap new file mode 100644 index 0000000000000000000000000000000000000000..5d4237c13aabef49691413cb90cf9830c43f5350 GIT binary patch literal 2613 zcmV-53d;3CRzVt}mC zqsPjnvKxydZY(O{STs8g(?p{%4Z8mV9tHPu%>O1Za2fZX8=yV!dp&qxe3!Mb%lS#R zTubh76@F=0iq9Vnk z6}VbDQe`(%bCHoEX<7pAO-sc}z|^;XbJ^PyQsI(CD-^O}FyrgbJQX~88j@OnppnD_ zFkpt7lHkPDzb5JQ#HZ#3nbqiys@3QPU|@f)wArxMN|sS-8%FUX)461AWxb=@4mel+ z1AzOD0B*=dEH|zAmAklg^QLb0bt#w1C)kC?hR)V)wb_R&hVfxh6u%Y2@M0L&uj=Zz zNa?5Fvh;4t)rxDO31r29T9~J|mJC>xta7axX$a$6YY0%QFNP7z9&5 zvgZXIQaPyq0*e1C8q{MnrUl|1<>DcCOCy|prg|sYJG=ZEC06G60 zA34hvO-9jjMUxX1$tH|YR0a$@4n!^N-Oa?foADGxvK%8+@Gvm&gs0#KZNs>}Ct)H9 zkzC7eNZ7xKmhfL7;qT)h;TgLVViC{4NQz|K*~E}&fh?}+olTwI@9Ygnk&a}7Xva6L zMbV~pPeg%;6)K%G8WE2I15ZH_E#0*CR7|Ae&gONWhGn6qnZ8^rG$YAPRn%k2g3Uv(5x_ zwr|*+a(}2#Ic=Hz2Y13T*|K1rx&p*K=fhm434p!7p;#Mq=W+o{mjO#FnYi7oQQZt8 zmNJ%H2jB!WgfiTqXgxc|akFz`8%ArZqZeghDglKLJ6$FXV352BOg!m9;#i>>*#{W; z+ui@ut>e>6+7KA@-vfZ~$9bDb)&iFm$&*os-dt%Forz7jmOKiy{g=46Q+bv)HERa% zqP=SP<0?4#SwS*ruAR_PJy+o>kmi`UH-a;I2_=38Nc=FdT?n=>)>!_uXzJuHNa)QE zXjYI+8$1L_s(u2fH6?REQ@!?bTSdGV5d3ec#?q2cd}6d&UR$-wz&P)>1BkOOETP)Y^XG&VN$uEh!^ z3Y&94<0VO^5z`6*ssn)Dk(^u5PRXM*c2ETa5{(xxx@bt=Gi<%YtrKkFMHhLyPSQj* zULOIxK9I)C->-O7ISDU6l4C?!P%jD6&U4acW0YuQm%{e}7jGu2707=GE+K`V0t(lX z6>oO(qjmRAod?^3)$0*RzQvK8i&Hhk6+lWs*8nCLk`=Is))Zp74Y1ruSW~3>iGuk* zA~PHqADVQ*$zyXqS;5I|keD!OHWSr0Kx>LiPi?^Gm7z;du&+Tr0g!0{P+=8{yW|z3 zBy-x@0#=KP;0(`ci>;`wN<9tm$z`ajlo*RN(-B#q;vIEsRAR;Xp*0Q3YKK2GAM4PX z=;QJU*RO*>;C<9F2Sv~P*u7nO)99L3f2Y07y;;H+owi{tMOPuKWP+L&S<#ab5=srq z+gT>Oj~m4k71AL-^e+hlFL4BroHREaR=)^jW8xvcq)_-nK=_9u#`x0SAm>j5sD=~F z^yrp(8o&sK^#P#n1Gu_Tm>E6D)A z#Fe*GrM{GY*-q*^mVCdi*uQoy`+l!EMG;~?xBsW`w8ImgNu{0o{Be! zFQvIhc{C4HA0iz16;LSXML>zpK^?8@bC69 z{VLmb+s!dH3*VsS7@Hf^b5zs)9iaP8W+c6@!QOM?(@$(T3>37QKSb4Vh-N{E=E4Hc zvu!cOXE??4v1?c~z3&2UUK^tRF#1n$=j`kjvKryscmzy=T|(4WVF1c!A@$ zkgO&UwQIZ%7_=owdT>w;W>&z7-bD zeI>79`~tlDS+GYKk$1I#cj?|h1PdbMCc>?Ugf|jAj>Ja77e`_zvFsobpk$F77YrU= zbDOnO^!YqFPodK|UUL&$8U5XVMEm5XAeDs0yZHyM+i$f06nQjwwmi^2RL+w?0DtPY zlre=QfL>&$d?ZM8BkHbvJh%wgY9sKN;&@adrv_x5#J^l1!i+*BUIs`UlA9dpdd`?o zATPhh<=13q2ZRFf5RyzW&h(%XhS0N6V$2T$CdLYl*b_w2|Ghh>T6)tM9HtB0Yto+~ zUjSkjoX$pDQV7Pg0E|amFeLggfI{ZDe=0s(?ti{ily?!2nmQ-=jv>!<-i_2`oUaPF z2xL5qmy_Z(qL3Ewoj=*@M7b$u_t4oTf~)j1CLfcyUq9fT@5fFF4htZ7{7B|?>Y&@M zAqXlE*(Q0&Pz8kdD2D!(FHT&DXZ1)V>EZf^HX*$z;tvE%XkHQd85DV>p