diff --git a/dist/core/rules/attr-no-duplication.js b/dist/core/rules/attr-no-duplication.js index 35912a1d5..97109025b 100644 --- a/dist/core/rules/attr-no-duplication.js +++ b/dist/core/rules/attr-no-duplication.js @@ -12,7 +12,7 @@ exports.default = { const mapAttrName = {}; for (let i = 0, l = attrs.length; i < l; i++) { attr = attrs[i]; - attrName = attr.name; + attrName = attr.name.toLowerCase(); if (mapAttrName[attrName] === true) { reporter.error(`Duplicate of attribute name [ ${attr.name} ] was found.`, event.line, col + attr.index, this, attr.raw); } @@ -21,4 +21,4 @@ exports.default = { }); }, }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0ci1uby1kdXBsaWNhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL3J1bGVzL2F0dHItbm8tZHVwbGljYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSxrQkFBZTtJQUNiLEVBQUUsRUFBRSxxQkFBcUI7SUFDekIsV0FBVyxFQUFFLDRDQUE0QztJQUN6RCxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVE7UUFDbkIsTUFBTSxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUN2QyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFBO1lBQ3pCLElBQUksSUFBSSxDQUFBO1lBQ1IsSUFBSSxRQUFnQixDQUFBO1lBQ3BCLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFBO1lBRWhELE1BQU0sV0FBVyxHQUFnQyxFQUFFLENBQUE7WUFFbkQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUM3QyxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFBO2dCQUNmLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFBO2dCQUVwQixJQUFJLFdBQVcsQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDbkMsUUFBUSxDQUFDLEtBQUssQ0FDWixpQ0FBaUMsSUFBSSxDQUFDLElBQUksZUFBZSxFQUN6RCxLQUFLLENBQUMsSUFBSSxFQUNWLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUNoQixJQUFJLEVBQ0osSUFBSSxDQUFDLEdBQUcsQ0FDVCxDQUFBO2dCQUNILENBQUM7Z0JBQ0QsV0FBVyxDQUFDLFFBQVEsQ0FBQyxHQUFHLElBQUksQ0FBQTtZQUM5QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0NBQ00sQ0FBQSJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0ci1uby1kdXBsaWNhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL3J1bGVzL2F0dHItbm8tZHVwbGljYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSxrQkFBZTtJQUNiLEVBQUUsRUFBRSxxQkFBcUI7SUFDekIsV0FBVyxFQUFFLDRDQUE0QztJQUN6RCxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVE7UUFDbkIsTUFBTSxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUN2QyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFBO1lBQ3pCLElBQUksSUFBSSxDQUFBO1lBQ1IsSUFBSSxRQUFnQixDQUFBO1lBQ3BCLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFBO1lBRWhELE1BQU0sV0FBVyxHQUFnQyxFQUFFLENBQUE7WUFFbkQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUM3QyxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFBO2dCQUdmLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFBO2dCQUVsQyxJQUFJLFdBQVcsQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDbkMsUUFBUSxDQUFDLEtBQUssQ0FDWixpQ0FBaUMsSUFBSSxDQUFDLElBQUksZUFBZSxFQUN6RCxLQUFLLENBQUMsSUFBSSxFQUNWLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUNoQixJQUFJLEVBQ0osSUFBSSxDQUFDLEdBQUcsQ0FDVCxDQUFBO2dCQUNILENBQUM7Z0JBQ0QsV0FBVyxDQUFDLFFBQVEsQ0FBQyxHQUFHLElBQUksQ0FBQTtZQUM5QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0NBQ00sQ0FBQSJ9 \ No newline at end of file diff --git a/dist/core/rules/src-not-empty.js b/dist/core/rules/src-not-empty.js index 0db9c23d9..4bc01a884 100644 --- a/dist/core/rules/src-not-empty.js +++ b/dist/core/rules/src-not-empty.js @@ -5,16 +5,17 @@ exports.default = { description: 'The src attribute of an img(script,link) must have a value.', init(parser, reporter) { parser.addListener('tagstart', (event) => { - const tagName = event.tagName; + const tagName = event.tagName.toLowerCase(); const attrs = event.attrs; let attr; const col = event.col + tagName.length + 1; for (let i = 0, l = attrs.length; i < l; i++) { attr = attrs[i]; + const attrName = attr.name.toLowerCase(); if (((/^(img|script|embed|bgsound|iframe)$/.test(tagName) === true && - attr.name === 'src') || - (tagName === 'link' && attr.name === 'href') || - (tagName === 'object' && attr.name === 'data')) && + attrName === 'src') || + (tagName === 'link' && attrName === 'href') || + (tagName === 'object' && attrName === 'data')) && attr.value === '') { reporter.error(`The attribute [ ${attr.name} ] of the tag [ ${tagName} ] must have a value.`, event.line, col + attr.index, this, attr.raw); } @@ -22,4 +23,4 @@ exports.default = { }); }, }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3JjLW5vdC1lbXB0eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL3J1bGVzL3NyYy1ub3QtZW1wdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSxrQkFBZTtJQUNiLEVBQUUsRUFBRSxlQUFlO0lBQ25CLFdBQVcsRUFBRSw2REFBNkQ7SUFDMUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRO1FBQ25CLE1BQU0sQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDdkMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQTtZQUM3QixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFBO1lBQ3pCLElBQUksSUFBSSxDQUFBO1lBQ1IsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQTtZQUUxQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQzdDLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7Z0JBRWYsSUFDRSxDQUFDLENBQUMscUNBQXFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUk7b0JBQzVELElBQUksQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDO29CQUNwQixDQUFDLE9BQU8sS0FBSyxNQUFNLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxNQUFNLENBQUM7b0JBQzVDLENBQUMsT0FBTyxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQyxDQUFDO29CQUNqRCxJQUFJLENBQUMsS0FBSyxLQUFLLEVBQUUsRUFDakIsQ0FBQztvQkFDRCxRQUFRLENBQUMsS0FBSyxDQUNaLG1CQUFtQixJQUFJLENBQUMsSUFBSSxtQkFBbUIsT0FBTyx1QkFBdUIsRUFDN0UsS0FBSyxDQUFDLElBQUksRUFDVixHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFDaEIsSUFBSSxFQUNKLElBQUksQ0FBQyxHQUFHLENBQ1QsQ0FBQTtnQkFDSCxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNNLENBQUEifQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3JjLW5vdC1lbXB0eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL3J1bGVzL3NyYy1ub3QtZW1wdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSxrQkFBZTtJQUNiLEVBQUUsRUFBRSxlQUFlO0lBQ25CLFdBQVcsRUFBRSw2REFBNkQ7SUFDMUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRO1FBQ25CLE1BQU0sQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFJdkMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQTtZQUMzQyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFBO1lBQ3pCLElBQUksSUFBSSxDQUFBO1lBQ1IsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQTtZQUUxQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQzdDLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7Z0JBQ2YsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQTtnQkFFeEMsSUFDRSxDQUFDLENBQUMscUNBQXFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUk7b0JBQzVELFFBQVEsS0FBSyxLQUFLLENBQUM7b0JBQ25CLENBQUMsT0FBTyxLQUFLLE1BQU0sSUFBSSxRQUFRLEtBQUssTUFBTSxDQUFDO29CQUMzQyxDQUFDLE9BQU8sS0FBSyxRQUFRLElBQUksUUFBUSxLQUFLLE1BQU0sQ0FBQyxDQUFDO29CQUNoRCxJQUFJLENBQUMsS0FBSyxLQUFLLEVBQUUsRUFDakIsQ0FBQztvQkFDRCxRQUFRLENBQUMsS0FBSyxDQUNaLG1CQUFtQixJQUFJLENBQUMsSUFBSSxtQkFBbUIsT0FBTyx1QkFBdUIsRUFDN0UsS0FBSyxDQUFDLElBQUksRUFDVixHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFDaEIsSUFBSSxFQUNKLElBQUksQ0FBQyxHQUFHLENBQ1QsQ0FBQTtnQkFDSCxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNNLENBQUEifQ== \ No newline at end of file diff --git a/src/core/rules/attr-no-duplication.ts b/src/core/rules/attr-no-duplication.ts index f7b4e4d9c..fada923d9 100644 --- a/src/core/rules/attr-no-duplication.ts +++ b/src/core/rules/attr-no-duplication.ts @@ -14,7 +14,9 @@ export default { for (let i = 0, l = attrs.length; i < l; i++) { attr = attrs[i] - attrName = attr.name + // HTML attribute names are ASCII case insensitive, so id and ID on the + // same element are a duplicate. + attrName = attr.name.toLowerCase() if (mapAttrName[attrName] === true) { reporter.error( diff --git a/src/core/rules/src-not-empty.ts b/src/core/rules/src-not-empty.ts index 4510e151d..1a9dd27ae 100644 --- a/src/core/rules/src-not-empty.ts +++ b/src/core/rules/src-not-empty.ts @@ -5,19 +5,23 @@ export default { description: 'The src attribute of an img(script,link) must have a value.', init(parser, reporter) { parser.addListener('tagstart', (event) => { - const tagName = event.tagName + // HTML tag and attribute names are ASCII case insensitive, so compare + // against the lowercased form. The parser hands them over exactly as they + // were written. + const tagName = event.tagName.toLowerCase() const attrs = event.attrs let attr const col = event.col + tagName.length + 1 for (let i = 0, l = attrs.length; i < l; i++) { attr = attrs[i] + const attrName = attr.name.toLowerCase() if ( ((/^(img|script|embed|bgsound|iframe)$/.test(tagName) === true && - attr.name === 'src') || - (tagName === 'link' && attr.name === 'href') || - (tagName === 'object' && attr.name === 'data')) && + attrName === 'src') || + (tagName === 'link' && attrName === 'href') || + (tagName === 'object' && attrName === 'data')) && attr.value === '' ) { reporter.error( diff --git a/test/rules/attr-no-duplication.spec.js b/test/rules/attr-no-duplication.spec.js index 498ae2ef4..851eff5e5 100644 --- a/test/rules/attr-no-duplication.spec.js +++ b/test/rules/attr-no-duplication.spec.js @@ -15,6 +15,15 @@ describe(`Rules: ${ruleId}`, () => { expect(messages[0].col).toBe(12) }) + it('Attribute name duplicated in a different case should result in an error', () => { + // HTML attribute names are ASCII case insensitive, so href and HREF on the + // same element are the same attribute. + const code = 'bbb' + const messages = HTMLHint.verify(code, ruleOptions) + expect(messages.length).toBe(1) + expect(messages[0].rule.id).toBe(ruleId) + }) + it('Attribute name not been duplication should not result in an error', () => { const code = 'bbb' const messages = HTMLHint.verify(code, ruleOptions) diff --git a/test/rules/src-not-empty.spec.js b/test/rules/src-not-empty.spec.js index 1005b7c9b..a22faa719 100644 --- a/test/rules/src-not-empty.spec.js +++ b/test/rules/src-not-empty.spec.js @@ -20,6 +20,20 @@ describe(`Rules: ${ruleId}`, () => { expect(messages.length).toBe(0) }) + it('Src be empty should result in an error whatever the case', () => { + // HTML tag and attribute names are ASCII case insensitive, so these are four + // spellings of one bug and all four have to be reported. + const code = '' + const messages = HTMLHint.verify(code, ruleOptions) + expect(messages.length).toBe(4) + }) + + it('Uppercase href and data should result in an error', () => { + const code = '' + const messages = HTMLHint.verify(code, ruleOptions) + expect(messages.length).toBe(2) + }) + it('Src be not set value should not result in an error', () => { const code = '