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 = '