eslint-plugin-san
Version:
Official ESLint plugin for San
156 lines (146 loc) • 5.53 kB
JavaScript
/**
* @fileoverview Define a style for the props casing in templates.
* @author Armano
*/
'use strict';
/* eslint-disable */
// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------
const utils = require('../utils');
// ------------------------------------------------------------------------------
// Helper
// ------------------------------------------------------------------------------
function isAlways(configuration, exceptions, propName) {
const isException = exceptions.has(propName);
if (configuration === ALWAYS) {
return !isException;
}
return isException;
}
function isNever(configuration, exceptions, propName) {
const isException = exceptions.has(propName);
if (configuration === NEVER) {
return !isException;
}
return isException;
}
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
const exceptionsSchema = {
type: 'array',
items: {type: 'string', minLength: 1},
uniqueItems: true
};
const ALWAYS = 'always';
const NEVER = 'never';
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: '',
categories: ['strongly-recommended'],
url: 'https://ecomfe.github.io/eslint-plugin-san/rules/boolean-value.html'
},
fixable: 'code',
// TODO
schema: {
anyOf: [
{
type: 'array',
items: [{enum: [ALWAYS, NEVER]}],
additionalItems: false
},
{
type: 'array',
items: [
{
enum: [ALWAYS]
},
{
type: 'object',
additionalProperties: false,
properties: {
[NEVER]: exceptionsSchema
}
}
],
additionalItems: false
},
{
type: 'array',
items: [
{
enum: [NEVER]
},
{
type: 'object',
additionalProperties: false,
properties: {
[ALWAYS]: exceptionsSchema
}
}
],
additionalItems: false
}
]
},
messages: {
omitBoolean: 'Value must be omitted for boolean attributes{{name}}',
omitBoolean_noMessage: 'Value must be omitted for boolean attributes',
setBoolean: 'Value must be set for boolean attributes{{name}}',
setBoolean_noMessage: 'Value must be set for boolean attributes'
}
},
/** @param {RuleContext} context */
create(context) {
const sourceCode = context.getSourceCode();
const configuration = context.options[0] || NEVER;
const configObject = context.options[1] || {};
const exceptions = new Set((configuration === ALWAYS ? configObject[NEVER] : configObject[ALWAYS]) || []);
return utils.defineTemplateBodyVisitor(context, {
VAttribute(node) {
if (!node) {
return {};
}
const propName = node.key.name;
const value = node.value;
if (isAlways(configuration, exceptions, propName) && value === null) {
const message = 'Value must be set for boolean attributes {{name}}';
context.report({
node,
loc: node.loc,
message,
data: {
name: node.key.rawName
},
fix: fixer => {
return fixer.insertTextAfter(node, '="{{true}}"');
}
});
}
if (isNever(configuration, exceptions, propName) && value) {
const message = 'Value must be omitted for boolean attributes {{name}}';
if (/\{[\s]*\{[\s]*true[\s]*\}[\s]*\}/.test(node.value.value)) {
context.report({
node,
loc: node.loc,
message,
data: {
name: node.key.rawName
},
fix: fixer => {
const name = node.key.name;
const relativeStartLoc = name.length;
const startLoc = node.range[0] + relativeStartLoc;
const range = [startLoc, node.value.range[1]];
return fixer.removeRange(range);
}
});
}
}
}
});
}
};