diff --git a/CHANGELOG.md b/CHANGELOG.md index 05d623f41..0d53b58ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange - [`dynamic-import-chunkname`]: Allow empty chunk name when webpackMode: 'eager' is set; add suggestions to remove name in eager mode ([#3004], thanks [@amsardesai]) - [`no-unused-modules`]: Add `ignoreUnusedTypeExports` option ([#3011], thanks [@silverwind]) - add support for Flat Config ([#3018], thanks [@michaelfaith]) +- [`no-rename-default`]: Forbid importing a default export by a different name ([#3006], thanks [@whitneyit]) ### Fixed - [`no-extraneous-dependencies`]: allow wrong path ([#3012], thanks [@chabb]) diff --git a/README.md b/README.md index bf563f4d7..e16783d3a 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a | [no-mutable-exports](docs/rules/no-mutable-exports.md) | Forbid the use of mutable exports with `var` or `let`. | | | | | | | | [no-named-as-default](docs/rules/no-named-as-default.md) | Forbid use of exported name as identifier of default export. | | ☑️ 🚸 | | | | | | [no-named-as-default-member](docs/rules/no-named-as-default-member.md) | Forbid use of exported name as property of default export. | | ☑️ 🚸 | | | | | +| [no-rename-default](docs/rules/no-rename-default.md) | Forbid importing a default export by a different name. | | | | | | | | [no-unused-modules](docs/rules/no-unused-modules.md) | Forbid modules without exports, or exports without matching import in another module. | | | | | | | ### Module systems diff --git a/docs/rules/no-rename-default.md b/docs/rules/no-rename-default.md new file mode 100644 index 000000000..f101850de --- /dev/null +++ b/docs/rules/no-rename-default.md @@ -0,0 +1,29 @@ +# import/no-rename-default + + + +Prohibit importing a default export by another name. + +## Rule Details + +Given: + +```js +// api/get-users.js +export default async function getUsers() {} +``` + +...this would be valid: + +```js +import getUsers from './api/get-users.js'; +``` + +...and the following would be reported: + +```js +// Caution: `get-users.js` has a default export `getUsers`. +// This imports `getUsers` as `findUsers`. +// Check if you meant to write `import getUsers from './api/get-users'` instead. +import findUsers from './get-users'; +``` diff --git a/src/exportMap/builder.js b/src/exportMap/builder.js index 5348dba37..0e84f6c38 100644 --- a/src/exportMap/builder.js +++ b/src/exportMap/builder.js @@ -195,6 +195,7 @@ export default class ExportMapBuilder { && exportMap.namespace.size > 0 // anything is exported && !exportMap.namespace.has('default') // and default isn't added already ) { + exportMap.exports.set('default', {}); exportMap.namespace.set('default', {}); // add default export } diff --git a/src/exportMap/index.js b/src/exportMap/index.js index e4d61638c..3971d320d 100644 --- a/src/exportMap/index.js +++ b/src/exportMap/index.js @@ -14,6 +14,7 @@ export default class ExportMap { * @type {Map ExportMap>} */ this.imports = new Map(); + this.exports = new Map(); this.errors = []; /** * type {'ambiguous' | 'Module' | 'Script'} diff --git a/src/exportMap/specifier.js b/src/exportMap/specifier.js index dfaaf618e..835e6f003 100644 --- a/src/exportMap/specifier.js +++ b/src/exportMap/specifier.js @@ -9,15 +9,18 @@ export default function processSpecifier(specifier, astNode, exportMap, namespac local = 'default'; break; case 'ExportNamespaceSpecifier': + exportMap.exports.set(specifier.exported.name, astNode); exportMap.namespace.set(specifier.exported.name, Object.defineProperty(exportMeta, 'namespace', { get() { return namespace.resolveImport(nsource); }, })); return; case 'ExportAllDeclaration': + exportMap.exports.set(specifier.exported.name || specifier.exported.value, astNode); exportMap.namespace.set(specifier.exported.name || specifier.exported.value, namespace.add(exportMeta, specifier.source.value)); return; case 'ExportSpecifier': if (!astNode.source) { + exportMap.exports.set(specifier.exported.name || specifier.exported.value, astNode); exportMap.namespace.set(specifier.exported.name || specifier.exported.value, namespace.add(exportMeta, specifier.local)); return; } diff --git a/src/exportMap/visitor.js b/src/exportMap/visitor.js index 21c1a7c64..54a7b377b 100644 --- a/src/exportMap/visitor.js +++ b/src/exportMap/visitor.js @@ -53,6 +53,7 @@ export default class ImportExportVisitorBuilder { if (astNode.declaration.type === 'Identifier') { this.namespace.add(exportMeta, astNode.declaration); } + this.exportMap.exports.set('default', astNode); this.exportMap.namespace.set('default', exportMeta); }, ExportAllDeclaration() { @@ -86,13 +87,17 @@ export default class ImportExportVisitorBuilder { case 'TSInterfaceDeclaration': case 'TSAbstractClassDeclaration': case 'TSModuleDeclaration': + this.exportMap.exports.set(astNode.declaration.id.name, astNode); this.exportMap.namespace.set(astNode.declaration.id.name, captureDoc(this.source, this.docStyleParsers, astNode)); break; case 'VariableDeclaration': astNode.declaration.declarations.forEach((d) => { recursivePatternCapture( d.id, - (id) => this.exportMap.namespace.set(id.name, captureDoc(this.source, this.docStyleParsers, d, astNode)), + (id) => { + this.exportMap.exports.set(id.name, astNode); + this.exportMap.namespace.set(id.name, captureDoc(this.source, this.docStyleParsers, d, astNode)); + }, ); }); break; @@ -126,6 +131,7 @@ export default class ImportExportVisitorBuilder { )); if (exportedDecls.length === 0) { // Export is not referencing any local declaration, must be re-exporting + this.exportMap.exports.set('default', astNode); this.exportMap.namespace.set('default', captureDoc(this.source, this.docStyleParsers, astNode)); return; } @@ -133,11 +139,13 @@ export default class ImportExportVisitorBuilder { this.isEsModuleInteropTrue // esModuleInterop is on in tsconfig && !this.exportMap.namespace.has('default') // and default isn't added already ) { + this.exportMap.exports.set('default', {}); // add default export this.exportMap.namespace.set('default', {}); // add default export } exportedDecls.forEach((decl) => { if (decl.type === 'TSModuleDeclaration') { if (decl.body && decl.body.type === 'TSModuleDeclaration') { + this.exportMap.exports.set(decl.body.id.name, astNode); this.exportMap.namespace.set(decl.body.id.name, captureDoc(this.source, this.docStyleParsers, decl.body)); } else if (decl.body && decl.body.body) { decl.body.body.forEach((moduleBlockNode) => { @@ -150,20 +158,19 @@ export default class ImportExportVisitorBuilder { if (!namespaceDecl) { // TypeScript can check this for us; we needn't } else if (namespaceDecl.type === 'VariableDeclaration') { - namespaceDecl.declarations.forEach((d) => recursivePatternCapture(d.id, (id) => this.exportMap.namespace.set( - id.name, - captureDoc(this.source, this.docStyleParsers, decl, namespaceDecl, moduleBlockNode), - )), - ); + namespaceDecl.declarations.forEach((d) => recursivePatternCapture(d.id, (id) => { + this.exportMap.exports.set(id.name, astNode); + this.exportMap.namespace.set(id.name, captureDoc(this.source, this.docStyleParsers, decl, namespaceDecl, moduleBlockNode)); + })); } else { - this.exportMap.namespace.set( - namespaceDecl.id.name, - captureDoc(this.source, this.docStyleParsers, moduleBlockNode)); + this.exportMap.exports.set(namespaceDecl.id.name, astNode); + this.exportMap.namespace.set(namespaceDecl.id.name, captureDoc(this.source, this.docStyleParsers, moduleBlockNode)); } }); } } else { // Export as default + this.exportMap.exports.set('default', {}); this.exportMap.namespace.set('default', captureDoc(this.source, this.docStyleParsers, decl)); } }); diff --git a/src/index.js b/src/index.js index 0ab82ebee..0adb71443 100644 --- a/src/index.js +++ b/src/index.js @@ -22,6 +22,7 @@ export const rules = { 'no-named-as-default': require('./rules/no-named-as-default'), 'no-named-as-default-member': require('./rules/no-named-as-default-member'), 'no-anonymous-default-export': require('./rules/no-anonymous-default-export'), + 'no-rename-default': require('./rules/no-rename-default'), 'no-unused-modules': require('./rules/no-unused-modules'), 'no-commonjs': require('./rules/no-commonjs'), diff --git a/src/rules/no-rename-default.js b/src/rules/no-rename-default.js new file mode 100644 index 000000000..b61ede54c --- /dev/null +++ b/src/rules/no-rename-default.js @@ -0,0 +1,278 @@ +/** + * @fileOverview Rule to warn about importing a default export by different name + * @author James Whitney + */ + +import docsUrl from '../docsUrl'; +import ExportMapBuilder from '../exportMap/builder'; +import path from 'path'; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'suggestion', + docs: { + category: 'Helpful warnings', + description: 'Forbid importing a default export by a different name.', + recommended: false, + url: docsUrl('no-named-as-default'), + }, + schema: [ + { + type: 'object', + properties: { + commonjs: { + default: false, + type: 'boolean', + }, + preventRenamingBindings: { + default: true, + type: 'boolean', + }, + }, + additionalProperties: false, + }, + ], + }, + + create(context) { + const { + commonjs = false, + preventRenamingBindings = true, + } = context.options[0] || {}; + + function getDefaultExportName(targetNode) { + if (targetNode == null) { + return; + } + switch (targetNode.type) { + case 'AssignmentExpression': { + if (!preventRenamingBindings) { + // Allow assignments to be renamed when the `preventRenamingBindings` + // option is set to `false`. + // + // export default Foo = 1; + return; + } + return targetNode.left.name; + } + case 'CallExpression': { + const [argumentNode] = targetNode.arguments; + return getDefaultExportName(argumentNode); + } + case 'ClassDeclaration': { + if (targetNode.id && typeof targetNode.id.name === 'string') { + return targetNode.id.name; + } + // Here we have an anonymous class. We can skip here. + return; + } + case 'ExportSpecifier': { + return targetNode.local.name; + } + case 'FunctionDeclaration': { + return targetNode.id.name; + } + case 'Identifier': { + if (!preventRenamingBindings) { + // Allow identifier to be renamed when the `preventRenamingBindings` + // option is set to `false`. + // + // const foo = 'foo'; + // export default foo; + return; + } + return targetNode.name; + } + default: + // This type of node is not handled. + // Returning `undefined` here signifies this and causes the check to + // exit early. + } + } + + function getDefaultExportNode(exportMap) { + const defaultExportNode = exportMap.exports.get('default'); + if (defaultExportNode == null) { + return; + } + + if (defaultExportNode.type === 'ExportDefaultDeclaration') { + return defaultExportNode.declaration; + } + + if (defaultExportNode.type === 'ExportNamedDeclaration') { + return defaultExportNode.specifiers.find((specifier) => specifier.exported.name === 'default'); + } + } + + function getExportMap(source, context) { + const exportMap = ExportMapBuilder.get(source.value, context); + if (exportMap == null) { + return; + } + if (exportMap.errors.length > 0) { + exportMap.reportErrors(context, source.value); + return; + } + return exportMap; + } + + function handleImport(node) { + const exportMap = getExportMap(node.parent.source, context); + if (exportMap == null) { + return; + } + + const defaultExportNode = getDefaultExportNode(exportMap); + if (defaultExportNode == null) { + return; + } + + const defaultExportName = getDefaultExportName(defaultExportNode); + if (defaultExportName === undefined) { + return; + } + + const importTarget = node.parent.source.value; + const importBasename = path.basename(exportMap.path); + + if (node.type === 'ImportDefaultSpecifier') { + const importName = node.local.name; + + if (importName === defaultExportName) { + return; + } + + context.report({ + node, + message: `Caution: \`{{importBasename}}\` has a default export \`{{defaultExportName}}\`. This imports \`{{defaultExportName}}\` as \`{{importName}}\`. Check if you meant to write \`import {{defaultExportName} from '{{importTarget}}'\` instead.`, + data: { + defaultExportName, + importBasename, + importName, + importTarget, + }, + }); + + return; + } + + if (node.type !== 'ImportSpecifier' || node.imported.name !== 'default') { + return; + } + + const actualImportedName = node.local.name; + + if (actualImportedName === defaultExportName) { + return; + } + + context.report({ + node, + message: `Caution: \`{{importBasename}}\` has a default export \`{{defaultExportName}}\`. This imports \`{{defaultExportName}}\` as \`{{actualImportedName}}\`. Check if you meant to write \`import { default as {{defaultExportName}} } from '{{importTarget}}'\` instead.`, + data: { + actualImportedName, + defaultExportName, + importBasename, + importTarget, + }, + }); + } + + function handleRequire(node) { + if ( + !commonjs + || node.type !== 'VariableDeclarator' + || !node.id + || !(node.id.type === 'Identifier' + || node.id.type === 'ObjectPattern') + || !node.init + || node.init.type !== 'CallExpression' + ) { + return; + } + + let defaultDestructure; + if (node.id.type === 'ObjectPattern') { + defaultDestructure = node.id.properties.find((property) => property.key.name === 'default'); + if (defaultDestructure === undefined) { + return; + } + } + + const call = node.init; + const [source] = call.arguments; + + if ( + call.callee.type !== 'Identifier' + || call.callee.name !== 'require' + || call.arguments.length !== 1 + || source.type !== 'Literal' + ) { + return; + } + + const exportMap = getExportMap(source, context); + if (exportMap == null) { + return; + } + + const defaultExportNode = getDefaultExportNode(exportMap); + if (defaultExportNode == null) { + return; + } + + const defaultExportName = getDefaultExportName(defaultExportNode); + const requireTarget = source.value; + const requireBasename = path.basename(exportMap.path); + const requireName = node.id.type === 'Identifier' ? node.id.name : defaultDestructure.value.name; + + if (defaultExportName === undefined) { + return; + } + + if (requireName === defaultExportName) { + return; + } + + const data = { + defaultExportName, + requireBasename, + requireName, + requireTarget, + }; + + if (node.id.type === 'Identifier') { + context.report({ + node, + message: `Caution: \`{{requireBasename}}\` has a default export \`{{defaultExportName}}\`. This requires \`{{defaultExportName}}\` as \`{{requireName}}\`. Check if you meant to write \`const {{defaultExportName}} = require('{{requireTarget}}')\` instead.`, + data, + }); + return; + } + + context.report({ + node, + message: `Caution: \`{{requireBasename}}\` has a default export \`{{defaultExportName}\`. This requires \`{{defaultExportName}\` as \`{{requireName}}\`. Check if you meant to write \`const { default: {{defaultExportName}} } = require('{{requireTarget}}')\` instead.`, + data, + }); + } + + return { + ImportDefaultSpecifier(node) { + handleImport(node); + }, + ImportSpecifier(node) { + handleImport(node); + }, + VariableDeclarator(node) { + handleRequire(node); + }, + }; + }, +}; diff --git a/tests/files/no-rename-default/anonymous-arrow-async.js b/tests/files/no-rename-default/anonymous-arrow-async.js new file mode 100644 index 000000000..18554e89e --- /dev/null +++ b/tests/files/no-rename-default/anonymous-arrow-async.js @@ -0,0 +1 @@ +export default async () => {}; diff --git a/tests/files/no-rename-default/anonymous-arrow.js b/tests/files/no-rename-default/anonymous-arrow.js new file mode 100644 index 000000000..2d1ec2382 --- /dev/null +++ b/tests/files/no-rename-default/anonymous-arrow.js @@ -0,0 +1 @@ +export default () => {}; diff --git a/tests/files/no-rename-default/anonymous-class.js b/tests/files/no-rename-default/anonymous-class.js new file mode 100644 index 000000000..0a6916a6d --- /dev/null +++ b/tests/files/no-rename-default/anonymous-class.js @@ -0,0 +1 @@ +export default class {}; diff --git a/tests/files/no-rename-default/anonymous-object.js b/tests/files/no-rename-default/anonymous-object.js new file mode 100644 index 000000000..ff8b4c563 --- /dev/null +++ b/tests/files/no-rename-default/anonymous-object.js @@ -0,0 +1 @@ +export default {}; diff --git a/tests/files/no-rename-default/anonymous-primitive.js b/tests/files/no-rename-default/anonymous-primitive.js new file mode 100644 index 000000000..05e087120 --- /dev/null +++ b/tests/files/no-rename-default/anonymous-primitive.js @@ -0,0 +1 @@ +export default 123; diff --git a/tests/files/no-rename-default/assign-arrow-async.js b/tests/files/no-rename-default/assign-arrow-async.js new file mode 100644 index 000000000..85c31b471 --- /dev/null +++ b/tests/files/no-rename-default/assign-arrow-async.js @@ -0,0 +1 @@ +export default arrowAsync = async () => {}; diff --git a/tests/files/no-rename-default/assign-arrow.js b/tests/files/no-rename-default/assign-arrow.js new file mode 100644 index 000000000..970ba63d1 --- /dev/null +++ b/tests/files/no-rename-default/assign-arrow.js @@ -0,0 +1 @@ +export default arrow = () => {}; diff --git a/tests/files/no-rename-default/assign-class-named.js b/tests/files/no-rename-default/assign-class-named.js new file mode 100644 index 000000000..90f15bb0a --- /dev/null +++ b/tests/files/no-rename-default/assign-class-named.js @@ -0,0 +1 @@ +export default User = class MyUser {} diff --git a/tests/files/no-rename-default/assign-class.js b/tests/files/no-rename-default/assign-class.js new file mode 100644 index 000000000..3b46709fa --- /dev/null +++ b/tests/files/no-rename-default/assign-class.js @@ -0,0 +1 @@ +export default User = class {} diff --git a/tests/files/no-rename-default/assign-fn-named.js b/tests/files/no-rename-default/assign-fn-named.js new file mode 100644 index 000000000..ccbf54a54 --- /dev/null +++ b/tests/files/no-rename-default/assign-fn-named.js @@ -0,0 +1 @@ +export default fn = function myFn() {}; diff --git a/tests/files/no-rename-default/assign-fn.js b/tests/files/no-rename-default/assign-fn.js new file mode 100644 index 000000000..f3da45e3e --- /dev/null +++ b/tests/files/no-rename-default/assign-fn.js @@ -0,0 +1 @@ +export default fn = function () {}; diff --git a/tests/files/no-rename-default/assign-generator-named.js b/tests/files/no-rename-default/assign-generator-named.js new file mode 100644 index 000000000..737411e01 --- /dev/null +++ b/tests/files/no-rename-default/assign-generator-named.js @@ -0,0 +1 @@ +export default generator = function* myGenerator() {}; diff --git a/tests/files/no-rename-default/assign-generator.js b/tests/files/no-rename-default/assign-generator.js new file mode 100644 index 000000000..68e256de4 --- /dev/null +++ b/tests/files/no-rename-default/assign-generator.js @@ -0,0 +1 @@ +export default generator = function* () {}; diff --git a/tests/files/no-rename-default/class-user.js b/tests/files/no-rename-default/class-user.js new file mode 100644 index 000000000..e6c5fb052 --- /dev/null +++ b/tests/files/no-rename-default/class-user.js @@ -0,0 +1 @@ +export default class User {}; diff --git a/tests/files/no-rename-default/const-bar.js b/tests/files/no-rename-default/const-bar.js new file mode 100644 index 000000000..da071dcc1 --- /dev/null +++ b/tests/files/no-rename-default/const-bar.js @@ -0,0 +1,6 @@ +export const barNamed1 = 'bar-named-1'; +export const barNamed2 = 'bar-named-2'; + +const bar = 'bar'; + +export default bar; diff --git a/tests/files/no-rename-default/const-foo.js b/tests/files/no-rename-default/const-foo.js new file mode 100644 index 000000000..a85147d86 --- /dev/null +++ b/tests/files/no-rename-default/const-foo.js @@ -0,0 +1,6 @@ +export const fooNamed1 = 'foo-named-1'; +export const fooNamed2 = 'foo-named-2'; + +const foo = 'foo'; + +export default foo; diff --git a/tests/files/no-rename-default/fn-get-users-sync.js b/tests/files/no-rename-default/fn-get-users-sync.js new file mode 100644 index 000000000..c1f60a47f --- /dev/null +++ b/tests/files/no-rename-default/fn-get-users-sync.js @@ -0,0 +1 @@ +export default function getUsersSync() {} diff --git a/tests/files/no-rename-default/fn-get-users.js b/tests/files/no-rename-default/fn-get-users.js new file mode 100644 index 000000000..9b77ba196 --- /dev/null +++ b/tests/files/no-rename-default/fn-get-users.js @@ -0,0 +1 @@ +export default async function getUsers() {} diff --git a/tests/files/no-rename-default/generator-reader.js b/tests/files/no-rename-default/generator-reader.js new file mode 100644 index 000000000..358f1186c --- /dev/null +++ b/tests/files/no-rename-default/generator-reader.js @@ -0,0 +1 @@ +export default function* reader() {} diff --git a/tests/files/no-rename-default/pr-3006-feedback/binding-const-rename-fn.js b/tests/files/no-rename-default/pr-3006-feedback/binding-const-rename-fn.js new file mode 100644 index 000000000..139b0492c --- /dev/null +++ b/tests/files/no-rename-default/pr-3006-feedback/binding-const-rename-fn.js @@ -0,0 +1,3 @@ +const foo = function bar() {}; + +export default foo; diff --git a/tests/files/no-rename-default/pr-3006-feedback/binding-fn-rename.js b/tests/files/no-rename-default/pr-3006-feedback/binding-fn-rename.js new file mode 100644 index 000000000..e16264a21 --- /dev/null +++ b/tests/files/no-rename-default/pr-3006-feedback/binding-fn-rename.js @@ -0,0 +1,3 @@ +function bar() {} + +export default bar; diff --git a/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-foo.js b/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-foo.js new file mode 100644 index 000000000..36904cdfd --- /dev/null +++ b/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-foo.js @@ -0,0 +1,4 @@ +import foo from '../default-const-foo'; +import withLogger from './hoc-with-logger'; + +export default withLogger(foo); diff --git a/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-get-users.js b/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-get-users.js new file mode 100644 index 000000000..6d16feefb --- /dev/null +++ b/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-get-users.js @@ -0,0 +1,4 @@ +import getUsers from '../default-fn-get-users'; +import withLogger from './hoc-with-logger'; + +export default withLogger(getUsers); diff --git a/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-with-auth-for-get-users.js b/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-with-auth-for-get-users.js new file mode 100644 index 000000000..53b24539b --- /dev/null +++ b/tests/files/no-rename-default/pr-3006-feedback/binding-hoc-with-logger-with-auth-for-get-users.js @@ -0,0 +1,5 @@ +import getUsers from '../default-fn-get-users'; +import withAuth from './hoc-with-auth'; +import withLogger from './hoc-with-logger'; + +export default withLogger(withAuth(getUsers)); diff --git a/tests/files/no-rename-default/pr-3006-feedback/hoc-with-auth.js b/tests/files/no-rename-default/pr-3006-feedback/hoc-with-auth.js new file mode 100644 index 000000000..03c9006a2 --- /dev/null +++ b/tests/files/no-rename-default/pr-3006-feedback/hoc-with-auth.js @@ -0,0 +1,6 @@ +export default function withAuth(fn) { + return function innerAuth(...args) { + const auth = {}; + return fn.call(null, auth, ...args); + } +} diff --git a/tests/files/no-rename-default/pr-3006-feedback/hoc-with-logger.js b/tests/files/no-rename-default/pr-3006-feedback/hoc-with-logger.js new file mode 100644 index 000000000..bead43621 --- /dev/null +++ b/tests/files/no-rename-default/pr-3006-feedback/hoc-with-logger.js @@ -0,0 +1,6 @@ +export default function withLogger(fn) { + return function innerLogger(...args) { + console.log(`${fn.name} called`); + return fn.apply(null, args); + } +} diff --git a/tests/files/no-rename-default/typescript-default.d.ts b/tests/files/no-rename-default/typescript-default.d.ts new file mode 100644 index 000000000..deac53f85 --- /dev/null +++ b/tests/files/no-rename-default/typescript-default.d.ts @@ -0,0 +1,3 @@ +declare const foo: {}; + +export default foo; diff --git a/tests/src/rules/no-rename-default.js b/tests/src/rules/no-rename-default.js new file mode 100644 index 000000000..5236f7ada --- /dev/null +++ b/tests/src/rules/no-rename-default.js @@ -0,0 +1,1067 @@ +import { RuleTester } from 'eslint'; +import { getTSParsers, test } from '../utils'; + +const ruleTester = new RuleTester(); +const rule = require('rules/no-rename-default'); + +// IMPORT +// anonymous-arrow.js +// anonymous-arrow-async.js +// anonymous-class.js +// anonymous-object.js +// anonymous-primitive.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import _ from './no-rename-default/anonymous-arrow' + `, + }), + test({ + code: ` + import _ from './no-rename-default/anonymous-arrow-async' + `, + }), + test({ + code: ` + import _ from './no-rename-default/anonymous-class' + `, + }), + test({ + code: ` + import _ from './no-rename-default/anonymous-object' + `, + }), + test({ + code: ` + import _ from './no-rename-default/anonymous-primitive' + `, + }), + ], + invalid: [], +}); + +// REQUIRE { commonjs: true } +// anonymous-arrow.js +// anonymous-arrow-async.js +// anonymous-class.js +// anonymous-object.js +// anonymous-primitive.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const _ = require('./no-rename-default/anonymous-arrow') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const _ = require('./no-rename-default/anonymous-arrow-async') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const _ = require('./no-rename-default/anonymous-class') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const _ = require('./no-rename-default/anonymous-object') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const _ = require('./no-rename-default/anonymous-primitive') + `, + options: [{ commonjs: true }], + }), + ], + invalid: [], +}); + +// IMPORT +// assign-arrow.js +// assign-arrow-async.js +// assign-class.js +// assign-class-named.js +// assign-fn.js +// assign-fn-named.js +// assign-generator.js +// assign-generator-named.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import arrow from './no-rename-default/assign-arrow' + `, + }), + test({ + code: ` + import arrowAsync from './no-rename-default/assign-arrow-async' + `, + }), + test({ + code: ` + import User from './no-rename-default/assign-class' + `, + }), + test({ + code: ` + import User from './no-rename-default/assign-class-named' + `, + }), + test({ + code: ` + import fn from './no-rename-default/assign-fn' + `, + }), + test({ + code: ` + import fn from './no-rename-default/assign-fn-named' + `, + }), + test({ + code: ` + import generator from './no-rename-default/assign-generator' + `, + }), + test({ + code: ` + import generator from './no-rename-default/assign-generator-named' + `, + }), + ], + invalid: [ + test({ + code: ` + import myArrow from './no-rename-default/assign-arrow' + `, + errors: [{ + message: 'Caution: `assign-arrow.js` has a default export `arrow`. This imports `arrow` as `myArrow`. Check if you meant to write `import arrow from \'./no-rename-default/assign-arrow\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import myArrowAsync from './no-rename-default/assign-arrow-async' + `, + errors: [{ + message: 'Caution: `assign-arrow-async.js` has a default export `arrowAsync`. This imports `arrowAsync` as `myArrowAsync`. Check if you meant to write `import arrowAsync from \'./no-rename-default/assign-arrow-async\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import MyUser from './no-rename-default/assign-class' + `, + errors: [{ + message: 'Caution: `assign-class.js` has a default export `User`. This imports `User` as `MyUser`. Check if you meant to write `import User from \'./no-rename-default/assign-class\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import MyUser from './no-rename-default/assign-class-named' + `, + errors: [{ + message: 'Caution: `assign-class-named.js` has a default export `User`. This imports `User` as `MyUser`. Check if you meant to write `import User from \'./no-rename-default/assign-class-named\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import myFn from './no-rename-default/assign-fn' + `, + errors: [{ + message: 'Caution: `assign-fn.js` has a default export `fn`. This imports `fn` as `myFn`. Check if you meant to write `import fn from \'./no-rename-default/assign-fn\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import myFn from './no-rename-default/assign-fn-named' + `, + errors: [{ + message: 'Caution: `assign-fn-named.js` has a default export `fn`. This imports `fn` as `myFn`. Check if you meant to write `import fn from \'./no-rename-default/assign-fn-named\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import myGenerator from './no-rename-default/assign-generator' + `, + errors: [{ + message: 'Caution: `assign-generator.js` has a default export `generator`. This imports `generator` as `myGenerator`. Check if you meant to write `import generator from \'./no-rename-default/assign-generator\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import myGenerator from './no-rename-default/assign-generator-named' + `, + errors: [{ + message: 'Caution: `assign-generator-named.js` has a default export `generator`. This imports `generator` as `myGenerator`. Check if you meant to write `import generator from \'./no-rename-default/assign-generator-named\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + ], +}); + +// IMPORT { preventRenamingBindings: false } +// assign-arrow.js +// assign-arrow-async.js +// assign-class.js +// assign-class-named.js +// assign-fn.js +// assign-fn-named.js +// assign-generator.js +// assign-generator-named.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import myArrow from './no-rename-default/assign-arrow' + `, + options: [{ preventRenamingBindings: false }], + }), + test({ + code: ` + import myArrowAsync from './no-rename-default/assign-arrow-async' + `, + options: [{ preventRenamingBindings: false }], + }), + test({ + code: ` + import MyUser from './no-rename-default/assign-class' + `, + options: [{ preventRenamingBindings: false }], + }), + test({ + code: ` + import MyUser from './no-rename-default/assign-class-named' + `, + options: [{ preventRenamingBindings: false }], + }), + test({ + code: ` + import myFn from './no-rename-default/assign-fn' + `, + options: [{ preventRenamingBindings: false }], + }), + test({ + code: ` + import myFn from './no-rename-default/assign-fn-named' + `, + options: [{ preventRenamingBindings: false }], + }), + test({ + code: ` + import myGenerator from './no-rename-default/assign-generator' + `, + options: [{ preventRenamingBindings: false }], + }), + test({ + code: ` + import myGenerator from './no-rename-default/assign-generator-named' + `, + options: [{ preventRenamingBindings: false }], + }), + ], + invalid: [], +}); + +// REQUIRE { commonjs: true } +// assign-arrow.js +// assign-arrow-async.js +// assign-class.js +// assign-class-named.js +// assign-fn.js +// assign-fn-named.js +// assign-generator.js +// assign-generator-named.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const arrow = require('./no-rename-default/assign-arrow') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const arrowAsync = require('./no-rename-default/assign-arrow-async') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const User = require('./no-rename-default/assign-class') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const User = require('./no-rename-default/assign-class-named') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const fn = require('./no-rename-default/assign-fn') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const fn = require('./no-rename-default/assign-fn-named') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const generator = require('./no-rename-default/assign-generator') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const generator = require('./no-rename-default/assign-generator-named') + `, + options: [{ commonjs: true }], + }), + ], + invalid: [ + test({ + code: ` + const myArrow = require('./no-rename-default/assign-arrow') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-arrow.js` has a default export `arrow`. This requires `arrow` as `myArrow`. Check if you meant to write `const arrow = require(\'./no-rename-default/assign-arrow\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const myArrowAsync = require('./no-rename-default/assign-arrow-async') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-arrow-async.js` has a default export `arrowAsync`. This requires `arrowAsync` as `myArrowAsync`. Check if you meant to write `const arrowAsync = require(\'./no-rename-default/assign-arrow-async\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const MyUser = require('./no-rename-default/assign-class') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-class.js` has a default export `User`. This requires `User` as `MyUser`. Check if you meant to write `const User = require(\'./no-rename-default/assign-class\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const MyUser = require('./no-rename-default/assign-class-named') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-class-named.js` has a default export `User`. This requires `User` as `MyUser`. Check if you meant to write `const User = require(\'./no-rename-default/assign-class-named\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const myFn = require('./no-rename-default/assign-fn') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-fn.js` has a default export `fn`. This requires `fn` as `myFn`. Check if you meant to write `const fn = require(\'./no-rename-default/assign-fn\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const myFn = require('./no-rename-default/assign-fn-named') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-fn-named.js` has a default export `fn`. This requires `fn` as `myFn`. Check if you meant to write `const fn = require(\'./no-rename-default/assign-fn-named\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const myGenerator = require('./no-rename-default/assign-generator') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-generator.js` has a default export `generator`. This requires `generator` as `myGenerator`. Check if you meant to write `const generator = require(\'./no-rename-default/assign-generator\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const myGenerator = require('./no-rename-default/assign-generator-named') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `assign-generator-named.js` has a default export `generator`. This requires `generator` as `myGenerator`. Check if you meant to write `const generator = require(\'./no-rename-default/assign-generator-named\')` instead.', + type: 'VariableDeclarator', + }], + }), + ], +}); + +// REQUIRE { commonjs: true, preventRenamingBindings: false } +// assign-arrow.js +// assign-arrow-async.js +// assign-class.js +// assign-class-named.js +// assign-fn.js +// assign-fn-named.js +// assign-generator.js +// assign-generator-named.js +ruleTester.run('no-renamed-default', rule, { + valid: [ + test({ + code: ` + const myArrow = require('./no-rename-default/assign-arrow') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + test({ + code: ` + const myArrowAsync = require('./no-rename-default/assign-arrow-async') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + test({ + code: ` + const MyUser = require('./no-rename-default/assign-class') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + test({ + code: ` + const MyUser = require('./no-rename-default/assign-class-named') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + test({ + code: ` + const myFn = require('./no-rename-default/assign-fn') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + test({ + code: ` + const myFn = require('./no-rename-default/assign-fn-named') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + test({ + code: ` + const myGenerator = require('./no-rename-default/assign-generator') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + test({ + code: ` + const myGenerator = require('./no-rename-default/assign-generator-named') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + ], + invalid: [ + + ], +}); + +// IMPORT +// class-user.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import User from './no-rename-default/class-user' + `, + }), + ], + invalid: [ + test({ + code: ` + import MyUser from './no-rename-default/class-user' + `, + errors: [{ + message: 'Caution: `class-user.js` has a default export `User`. This imports `User` as `MyUser`. Check if you meant to write `import User from \'./no-rename-default/class-user\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + ], +}); + +// REQUIRE { commonjs: true } +// class-user.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const User = require('./no-rename-default/class-user') + `, + options: [{ commonjs: true }], + }), + ], + invalid: [ + test({ + code: ` + const MyUser = require('./no-rename-default/class-user') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `class-user.js` has a default export `User`. This requires `User` as `MyUser`. Check if you meant to write `const User = require(\'./no-rename-default/class-user\')` instead.', + type: 'VariableDeclarator', + }], + }), + ], +}); + +// IMPORT +// const-bar.js +// const-foo.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import foo from './no-rename-default/const-foo' + `, + }), + test({ + code: ` + import { fooNamed1 } from './no-rename-default/const-foo' + `, + }), + test({ + code: ` + import { fooNamed1, fooNamed2 } from './no-rename-default/const-foo' + `, + }), + test({ + code: ` + import { default as foo } from './no-rename-default/const-foo' + `, + }), + test({ + code: ` + import { default as foo, fooNamed1 } from './no-rename-default/const-foo' + `, + }), + test({ + code: ` + import foo, { fooNamed1 } from './no-rename-default/const-foo' + `, + }), + test({ + code: ` + import bar from './no-rename-default/const-bar' + import foo from './no-rename-default/const-foo' + `, + }), + test({ + code: ` + import bar, { barNamed1 } from './no-rename-default/const-bar' + import foo, { fooNamed1 } from './no-rename-default/const-foo' + `, + }), + ], + invalid: [ + test({ + code: ` + import bar from './no-rename-default/const-foo' + `, + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This imports `foo` as `bar`. Check if you meant to write `import foo from \'./no-rename-default/const-foo\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import { default as bar } from './no-rename-default/const-foo' + `, + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This imports `foo` as `bar`. Check if you meant to write `import { default as foo } from \'./no-rename-default/const-foo\'` instead.', + type: 'ImportSpecifier', + }], + }), + test({ + code: ` + import { default as bar, fooNamed1 } from './no-rename-default/const-foo' + `, + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This imports `foo` as `bar`. Check if you meant to write `import { default as foo } from \'./no-rename-default/const-foo\'` instead.', + type: 'ImportSpecifier', + }], + }), + test({ + code: ` + import bar, { fooNamed1 } from './no-rename-default/const-foo' + `, + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This imports `foo` as `bar`. Check if you meant to write `import foo from \'./no-rename-default/const-foo\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import foo from './no-rename-default/const-bar' + import bar from './no-rename-default/const-foo' + `, + errors: [{ + message: 'Caution: `const-bar.js` has a default export `bar`. This imports `bar` as `foo`. Check if you meant to write `import bar from \'./no-rename-default/const-bar\'` instead.', + type: 'ImportDefaultSpecifier', + }, { + message: 'Caution: `const-foo.js` has a default export `foo`. This imports `foo` as `bar`. Check if you meant to write `import foo from \'./no-rename-default/const-foo\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import findUsers from './no-rename-default/fn-get-users' + `, + errors: [{ + message: 'Caution: `fn-get-users.js` has a default export `getUsers`. This imports `getUsers` as `findUsers`. Check if you meant to write `import getUsers from \'./no-rename-default/fn-get-users\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import findUsersSync from './no-rename-default/fn-get-users-sync' + `, + errors: [{ + message: 'Caution: `fn-get-users-sync.js` has a default export `getUsersSync`. This imports `getUsersSync` as `findUsersSync`. Check if you meant to write `import getUsersSync from \'./no-rename-default/fn-get-users-sync\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import foo, { barNamed1 } from './no-rename-default/const-bar' + import bar, { fooNamed1 } from './no-rename-default/const-foo' + `, + errors: [{ + message: 'Caution: `const-bar.js` has a default export `bar`. This imports `bar` as `foo`. Check if you meant to write `import bar from \'./no-rename-default/const-bar\'` instead.', + type: 'ImportDefaultSpecifier', + }, { + message: 'Caution: `const-foo.js` has a default export `foo`. This imports `foo` as `bar`. Check if you meant to write `import foo from \'./no-rename-default/const-foo\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + ], +}); + +// REQUIRE { commonjs: true } +// const-bar.js +// const-foo.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const foo = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const { fooNamed1 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const { fooNamed1, fooNamed2 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const { default: foo } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const { default: foo, fooNamed1 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const foo = require('./no-rename-default/const-foo') + const { fooNamed1 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const getUsers = require('./no-rename-default/fn-get-users') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const getUsersSync = require('./no-rename-default/fn-get-users-sync') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const bar = require('./no-rename-default/const-bar') + const { barNamed1 } = require('./no-rename-default/const-bar') + const foo = require('./no-rename-default/const-foo') + const { fooNamed1 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + }), + ], + invalid: [ + test({ + code: ` + const bar = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This requires `foo` as `bar`. Check if you meant to write `const foo = require(\'./no-rename-default/const-foo\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const bar = require('./no-rename-default/const-foo') + const { fooNamed1 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This requires `foo` as `bar`. Check if you meant to write `const foo = require(\'./no-rename-default/const-foo\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const { default: bar } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This requires `foo` as `bar`. Check if you meant to write `const { default: foo } = require(\'./no-rename-default/const-foo\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const { default: bar, fooNamed1 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `const-foo.js` has a default export `foo`. This requires `foo` as `bar`. Check if you meant to write `const { default: foo } = require(\'./no-rename-default/const-foo\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const foo = require('./no-rename-default/const-bar') + const bar = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `const-bar.js` has a default export `bar`. This requires `bar` as `foo`. Check if you meant to write `const bar = require(\'./no-rename-default/const-bar\')` instead.', + type: 'VariableDeclarator', + }, { + message: 'Caution: `const-foo.js` has a default export `foo`. This requires `foo` as `bar`. Check if you meant to write `const foo = require(\'./no-rename-default/const-foo\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const foo = require('./no-rename-default/const-bar') + const { barNamed1 } = require('./no-rename-default/const-bar') + const bar = require('./no-rename-default/const-foo') + const { fooNamed1 } = require('./no-rename-default/const-foo') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `const-bar.js` has a default export `bar`. This requires `bar` as `foo`. Check if you meant to write `const bar = require(\'./no-rename-default/const-bar\')` instead.', + type: 'VariableDeclarator', + }, { + message: 'Caution: `const-foo.js` has a default export `foo`. This requires `foo` as `bar`. Check if you meant to write `const foo = require(\'./no-rename-default/const-foo\')` instead.', + type: 'VariableDeclarator', + }], + }), + ], +}); + +// IMPORT +// fn-get-users.js +// fn-get-users-sync.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import getUsers from './no-rename-default/fn-get-users' + `, + }), + test({ + code: ` + import getUsersSync from './no-rename-default/fn-get-users-sync' + `, + }), + ], + invalid: [ + test({ + code: ` + import findUsers from './no-rename-default/fn-get-users' + `, + errors: [{ + message: 'Caution: `fn-get-users.js` has a default export `getUsers`. This imports `getUsers` as `findUsers`. Check if you meant to write `import getUsers from \'./no-rename-default/fn-get-users\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + test({ + code: ` + import findUsersSync from './no-rename-default/fn-get-users-sync' + `, + errors: [{ + message: 'Caution: `fn-get-users-sync.js` has a default export `getUsersSync`. This imports `getUsersSync` as `findUsersSync`. Check if you meant to write `import getUsersSync from \'./no-rename-default/fn-get-users-sync\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + ], +}); + +// REQUIRE { commonjs: true } +// fn-get-users.js +// fn-get-users-sync.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const getUsers = require('./no-rename-default/fn-get-users') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const getUsersSync = require('./no-rename-default/fn-get-users-sync') + `, + options: [{ commonjs: true }], + }), + ], + invalid: [ + test({ + code: ` + const findUsers = require('./no-rename-default/fn-get-users') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `fn-get-users.js` has a default export `getUsers`. This requires `getUsers` as `findUsers`. Check if you meant to write `const getUsers = require(\'./no-rename-default/fn-get-users\')` instead.', + type: 'VariableDeclarator', + }], + }), + test({ + code: ` + const findUsersSync = require('./no-rename-default/fn-get-users-sync') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `fn-get-users-sync.js` has a default export `getUsersSync`. This requires `getUsersSync` as `findUsersSync`. Check if you meant to write `const getUsersSync = require(\'./no-rename-default/fn-get-users-sync\')` instead.', + type: 'VariableDeclarator', + }], + }), + ], +}); + +// IMPORT +// generator-reader.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import reader from './no-rename-default/generator-reader' + `, + }), + ], + invalid: [ + test({ + code: ` + import myReader from './no-rename-default/generator-reader' + `, + errors: [{ + message: 'Caution: `generator-reader.js` has a default export `reader`. This imports `reader` as `myReader`. Check if you meant to write `import reader from \'./no-rename-default/generator-reader\'` instead.', + type: 'ImportDefaultSpecifier', + }], + }), + ], +}); + +// REQUIRE { commonjs: true } +// generator-reader.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const reader = require('./no-rename-default/generator-reader') + `, + options: [{ commonjs: true }], + }), + ], + invalid: [ + test({ + code: ` + const myReader = require('./no-rename-default/generator-reader') + `, + options: [{ commonjs: true }], + errors: [{ + message: 'Caution: `generator-reader.js` has a default export `reader`. This requires `reader` as `myReader`. Check if you meant to write `const reader = require(\'./no-rename-default/generator-reader\')` instead.', + type: 'VariableDeclarator', + }], + }), + ], +}); + +//------------------------------------------------------------------------------ +// PR_FEEDBACK +//------------------------------------------------------------------------------ + +// IMPORT +// binding-const-rename-fn.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import foo from './no-rename-default/pr-3006-feedback/binding-const-rename-fn' + `, + }), + ], + invalid: [], +}); + +// REQUIRE { commonjs: true } +// binding-const-rename-fn.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const foo = require('./no-rename-default/pr-3006-feedback/binding-const-rename-fn') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + ], + invalid: [], +}); + +// IMPORT +// binding-hoc-with-logger-for-foo.js +// binding-hoc-with-logger-for-get-users.js +// binding-hoc-with-logger-with-auth-for-get-users.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import foo from './no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-foo' + `, + }), + test({ + code: ` + import getUsers from './no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-get-users' + `, + }), + test({ + code: ` + import getUsers from './no-rename-default/pr-3006-feedback/binding-hoc-with-logger-with-auth-for-get-users' + `, + }), + ], + invalid: [ + + ], +}); + +// REQUIRE { commonjs: true } +// binding-hoc-with-logger-for-foo.js +// binding-hoc-with-logger-for-get-users.js +// binding-hoc-with-logger-with-auth-for-get-users.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const foo = require('./no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-foo') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const getUsers = require('./no-rename-default/pr-3006-feedback/binding-hoc-with-logger-for-get-users') + `, + options: [{ commonjs: true }], + }), + test({ + code: ` + const getUsers = require('./no-rename-default/pr-3006-feedback/binding-hoc-with-logger-with-auth-for-get-users') + `, + options: [{ commonjs: true }], + }), + ], + invalid: [], +}); + +// IMPORT { preventRenamingBindings: false } +// binding-fn-rename.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import _ from './no-rename-default/pr-3006-feedback/binding-fn-rename' + `, + options: [{ preventRenamingBindings: false }], + }), + ], + invalid: [], +}); + +// REQUIRE { commonjs: true, preventRenamingBindings: false } +// binding-fn-rename.js +ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + const _ = require('./no-rename-default/pr-3006-feedback/binding-fn-rename') + `, + options: [{ commonjs: true, preventRenamingBindings: false }], + }), + ], + invalid: [], +}); + +context('TypeScript', function () { + // IMPORT + // typescript-default.d.ts + getTSParsers().forEach((parser) => { + ruleTester.run('no-rename-default', rule, { + valid: [ + test({ + code: ` + import foo from './no-rename-default/typescript-default' + `, + parser, + settings: { + 'import/parsers': { [parser]: ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + ], + invalid: [], + }); + }); +});