From ff43745773606499bad85c71c4c131ab78ea75da Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 2 Nov 2021 00:39:49 +0800 Subject: [PATCH] Add `prefer-export-from` rule (#1453) --- configs/recommended.js | 1 + docs/rules/prefer-export-from.md | 61 ++ readme.md | 2 + rules/prefer-export-from.js | 288 ++++++ test/prefer-export-from.mjs | 287 ++++++ test/snapshots/prefer-export-from.mjs.md | 1048 ++++++++++++++++++++ test/snapshots/prefer-export-from.mjs.snap | Bin 0 -> 2558 bytes test/utils/test.mjs | 2 +- 8 files changed, 1688 insertions(+), 1 deletion(-) create mode 100644 docs/rules/prefer-export-from.md create mode 100644 rules/prefer-export-from.js create mode 100644 test/prefer-export-from.mjs create mode 100644 test/snapshots/prefer-export-from.mjs.md create mode 100644 test/snapshots/prefer-export-from.mjs.snap diff --git a/configs/recommended.js b/configs/recommended.js index 47ff8200be..3985e9232a 100644 --- a/configs/recommended.js +++ b/configs/recommended.js @@ -63,6 +63,7 @@ module.exports = { 'unicorn/prefer-dom-node-dataset': 'error', 'unicorn/prefer-dom-node-remove': 'error', 'unicorn/prefer-dom-node-text-content': 'error', + 'unicorn/prefer-export-from': 'error', 'unicorn/prefer-includes': 'error', 'unicorn/prefer-keyboard-event-key': 'error', 'unicorn/prefer-math-trunc': 'error', diff --git a/docs/rules/prefer-export-from.md b/docs/rules/prefer-export-from.md new file mode 100644 index 0000000000..2930e5e168 --- /dev/null +++ b/docs/rules/prefer-export-from.md @@ -0,0 +1,61 @@ +# Prefer `export…from` when re-exporting + +When re-exporting from a module, it's unnecessary to import and then export. It can be done in a single `export…from` declaration. + +This rule is fixable. + +## Fail + +```js +import defaultExport from './foo.js'; +export default defaultExport; +``` + +```js +import {named} from './foo.js'; +export {named}; +``` + +```js +import * as namespace from './foo.js'; +export {namespace}; +``` + +```js +import defaultExport, {named} from './foo.js'; +export default defaultExport; +export { + defaultExport as renamedDefault, + named, + named as renamedNamed, +}; +``` + +## Pass + +```js +export {default} from './foo.js'; +``` + +```js +export {named} from './foo.js'; +``` + +```js +export * as namespace from './foo.js'; +``` + +```js +export { + default, + default as renamedDefault, + named, + named as renamedNamed, +} from './foo.js'; +``` + +```js +// There is no substitution +import * as namespace from './foo.js'; +export default namespace; +``` diff --git a/readme.md b/readme.md index 38a8e72eda..9ab5ce97e5 100644 --- a/readme.md +++ b/readme.md @@ -95,6 +95,7 @@ Configure it in `package.json`. "unicorn/prefer-dom-node-dataset": "error", "unicorn/prefer-dom-node-remove": "error", "unicorn/prefer-dom-node-text-content": "error", + "unicorn/prefer-export-from": "error", "unicorn/prefer-includes": "error", "unicorn/prefer-keyboard-event-key": "error", "unicorn/prefer-math-trunc": "error", @@ -216,6 +217,7 @@ Each rule has emojis denoting: | [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over `.setAttribute(…)`. | ✅ | 🔧 | | | [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | | [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | | | [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | | [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | | [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | diff --git a/rules/prefer-export-from.js b/rules/prefer-export-from.js new file mode 100644 index 0000000000..db03914d9f --- /dev/null +++ b/rules/prefer-export-from.js @@ -0,0 +1,288 @@ +'use strict'; +const { + isCommaToken, + isOpeningBraceToken, + isClosingBraceToken, +} = require('eslint-utils'); + +const MESSAGE_ID = 'prefer-export-from'; +const messages = { + [MESSAGE_ID]: 'Use `export…from` to re-export `{{exported}}`.', +}; + +function * removeSpecifier(node, fixer, sourceCode) { + const {parent} = node; + const {specifiers} = parent; + + if (specifiers.length === 1) { + yield * removeImportOrExport(parent, fixer, sourceCode); + return; + } + + switch (node.type) { + case 'ImportSpecifier': { + const hasOtherSpecifiers = specifiers.some(specifier => specifier !== node && specifier.type === node.type); + if (!hasOtherSpecifiers) { + const closingBraceToken = sourceCode.getTokenAfter(node, isClosingBraceToken); + + // If there are other specifiers, they have to be the default import specifier + // And the default import has to write before the named import specifiers + // So there must be a comma before + const commaToken = sourceCode.getTokenBefore(node, isCommaToken); + yield fixer.replaceTextRange([commaToken.range[0], closingBraceToken.range[1]], ''); + return; + } + // Fallthrough + } + + case 'ExportSpecifier': + case 'ImportNamespaceSpecifier': + case 'ImportDefaultSpecifier': { + yield fixer.remove(node); + + const tokenAfter = sourceCode.getTokenAfter(node); + if (isCommaToken(tokenAfter)) { + yield fixer.remove(tokenAfter); + } + + break; + } + + // No default + } +} + +function * removeImportOrExport(node, fixer, sourceCode) { + switch (node.type) { + case 'ImportSpecifier': + case 'ExportSpecifier': + case 'ImportDefaultSpecifier': + case 'ImportNamespaceSpecifier': { + yield * removeSpecifier(node, fixer, sourceCode); + return; + } + + case 'ImportDeclaration': + case 'ExportDefaultDeclaration': + case 'ExportNamedDeclaration': { + yield fixer.remove(node); + } + + // No default + } +} + +function fix({ + context, + imported, + exported, + exportDeclarations, + program, +}) { + const sourceCode = context.getSourceCode(); + const sourceNode = imported.declaration.source; + const sourceValue = sourceNode.value; + const sourceText = sourceCode.getText(sourceNode); + const exportDeclaration = exportDeclarations.find(({source}) => source.value === sourceValue); + + /** @param {import('eslint').Rule.RuleFixer} fixer */ + return function * (fixer) { + if (imported.name === '*') { + yield fixer.insertTextAfter( + program, + `\nexport * as ${exported.name} from ${sourceText};`, + ); + } else { + const specifier = exported.name === imported.name + ? exported.name + : `${imported.name} as ${exported.name}`; + + if (exportDeclaration) { + const lastSpecifier = exportDeclaration.specifiers[exportDeclaration.specifiers.length - 1]; + + // `export {} from 'foo';` + if (lastSpecifier) { + yield fixer.insertTextAfter(lastSpecifier, `, ${specifier}`); + } else { + const openingBraceToken = sourceCode.getFirstToken(exportDeclaration, isOpeningBraceToken); + yield fixer.insertTextAfter(openingBraceToken, specifier); + } + } else { + yield fixer.insertTextAfter( + program, + `\nexport {${specifier}} from ${sourceText};`, + ); + } + } + + if (imported.variable.references.length === 1) { + yield * removeImportOrExport(imported.node, fixer, sourceCode); + } + + yield * removeImportOrExport(exported.node, fixer, sourceCode); + }; +} + +function getImportedName(specifier) { + switch (specifier.type) { + case 'ImportDefaultSpecifier': + return 'default'; + + case 'ImportSpecifier': + return specifier.imported.name; + + case 'ImportNamespaceSpecifier': + return '*'; + + // No default + } +} + +function getExported(identifier, context) { + const {parent} = identifier; + switch (parent.type) { + case 'ExportDefaultDeclaration': + return { + node: parent, + name: 'default', + }; + + case 'ExportSpecifier': + return { + node: parent, + name: parent.exported.name, + }; + + case 'VariableDeclarator': { + if ( + parent.init === identifier + && parent.id.type === 'Identifier' + && parent.parent.type === 'VariableDeclaration' + && parent.parent.kind === 'const' + && parent.parent.declarations.length === 1 + && parent.parent.declarations[0] === parent + && parent.parent.parent.type === 'ExportNamedDeclaration' + && isVariableUnused(parent, context) + ) { + return { + node: parent.parent.parent, + name: parent.id.name, + }; + } + + break; + } + + // No default + } +} + +function isVariableUnused(node, context) { + const variables = context.getDeclaredVariables(node); + + /* istanbul ignore next */ + if (variables.length !== 1) { + return false; + } + + const [{identifiers, references}] = variables; + return identifiers.length === 1 + && identifiers[0] === node.id + && references.length === 1 + && references[0].identifier === node.id; +} + +function * getProblems({ + context, + variable, + program, + exportDeclarations, +}) { + const {identifiers, references} = variable; + + if (identifiers.length !== 1 || references.length === 0) { + return; + } + + const specifier = identifiers[0].parent; + + const imported = { + name: getImportedName(specifier), + node: specifier, + declaration: specifier.parent, + variable, + }; + + for (const {identifier} of references) { + const exported = getExported(identifier, context); + + if (!exported) { + continue; + } + + /* + There is no substitution for: + + ```js + import * as foo from 'foo'; + export default foo; + ``` + */ + if (imported.name === '*' && exported.name === 'default') { + return; + } + + yield { + node: exported.node, + messageId: MESSAGE_ID, + data: { + exported: exported.name, + }, + fix: fix({ + context, + imported, + exported, + exportDeclarations, + program, + }), + }; + } +} + +/** @param {import('eslint').Rule.RuleContext} context */ +function create(context) { + const variables = []; + const exportDeclarations = []; + + return { + 'ImportDeclaration[specifiers.length>0]'(node) { + variables.push(...context.getDeclaredVariables(node)); + }, + // `ExportAllDeclaration` and `ExportDefaultDeclaration` can't be reused + 'ExportNamedDeclaration[source.type="Literal"]'(node) { + exportDeclarations.push(node); + }, + * 'Program:exit'(program) { + for (const variable of variables) { + yield * getProblems({ + context, + variable, + exportDeclarations, + program, + }); + } + }, + }; +} + +module.exports = { + create, + meta: { + type: 'suggestion', + docs: { + description: 'Prefer `export…from` when re-exporting.', + }, + fixable: 'code', + messages, + }, +}; diff --git a/test/prefer-export-from.mjs b/test/prefer-export-from.mjs new file mode 100644 index 0000000000..fee5beb222 --- /dev/null +++ b/test/prefer-export-from.mjs @@ -0,0 +1,287 @@ +import outdent from 'outdent'; +import {getTester} from './utils/test.mjs'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + 'import "foo";', + 'import {} from "foo";', + 'import * as namespace from "foo";', + 'import defaultExport from "foo";', + 'import {named} from "foo";', + outdent` + const named = import(foo); + export {named}; + `, + 'export * from "foo";', + 'export {default} from "foo";', + 'export {named} from "foo";', + outdent` + const defaultExport = require('foo'); + export default defaultExport; + `, + + // Variable is not `const` + outdent` + import defaultExport from 'foo'; + export var variable = defaultExport; + `, + outdent` + import defaultExport from 'foo'; + export let variable = defaultExport; + `, + + // Exported variable is reused + outdent` + import defaultExport from 'foo'; + export const variable = defaultExport; + use(variable); + `, + outdent` + import defaultExport from 'foo'; + export let variable = defaultExport; + variable = 1; + `, + // Export namespace as default + outdent` + import * as namespace from 'foo'; + export default namespace; + `, + outdent` + import * as namespace from 'foo'; + export {namespace as default}; + `, + // Cases we are not handled + outdent` + import defaultExport from 'foo'; + const variable = defaultExport; + export {variable} + `, + outdent` + import defaultExport from 'foo'; + export const {variable} = {variable: defaultExport}; + `, + ], + invalid: [ + // `default` + outdent` + import defaultExport from 'foo'; + export default defaultExport; + `, + outdent` + import defaultExport from 'foo'; + export {defaultExport as default}; + `, + outdent` + import defaultExport from 'foo'; + export {defaultExport as named}; + `, + outdent` + import defaultExport from 'foo'; + export const variable = defaultExport; + `, + outdent` + import {default as defaultExport} from 'foo'; + export default defaultExport; + `, + outdent` + import {default as defaultExport} from 'foo'; + export {defaultExport as default}; + `, + outdent` + import {default as defaultExport} from 'foo'; + export {defaultExport as named}; + `, + outdent` + import defaultExport from 'foo'; + export const variable = defaultExport; + `, + outdent` + import defaultExport from 'foo'; + defaultExport.bar = 1; + export {defaultExport as named}; + export {defaultExport as default}; + export const variable = defaultExport; + `, + // `named` + outdent` + import {named} from 'foo'; + export default named; + `, + outdent` + import {named} from 'foo'; + export {named as default}; + `, + outdent` + import {named} from 'foo'; + export {named as named}; + `, + outdent` + import {named} from 'foo'; + export {named as renamed}; + `, + outdent` + import {named} from 'foo'; + export const variable = named; + `, + outdent` + import {named} from 'foo'; + named.bar = 1; + export {named as named}; + export {named as default}; + export const variable = named; + `, + // Namespace + outdent` + import * as namespace from 'foo'; + export {namespace as namespace}; + `, + outdent` + import * as namespace from 'foo'; + export {namespace as renamed}; + `, + outdent` + import * as namespace from 'foo'; + export const variable = namespace; + `, + outdent` + import * as namespace from 'foo'; + namespace.bar = 1; + export {namespace as named}; + export {namespace as default}; + export const variable = namespace; + `, + // Some not exported + outdent` + import {named1, named2} from 'foo'; + export {named1}; + `, + outdent` + import defaultExport, {named} from 'foo'; + export {defaultExport}; + `, + outdent` + import defaultExport, {named} from 'foo'; + export {named}; + `, + outdent` + import defaultExport, * as namespace from 'foo'; + export {defaultExport}; + `, + // Existing export + outdent` + import * as foo from 'foo'; + export {foo}; + export * as bar from 'foo'; + `, + outdent` + import * as foo from 'foo'; + export {foo}; + export {bar} from 'foo'; + `, + outdent` + import * as foo from 'foo'; + export {foo}; + export {} from 'foo'; + `, + outdent` + import * as foo from 'foo'; + export {foo}; + export * from 'foo'; + `, + outdent` + import foo from 'foo'; + export {foo}; + export * as bar from 'foo'; + `, + outdent` + import foo from 'foo'; + export {foo}; + export {bar} from 'foo'; + `, + outdent` + import foo from 'foo'; + export {foo}; + export {bar,} from 'foo'; + `, + outdent` + import foo from 'foo'; + export {foo}; + export {} from 'foo'; + `, + outdent` + import foo from 'foo'; + export {foo}; + export * from 'foo'; + `, + // Multiple + outdent` + import {named1, named2} from 'foo'; + export {named1, named2}; + `, + outdent` + import {named} from 'foo'; + export {named as default, named}; + `, + outdent` + import {named, named as renamed} from 'foo'; + export {named, renamed}; + `, + outdent` + import defaultExport, {named1, named2} from 'foo'; + export {named1 as default}; + export {named2}; + export {defaultExport}; + `, + outdent` + import * as foo from 'foo'; + import * as bar from 'foo'; + export {foo, bar}; + `, + outdent` + import * as foo from 'foo'; + export {foo, foo as bar}; + `, + outdent` + import defaultExport from 'foo'; + export * from 'foo'; + export default defaultExport; + `, + outdent` + import defaultExport from 'foo'; + export {named} from 'foo'; + export * from 'foo'; + export default defaultExport; + `, + outdent` + import defaultExport from './foo.js'; + export {named} from './foo.js'; + export default defaultExport; + `, + outdent` + import defaultExport from './foo.js'; + export {named} from './foo.js?query'; + export default defaultExport; + `, + ], +}); + +// Strange case +// TODO: confirm how should this work +test.snapshot({ + valid: [ + outdent` + import * as namespace from 'foo'; + export default namespace; + export {namespace}; + `, + ], + invalid: [ + outdent` + import * as namespace from 'foo'; + export {namespace}; + export default namespace; + `, + ], +}); diff --git a/test/snapshots/prefer-export-from.mjs.md b/test/snapshots/prefer-export-from.mjs.md new file mode 100644 index 0000000000..19a478d4f4 --- /dev/null +++ b/test/snapshots/prefer-export-from.mjs.md @@ -0,0 +1,1048 @@ +# Snapshot report for `test/prefer-export-from.mjs` + +The actual snapshot is saved in `prefer-export-from.mjs.snap`. + +Generated by [AVA](https://avajs.dev). + +## Invalid #1 + 1 | import defaultExport from 'foo'; + 2 | export default defaultExport; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from 'foo';␊ + > 2 | export default defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #2 + 1 | import defaultExport from 'foo'; + 2 | export {defaultExport as default}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from 'foo';␊ + > 2 | export {defaultExport as default};␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #3 + 1 | import defaultExport from 'foo'; + 2 | export {defaultExport as named}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default as named} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from 'foo';␊ + > 2 | export {defaultExport as named};␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`named\`.␊ + ` + +## Invalid #4 + 1 | import defaultExport from 'foo'; + 2 | export const variable = defaultExport; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default as variable} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from 'foo';␊ + > 2 | export const variable = defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`variable\`.␊ + ` + +## Invalid #5 + 1 | import {default as defaultExport} from 'foo'; + 2 | export default defaultExport; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {default as defaultExport} from 'foo';␊ + > 2 | export default defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #6 + 1 | import {default as defaultExport} from 'foo'; + 2 | export {defaultExport as default}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {default as defaultExport} from 'foo';␊ + > 2 | export {defaultExport as default};␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #7 + 1 | import {default as defaultExport} from 'foo'; + 2 | export {defaultExport as named}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default as named} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {default as defaultExport} from 'foo';␊ + > 2 | export {defaultExport as named};␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`named\`.␊ + ` + +## Invalid #8 + 1 | import defaultExport from 'foo'; + 2 | export const variable = defaultExport; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default as variable} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from 'foo';␊ + > 2 | export const variable = defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`variable\`.␊ + ` + +## Invalid #9 + 1 | import defaultExport from 'foo'; + 2 | defaultExport.bar = 1; + 3 | export {defaultExport as named}; + 4 | export {defaultExport as default}; + 5 | export const variable = defaultExport; + +> Output + + `␊ + 1 | import defaultExport from 'foo';␊ + 2 | defaultExport.bar = 1;␊ + 3 |␊ + 4 |␊ + 5 |␊ + 6 | export {default as named, default, default as variable} from 'foo';␊ + ` + +> Error 1/3 + + `␊ + 1 | import defaultExport from 'foo';␊ + 2 | defaultExport.bar = 1;␊ + > 3 | export {defaultExport as named};␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`named\`.␊ + 4 | export {defaultExport as default};␊ + 5 | export const variable = defaultExport;␊ + ` + +> Error 2/3 + + `␊ + 1 | import defaultExport from 'foo';␊ + 2 | defaultExport.bar = 1;␊ + 3 | export {defaultExport as named};␊ + > 4 | export {defaultExport as default};␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + 5 | export const variable = defaultExport;␊ + ` + +> Error 3/3 + + `␊ + 1 | import defaultExport from 'foo';␊ + 2 | defaultExport.bar = 1;␊ + 3 | export {defaultExport as named};␊ + 4 | export {defaultExport as default};␊ + > 5 | export const variable = defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`variable\`.␊ + ` + +## Invalid #10 + 1 | import {named} from 'foo'; + 2 | export default named; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named as default} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {named} from 'foo';␊ + > 2 | export default named;␊ + | ^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #11 + 1 | import {named} from 'foo'; + 2 | export {named as default}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named as default} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {named} from 'foo';␊ + > 2 | export {named as default};␊ + | ^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #12 + 1 | import {named} from 'foo'; + 2 | export {named as named}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {named} from 'foo';␊ + > 2 | export {named as named};␊ + | ^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`named\`.␊ + ` + +## Invalid #13 + 1 | import {named} from 'foo'; + 2 | export {named as renamed}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named as renamed} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {named} from 'foo';␊ + > 2 | export {named as renamed};␊ + | ^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`renamed\`.␊ + ` + +## Invalid #14 + 1 | import {named} from 'foo'; + 2 | export const variable = named; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named as variable} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {named} from 'foo';␊ + > 2 | export const variable = named;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`variable\`.␊ + ` + +## Invalid #15 + 1 | import {named} from 'foo'; + 2 | named.bar = 1; + 3 | export {named as named}; + 4 | export {named as default}; + 5 | export const variable = named; + +> Output + + `␊ + 1 | import {named} from 'foo';␊ + 2 | named.bar = 1;␊ + 3 |␊ + 4 |␊ + 5 |␊ + 6 | export {named, named as default, named as variable} from 'foo';␊ + ` + +> Error 1/3 + + `␊ + 1 | import {named} from 'foo';␊ + 2 | named.bar = 1;␊ + > 3 | export {named as named};␊ + | ^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`named\`.␊ + 4 | export {named as default};␊ + 5 | export const variable = named;␊ + ` + +> Error 2/3 + + `␊ + 1 | import {named} from 'foo';␊ + 2 | named.bar = 1;␊ + 3 | export {named as named};␊ + > 4 | export {named as default};␊ + | ^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + 5 | export const variable = named;␊ + ` + +> Error 3/3 + + `␊ + 1 | import {named} from 'foo';␊ + 2 | named.bar = 1;␊ + 3 | export {named as named};␊ + 4 | export {named as default};␊ + > 5 | export const variable = named;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`variable\`.␊ + ` + +## Invalid #16 + 1 | import * as namespace from 'foo'; + 2 | export {namespace as namespace}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * as namespace from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as namespace from 'foo';␊ + > 2 | export {namespace as namespace};␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`namespace\`.␊ + ` + +## Invalid #17 + 1 | import * as namespace from 'foo'; + 2 | export {namespace as renamed}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * as renamed from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as namespace from 'foo';␊ + > 2 | export {namespace as renamed};␊ + | ^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`renamed\`.␊ + ` + +## Invalid #18 + 1 | import * as namespace from 'foo'; + 2 | export const variable = namespace; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * as variable from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as namespace from 'foo';␊ + > 2 | export const variable = namespace;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`variable\`.␊ + ` + +## Invalid #19 + 1 | import * as namespace from 'foo'; + 2 | namespace.bar = 1; + 3 | export {namespace as named}; + 4 | export {namespace as default}; + 5 | export const variable = namespace; + +> Output + + `␊ + 1 | import * as namespace from 'foo';␊ + 2 | namespace.bar = 1;␊ + 3 |␊ + 4 | export {namespace as default};␊ + 5 | export const variable = namespace;␊ + 6 | export * as named from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as namespace from 'foo';␊ + 2 | namespace.bar = 1;␊ + > 3 | export {namespace as named};␊ + | ^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`named\`.␊ + 4 | export {namespace as default};␊ + 5 | export const variable = namespace;␊ + ` + +## Invalid #20 + 1 | import {named1, named2} from 'foo'; + 2 | export {named1}; + +> Output + + `␊ + 1 | import { named2} from 'foo';␊ + 2 |␊ + 3 | export {named1} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import {named1, named2} from 'foo';␊ + > 2 | export {named1};␊ + | ^^^^^^ Use \`export…from\` to re-export \`named1\`.␊ + ` + +## Invalid #21 + 1 | import defaultExport, {named} from 'foo'; + 2 | export {defaultExport}; + +> Output + + `␊ + 1 | import {named} from 'foo';␊ + 2 |␊ + 3 | export {default as defaultExport} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport, {named} from 'foo';␊ + > 2 | export {defaultExport};␊ + | ^^^^^^^^^^^^^ Use \`export…from\` to re-export \`defaultExport\`.␊ + ` + +## Invalid #22 + 1 | import defaultExport, {named} from 'foo'; + 2 | export {named}; + +> Output + + `␊ + 1 | import defaultExport from 'foo';␊ + 2 |␊ + 3 | export {named} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport, {named} from 'foo';␊ + > 2 | export {named};␊ + | ^^^^^ Use \`export…from\` to re-export \`named\`.␊ + ` + +## Invalid #23 + 1 | import defaultExport, * as namespace from 'foo'; + 2 | export {defaultExport}; + +> Output + + `␊ + 1 | import * as namespace from 'foo';␊ + 2 |␊ + 3 | export {default as defaultExport} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport, * as namespace from 'foo';␊ + > 2 | export {defaultExport};␊ + | ^^^^^^^^^^^^^ Use \`export…from\` to re-export \`defaultExport\`.␊ + ` + +## Invalid #24 + 1 | import * as foo from 'foo'; + 2 | export {foo}; + 3 | export * as bar from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * as bar from 'foo';␊ + 4 | export * as foo from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export * as bar from 'foo';␊ + ` + +## Invalid #25 + 1 | import * as foo from 'foo'; + 2 | export {foo}; + 3 | export {bar} from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {bar} from 'foo';␊ + 4 | export * as foo from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export {bar} from 'foo';␊ + ` + +## Invalid #26 + 1 | import * as foo from 'foo'; + 2 | export {foo}; + 3 | export {} from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {} from 'foo';␊ + 4 | export * as foo from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export {} from 'foo';␊ + ` + +## Invalid #27 + 1 | import * as foo from 'foo'; + 2 | export {foo}; + 3 | export * from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * from 'foo';␊ + 4 | export * as foo from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export * from 'foo';␊ + ` + +## Invalid #28 + 1 | import foo from 'foo'; + 2 | export {foo}; + 3 | export * as bar from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * as bar from 'foo';␊ + 4 | export {default as foo} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export * as bar from 'foo';␊ + ` + +## Invalid #29 + 1 | import foo from 'foo'; + 2 | export {foo}; + 3 | export {bar} from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {bar, default as foo} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export {bar} from 'foo';␊ + ` + +## Invalid #30 + 1 | import foo from 'foo'; + 2 | export {foo}; + 3 | export {bar,} from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {bar, default as foo,} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export {bar,} from 'foo';␊ + ` + +## Invalid #31 + 1 | import foo from 'foo'; + 2 | export {foo}; + 3 | export {} from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {default as foo} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export {} from 'foo';␊ + ` + +## Invalid #32 + 1 | import foo from 'foo'; + 2 | export {foo}; + 3 | export * from 'foo'; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * from 'foo';␊ + 4 | export {default as foo} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import foo from 'foo';␊ + > 2 | export {foo};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + 3 | export * from 'foo';␊ + ` + +## Invalid #33 + 1 | import {named1, named2} from 'foo'; + 2 | export {named1, named2}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named1, named2} from 'foo';␊ + ` + +> Error 1/2 + + `␊ + 1 | import {named1, named2} from 'foo';␊ + > 2 | export {named1, named2};␊ + | ^^^^^^ Use \`export…from\` to re-export \`named1\`.␊ + ` + +> Error 2/2 + + `␊ + 1 | import {named1, named2} from 'foo';␊ + > 2 | export {named1, named2};␊ + | ^^^^^^ Use \`export…from\` to re-export \`named2\`.␊ + ` + +## Invalid #34 + 1 | import {named} from 'foo'; + 2 | export {named as default, named}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named as default, named} from 'foo';␊ + ` + +> Error 1/2 + + `␊ + 1 | import {named} from 'foo';␊ + > 2 | export {named as default, named};␊ + | ^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +> Error 2/2 + + `␊ + 1 | import {named} from 'foo';␊ + > 2 | export {named as default, named};␊ + | ^^^^^ Use \`export…from\` to re-export \`named\`.␊ + ` + +## Invalid #35 + 1 | import {named, named as renamed} from 'foo'; + 2 | export {named, renamed}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export {named, named as renamed} from 'foo';␊ + ` + +> Error 1/2 + + `␊ + 1 | import {named, named as renamed} from 'foo';␊ + > 2 | export {named, renamed};␊ + | ^^^^^ Use \`export…from\` to re-export \`named\`.␊ + ` + +> Error 2/2 + + `␊ + 1 | import {named, named as renamed} from 'foo';␊ + > 2 | export {named, renamed};␊ + | ^^^^^^^ Use \`export…from\` to re-export \`renamed\`.␊ + ` + +## Invalid #36 + 1 | import defaultExport, {named1, named2} from 'foo'; + 2 | export {named1 as default}; + 3 | export {named2}; + 4 | export {defaultExport}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 |␊ + 4 |␊ + 5 | export {default as defaultExport, named1 as default, named2} from 'foo';␊ + ` + +> Error 1/3 + + `␊ + 1 | import defaultExport, {named1, named2} from 'foo';␊ + > 2 | export {named1 as default};␊ + | ^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + 3 | export {named2};␊ + 4 | export {defaultExport};␊ + ` + +> Error 2/3 + + `␊ + 1 | import defaultExport, {named1, named2} from 'foo';␊ + 2 | export {named1 as default};␊ + > 3 | export {named2};␊ + | ^^^^^^ Use \`export…from\` to re-export \`named2\`.␊ + 4 | export {defaultExport};␊ + ` + +> Error 3/3 + + `␊ + 1 | import defaultExport, {named1, named2} from 'foo';␊ + 2 | export {named1 as default};␊ + 3 | export {named2};␊ + > 4 | export {defaultExport};␊ + | ^^^^^^^^^^^^^ Use \`export…from\` to re-export \`defaultExport\`.␊ + ` + +## Invalid #37 + 1 | import * as foo from 'foo'; + 2 | import * as bar from 'foo'; + 3 | export {foo, bar}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 |␊ + 4 | export * as foo from 'foo';␊ + 5 | export * as bar from 'foo';␊ + ` + +> Error 1/2 + + `␊ + 1 | import * as foo from 'foo';␊ + 2 | import * as bar from 'foo';␊ + > 3 | export {foo, bar};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + ` + +> Error 2/2 + + `␊ + 1 | import * as foo from 'foo';␊ + 2 | import * as bar from 'foo';␊ + > 3 | export {foo, bar};␊ + | ^^^ Use \`export…from\` to re-export \`bar\`.␊ + ` + +## Invalid #38 + 1 | import * as foo from 'foo'; + 2 | export {foo, foo as bar}; + +> Output + + `␊ + 1 |␊ + 2 |␊ + 3 | export * as foo from 'foo';␊ + 4 | export * as bar from 'foo';␊ + ` + +> Error 1/2 + + `␊ + 1 | import * as foo from 'foo';␊ + > 2 | export {foo, foo as bar};␊ + | ^^^ Use \`export…from\` to re-export \`foo\`.␊ + ` + +> Error 2/2 + + `␊ + 1 | import * as foo from 'foo';␊ + > 2 | export {foo, foo as bar};␊ + | ^^^^^^^^^^ Use \`export…from\` to re-export \`bar\`.␊ + ` + +## Invalid #39 + 1 | import defaultExport from 'foo'; + 2 | export * from 'foo'; + 3 | export default defaultExport; + +> Output + + `␊ + 1 |␊ + 2 | export * from 'foo';␊ + 3 |␊ + 4 | export {default} from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from 'foo';␊ + 2 | export * from 'foo';␊ + > 3 | export default defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #40 + 1 | import defaultExport from 'foo'; + 2 | export {named} from 'foo'; + 3 | export * from 'foo'; + 4 | export default defaultExport; + +> Output + + `␊ + 1 |␊ + 2 | export {named, default} from 'foo';␊ + 3 | export * from 'foo';␊ + 4 |␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from 'foo';␊ + 2 | export {named} from 'foo';␊ + 3 | export * from 'foo';␊ + > 4 | export default defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #41 + 1 | import defaultExport from './foo.js'; + 2 | export {named} from './foo.js'; + 3 | export default defaultExport; + +> Output + + `␊ + 1 |␊ + 2 | export {named, default} from './foo.js';␊ + 3 |␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from './foo.js';␊ + 2 | export {named} from './foo.js';␊ + > 3 | export default defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #42 + 1 | import defaultExport from './foo.js'; + 2 | export {named} from './foo.js?query'; + 3 | export default defaultExport; + +> Output + + `␊ + 1 |␊ + 2 | export {named} from './foo.js?query';␊ + 3 |␊ + 4 | export {default} from './foo.js';␊ + ` + +> Error 1/1 + + `␊ + 1 | import defaultExport from './foo.js';␊ + 2 | export {named} from './foo.js?query';␊ + > 3 | export default defaultExport;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`export…from\` to re-export \`default\`.␊ + ` + +## Invalid #1 + 1 | import * as namespace from 'foo'; + 2 | export {namespace}; + 3 | export default namespace; + +> Output + + `␊ + 1 | import * as namespace from 'foo';␊ + 2 |␊ + 3 | export default namespace;␊ + 4 | export * as namespace from 'foo';␊ + ` + +> Error 1/1 + + `␊ + 1 | import * as namespace from 'foo';␊ + > 2 | export {namespace};␊ + | ^^^^^^^^^ Use \`export…from\` to re-export \`namespace\`.␊ + 3 | export default namespace;␊ + ` diff --git a/test/snapshots/prefer-export-from.mjs.snap b/test/snapshots/prefer-export-from.mjs.snap new file mode 100644 index 0000000000000000000000000000000000000000..2b105207bbee6a01be8569ff67b7611402e64996 GIT binary patch literal 2558 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 U8gso6vQRPqU!xi2@Mt^$0IZPi2><{9 literal 0 HcmV?d00001 diff --git a/test/utils/test.mjs b/test/utils/test.mjs index 303844d562..9ec01ca8ad 100644 --- a/test/utils/test.mjs +++ b/test/utils/test.mjs @@ -161,5 +161,5 @@ const avoidTestTitleConflict = (tests, comment) => { export { getTester, avoidTestTitleConflict, - parsers, }; +export {default as parsers} from './parsers.mjs';