eslint-plugin-lit
Version:
lit-html support for ESLint
81 lines (80 loc) • 3.71 kB
JavaScript
/**
* @fileoverview Enforces that `value` is bound on an input after constraints
* @author James Garbutt <https://github.com/43081j>
*/
import { TemplateAnalyzer } from '../template-analyzer.js';
import { isExpressionPlaceholder } from '../util.js';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const knownConstraints = [
'max',
'min',
'maxlength',
'minlength',
'pattern'
];
export const rule = {
meta: {
docs: {
description: 'Enforces that `value` is bound on an input after constraints',
category: 'Best Practices',
url: 'https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/value-after-constraints.md'
},
schema: [],
messages: {
valueAfter: 'The `value` property/attribute should be bound after any bound ' +
'validation constraints (e.g. `min`, `max`, etc) to ensure they are ' +
'enabled before the value is set.'
}
},
create(context) {
const source = context.getSourceCode();
return {
TaggedTemplateExpression: (node) => {
if (node.type === 'TaggedTemplateExpression' &&
node.tag.type === 'Identifier' &&
node.tag.name === 'html') {
const analyzer = TemplateAnalyzer.create(node);
analyzer.traverse({
enterElement: (element) => {
var _a;
if (element.tagName !== 'input' ||
!((_a = element.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.attrs)) {
return;
}
const valueName = element.attribs['.value'] ? '.value' : 'value';
const attrLocs = element.sourceCodeLocation.attrs;
const valueLoc = attrLocs[valueName];
const valueAttr = element.attribs[valueName];
if (!valueAttr ||
!valueLoc ||
!isExpressionPlaceholder(valueAttr)) {
return;
}
for (const constraint of knownConstraints) {
const constraintName = element.attribs[`.${constraint}`]
? `.${constraint}`
: constraint;
const constraintLoc = attrLocs[constraintName];
const constraintAttr = element.attribs[constraintName];
if (constraintAttr &&
constraintLoc &&
isExpressionPlaceholder(constraintAttr) &&
constraintLoc.startOffset > valueLoc.startOffset) {
const loc = analyzer.getLocationForAttribute(element, valueName, source);
if (loc) {
context.report({
loc: loc,
messageId: 'valueAfter'
});
}
}
}
}
});
}
}
};
}
};