UNPKG

eslint-plugin-lit

Version:
79 lines (78 loc) 4.06 kB
/** * @fileoverview Disallows unencoded HTML entities in attribute values * @author James Garbutt <https://github.com/43081j> */ import { TemplateAnalyzer } from '../template-analyzer.js'; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ export const rule = { meta: { docs: { description: 'Disallows unencoded HTML entities in attribute values', recommended: false, url: 'https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/attribute-value-entities.md' }, schema: [], messages: { unencoded: 'Attribute values may not contain unencoded HTML ' + 'entities, e.g. use `&gt;` instead of `>`', doubleQuotes: 'Attributes delimited by double quotes may not contain ' + 'unencoded double quotes (e.g. `attr="bad"quote"`)', singleQuotes: 'Attributes delimited by single quotes may not contain ' + "unencoded single quotes (e.g. `attr='bad'quote'`)" } }, create(context) { const source = context.getSourceCode(); const disallowedPattern = /([<>]|&(?!(#\d+|[a-z]+);))/; //---------------------------------------------------------------------- // Helpers //---------------------------------------------------------------------- //---------------------------------------------------------------------- // Public //---------------------------------------------------------------------- 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, _b, _c, _d; // eslint-disable-next-line guard-for-in for (const attr in element.attribs) { const loc = analyzer.getLocationForAttribute(element, attr, source); const rawValue = analyzer.getRawAttributeValue(element, attr); if (!loc || !(rawValue === null || rawValue === void 0 ? void 0 : rawValue.value)) { continue; } if (disallowedPattern.test(rawValue.value)) { context.report({ loc: loc, messageId: 'unencoded' }); } else if (((_a = rawValue.quotedValue) === null || _a === void 0 ? void 0 : _a.startsWith('"')) && ((_b = rawValue.value) === null || _b === void 0 ? void 0 : _b.includes('"'))) { context.report({ loc: loc, messageId: 'doubleQuotes' }); } else if (((_c = rawValue.quotedValue) === null || _c === void 0 ? void 0 : _c.startsWith("'")) && ((_d = rawValue.value) === null || _d === void 0 ? void 0 : _d.includes("'"))) { context.report({ loc: loc, messageId: 'singleQuotes' }); } } } }); } } }; } };