eslint-plugin-unicorn-x
Version:
More than 100 powerful ESLint rules
124 lines (107 loc) • 3.15 kB
JavaScript
import {removeSpecifier} from './fix/index.js';
import assertToken from './utils/assert-token.js';
const MESSAGE_ID = 'no-named-default';
const messages = {
[MESSAGE_ID]: 'Prefer using the default {{type}} over named {{type}}.',
};
const isValueImport = (node) => !node.importKind || node.importKind === 'value';
const isValueExport = (node) => !node.exportKind || node.exportKind === 'value';
const fixImportSpecifier = (importSpecifier, {sourceCode}) =>
function* (fixer) {
const declaration = importSpecifier.parent;
yield* removeSpecifier(
importSpecifier,
fixer,
sourceCode,
/* keepDeclaration */ true,
);
const nameText = sourceCode.getText(importSpecifier.local);
const hasDefaultImport = declaration.specifiers.some(
({type}) => type === 'ImportDefaultSpecifier',
);
// Insert a new `ImportDeclaration`
if (hasDefaultImport) {
const fromToken = sourceCode.getTokenBefore(
declaration.source,
(token) => token.type === 'Identifier' && token.value === 'from',
);
const [startOfFromToken] = sourceCode.getRange(fromToken);
const [, endOfDeclaration] = sourceCode.getRange(declaration);
const text = `import ${nameText} ${sourceCode.text.slice(startOfFromToken, endOfDeclaration)}`;
yield fixer.insertTextBefore(declaration, `${text}\n`);
return;
}
const importToken = sourceCode.getFirstToken(declaration);
assertToken(importToken, {
expected: {type: 'Keyword', value: 'import'},
ruleId: 'no-named-default',
});
const shouldAddComma = declaration.specifiers.some(
(specifier) =>
specifier !== importSpecifier &&
specifier.type === importSpecifier.type,
);
yield fixer.insertTextAfter(
importToken,
` ${nameText}${shouldAddComma ? ',' : ''}`,
);
};
const fixExportSpecifier = (exportSpecifier, {sourceCode}) =>
function* (fixer) {
const declaration = exportSpecifier.parent;
yield* removeSpecifier(exportSpecifier, fixer, sourceCode);
const text = `export default ${sourceCode.getText(exportSpecifier.local)};`;
yield fixer.insertTextBefore(declaration, `${text}\n`);
};
/** @param {import('eslint').Rule.RuleContext} context */
const create = (context) => ({
ImportSpecifier(specifier) {
if (
!(
isValueImport(specifier) &&
specifier.imported.name === 'default' &&
isValueImport(specifier.parent)
)
) {
return;
}
return {
node: specifier,
messageId: MESSAGE_ID,
data: {type: 'import'},
fix: fixImportSpecifier(specifier, context),
};
},
ExportSpecifier(specifier) {
if (
!(
isValueExport(specifier) &&
specifier.exported.name === 'default' &&
isValueExport(specifier.parent) &&
!specifier.parent.source
)
) {
return;
}
return {
node: specifier,
messageId: MESSAGE_ID,
data: {type: 'export'},
fix: fixExportSpecifier(specifier, context),
};
},
});
/** @type {import('eslint').Rule.RuleModule} */
const config = {
create,
meta: {
type: 'suggestion',
docs: {
description: 'Disallow named usage of default import and export.',
recommended: true,
},
fixable: 'code',
messages,
},
};
export default config;