routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+118
@@ -0,0 +1,118 @@
|
||||
import {isCommaToken} from '@eslint-community/eslint-utils';
|
||||
import {isEmptyObjectExpression} from './ast/index.js';
|
||||
import {removeObjectProperty} from './fix/index.js';
|
||||
import {getParentheses} from './utils/index.js';
|
||||
|
||||
const MESSAGE_ID = 'require-module-attributes';
|
||||
const messages = {
|
||||
[MESSAGE_ID]: '{{type}} with empty attribute list is not allowed.',
|
||||
};
|
||||
|
||||
const isWithToken = token => token?.type === 'Keyword' && token.value === 'with';
|
||||
|
||||
/** @param {import('eslint').Rule.RuleContext} context */
|
||||
const create = context => {
|
||||
const {sourceCode} = context;
|
||||
|
||||
context.on(['ImportDeclaration', 'ExportNamedDeclaration', 'ExportAllDeclaration'], declaration => {
|
||||
const {source, attributes} = declaration;
|
||||
|
||||
if (!source || (Array.isArray(attributes) && attributes.length > 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const withToken = sourceCode.getTokenAfter(source);
|
||||
|
||||
if (!isWithToken(withToken)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// `WithStatement` is not possible in modules, so we don't need worry it's not attributes
|
||||
|
||||
const openingBraceToken = sourceCode.getTokenAfter(withToken);
|
||||
const closingBraceToken = sourceCode.getTokenAfter(openingBraceToken);
|
||||
|
||||
return {
|
||||
node: declaration,
|
||||
loc: {
|
||||
start: sourceCode.getLoc(openingBraceToken).start,
|
||||
end: sourceCode.getLoc(closingBraceToken).end,
|
||||
},
|
||||
messageId: MESSAGE_ID,
|
||||
data: {
|
||||
type: declaration.type === 'ImportDeclaration' ? 'import statement' : 'export statement',
|
||||
},
|
||||
/** @param {import('eslint').Rule.RuleFixer} fixer */
|
||||
fix: fixer => [withToken, closingBraceToken, openingBraceToken].map(token => fixer.remove(token)),
|
||||
};
|
||||
});
|
||||
|
||||
context.on('ImportExpression', importExpression => {
|
||||
const {options: optionsNode} = importExpression;
|
||||
|
||||
if (optionsNode?.type !== 'ObjectExpression') {
|
||||
return;
|
||||
}
|
||||
|
||||
const emptyWithProperty = optionsNode.properties.find(property =>
|
||||
property.type === 'Property'
|
||||
&& !property.method
|
||||
&& !property.shorthand
|
||||
&& !property.computed
|
||||
&& property.kind === 'init'
|
||||
&& (
|
||||
(
|
||||
property.key.type === 'Identifier'
|
||||
&& property.key.name === 'with'
|
||||
)
|
||||
|| (
|
||||
property.key.type === 'Literal'
|
||||
&& property.key.value === 'with'
|
||||
)
|
||||
)
|
||||
&& isEmptyObjectExpression(property.value));
|
||||
|
||||
const nodeToRemove = optionsNode.properties.length === 0 || (emptyWithProperty && optionsNode.properties.length === 1)
|
||||
? optionsNode
|
||||
: emptyWithProperty;
|
||||
|
||||
if (!nodeToRemove) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isProperty = nodeToRemove.type === 'Property';
|
||||
|
||||
return {
|
||||
node: emptyWithProperty?.value ?? nodeToRemove,
|
||||
messageId: MESSAGE_ID,
|
||||
data: {
|
||||
type: 'import expression',
|
||||
},
|
||||
/** @param {import('eslint').Rule.RuleFixer} fixer */
|
||||
fix: fixer => isProperty
|
||||
? removeObjectProperty(fixer, nodeToRemove, context)
|
||||
: [
|
||||
// Comma token before
|
||||
sourceCode.getTokenBefore(nodeToRemove, isCommaToken),
|
||||
...sourceCode.getTokens(nodeToRemove),
|
||||
...getParentheses(nodeToRemove, context),
|
||||
].map(token => fixer.remove(token)),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
const config = {
|
||||
create,
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Require non-empty module attributes for imports and exports',
|
||||
recommended: 'unopinionated',
|
||||
},
|
||||
fixable: 'code',
|
||||
messages,
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
Reference in New Issue
Block a user