eslint-plugin-svelte
Version:
ESLint plugin for Svelte using AST
111 lines (110 loc) • 3.74 kB
JavaScript
import { createRule } from '../utils/index.js';
import { findAttribute, findShorthandAttribute, findBindDirective, getStaticAttributeValue } from '../utils/ast-utils.js';
export default createRule('button-has-type', {
meta: {
docs: {
description: 'disallow usage of button without an explicit type attribute',
category: 'Best Practices',
recommended: false
},
schema: [
{
type: 'object',
properties: {
button: {
type: 'boolean'
},
submit: {
type: 'boolean'
},
reset: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
missingTypeAttribute: 'Missing an explicit type attribute for button.',
invalidTypeAttribute: '{{value}} is an invalid value for button type attribute.',
forbiddenTypeAttribute: '{{value}} is a forbidden value for button type attribute.',
emptyTypeAttribute: 'A value must be set for button type attribute.'
},
type: 'suggestion' // "problem",
},
create(context) {
const configuration = {
button: true,
submit: true,
reset: true,
...(context.options[0] ?? {})
};
/**
* Checks whether given text is known button type
*/
function isButtonType(type) {
return type === 'button' || type === 'submit' || type === 'reset';
}
/**
* Report
*/
function report(node, messageId, data = {}) {
context.report({
node,
messageId,
data
});
}
/**
* Validate attribute
*/
function validateAttribute(attribute) {
if (attribute.value.length === 0) {
report(attribute, 'emptyTypeAttribute');
return;
}
const strValue = getStaticAttributeValue(attribute);
if (strValue == null) {
return;
}
if (!isButtonType(strValue)) {
report(attribute, 'invalidTypeAttribute', { value: strValue });
}
else if (!configuration[strValue]) {
report(attribute, 'forbiddenTypeAttribute', { value: strValue });
}
}
/**
* @param {VDirective} directive
*/
function validateDirective(directive) {
if (!directive.expression) {
report(directive, 'emptyTypeAttribute');
}
}
return {
"SvelteElement[name.name='button'] > SvelteStartTag"(node) {
const typeAttr = findAttribute(node, 'type');
if (typeAttr) {
validateAttribute(typeAttr);
return;
}
const typeDir = findBindDirective(node, 'type');
if (typeDir) {
validateDirective(typeDir);
return;
}
const typeShortAttr = findShorthandAttribute(node, 'type');
if (typeShortAttr) {
return;
}
for (const attr of node.attributes) {
if (attr.type === 'SvelteSpreadAttribute') {
return;
}
}
report(node, 'missingTypeAttribute');
}
};
}
});