UNPKG

eslint-plugin-lit

Version:
81 lines (80 loc) 3.71 kB
/** * @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' }); } } } } }); } } }; } };