-
-
Notifications
You must be signed in to change notification settings - Fork 378
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add tags checking rule - allows specify rules for any tag and v…
…alidate that (#384) * adding tags check rule * fix missing commas * add polifil for old JS engines * add polifil for old JS engines * fix missing commas * fix indexOf * incrace code covarage * incrace code covarage * review fix * fix formating * fixing issues Co-authored-by: a.obitskyi <a.obitskyi@astoundcommerce.com>
- Loading branch information
1 parent
fe4f3c6
commit 518a1a2
Showing
3 changed files
with
184 additions
and
269 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,29 @@ | ||
export { default as altRequire } from './alt-require' | ||
export { default as attrLowercase } from './attr-lowercase' | ||
export { default as attrSort } from './attr-sorted' | ||
export { default as attrNoDuplication } from './attr-no-duplication' | ||
export { default as attrUnsafeChars } from './attr-unsafe-chars' | ||
export { default as attrValueDoubleQuotes } from './attr-value-double-quotes' | ||
export { default as attrValueNotEmpty } from './attr-value-not-empty' | ||
export { default as attrValueSingleQuotes } from './attr-value-single-quotes' | ||
export { default as attrWhitespace } from './attr-whitespace' | ||
export { default as doctypeFirst } from './doctype-first' | ||
export { default as doctypeHTML5 } from './doctype-html5' | ||
export { default as headScriptDisabled } from './head-script-disabled' | ||
export { default as hrefAbsOrRel } from './href-abs-or-rel' | ||
export { default as idClsasAdDisabled } from './id-class-ad-disabled' | ||
export { default as idClassValue } from './id-class-value' | ||
export { default as idUnique } from './id-unique' | ||
export { default as inlineScriptDisabled } from './inline-script-disabled' | ||
export { default as inlineStyleDisabled } from './inline-style-disabled' | ||
export { default as inputRequiresLabel } from './input-requires-label' | ||
export { default as scriptDisabled } from './script-disabled' | ||
export { default as spaceTabMixedDisabled } from './space-tab-mixed-disabled' | ||
export { default as specCharEscape } from './spec-char-escape' | ||
export { default as srcNotEmpty } from './src-not-empty' | ||
export { default as styleDisabled } from './style-disabled' | ||
export { default as tagPair } from './tag-pair' | ||
export { default as tagSelfClose } from './tag-self-close' | ||
export { default as tagnameLowercase } from './tagname-lowercase' | ||
export { default as tagnameSpecialChars } from './tagname-specialchars' | ||
export { default as titleRequire } from './title-require' | ||
export { default as tagsCheck } from './tags-check' | ||
export { default as attrNoUnnecessaryWhitespace } from './attr-no-unnecessary-whitespace' | ||
export { default as altRequire } from './alt-require'; | ||
export { default as attrLowercase } from './attr-lowercase'; | ||
export { default as attrSort } from './attr-sorted'; | ||
export { default as attrNoDuplication } from './attr-no-duplication'; | ||
export { default as attrUnsafeChars } from './attr-unsafe-chars'; | ||
export { default as attrValueDoubleQuotes } from './attr-value-double-quotes'; | ||
export { default as attrValueNotEmpty } from './attr-value-not-empty'; | ||
export { default as attrValueSingleQuotes } from './attr-value-single-quotes'; | ||
export { default as attrWhitespace } from './attr-whitespace'; | ||
export { default as doctypeFirst } from './doctype-first'; | ||
export { default as doctypeHTML5 } from './doctype-html5'; | ||
export { default as headScriptDisabled } from './head-script-disabled'; | ||
export { default as hrefAbsOrRel } from './href-abs-or-rel'; | ||
export { default as idClsasAdDisabled } from './id-class-ad-disabled'; | ||
export { default as idClassValue } from './id-class-value'; | ||
export { default as idUnique } from './id-unique'; | ||
export { default as inlineScriptDisabled } from './inline-script-disabled'; | ||
export { default as inlineStyleDisabled } from './inline-style-disabled'; | ||
export { default as scriptDisabled } from './script-disabled'; | ||
export { default as spaceTabMixedDisabled } from './space-tab-mixed-disabled'; | ||
export { default as specCharEscape } from './spec-char-escape'; | ||
export { default as srcNotEmpty } from './src-not-empty'; | ||
export { default as styleDisabled } from './style-disabled'; | ||
export { default as tagPair } from './tag-pair'; | ||
export { default as tagSelfClose } from './tag-self-close'; | ||
export { default as tagnameLowercase } from './tagname-lowercase'; | ||
export { default as tagnameSpecialChars } from './tagname-specialchars'; | ||
export { default as titleRequire } from './title-require'; | ||
export { default as tagsCheck } from './tags-check'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,202 +1,118 @@ | ||
|
||
var tagsTypings = { | ||
a: { | ||
selfclosing: false, | ||
attrsRequired: ['href', 'title'], | ||
redundantAttrs: ['alt'], | ||
}, | ||
div: { | ||
selfclosing: false, | ||
}, | ||
main: { | ||
selfclosing: false, | ||
redundantAttrs: ['role'], | ||
}, | ||
nav: { | ||
selfclosing: false, | ||
redundantAttrs: ['role'], | ||
}, | ||
script: { | ||
attrsOptional: [ | ||
['async', 'async'], | ||
['defer', 'defer'], | ||
], | ||
}, | ||
img: { | ||
selfclosing: true, | ||
attrsRequired: ['src', 'alt', 'title'], | ||
}, | ||
} | ||
a: { | ||
selfclosing: false, | ||
attrsRequired: ['href', 'title'], | ||
redundantAttrs: ['alt'] | ||
}, | ||
div: { | ||
selfclosing: false | ||
}, | ||
main: { | ||
selfclosing: false, | ||
redundantAttrs: ['role'] | ||
}, | ||
nav: { | ||
selfclosing: false, | ||
redundantAttrs: ['role'] | ||
}, | ||
script: { | ||
attrsOptional: [['async', 'async'], ['defer', 'defer']] | ||
}, | ||
img: { | ||
selfclosing: true, | ||
attrsRequired: [ | ||
'src', 'alt', 'title' | ||
] | ||
} | ||
}; | ||
|
||
var assign = function (target) { | ||
var _source | ||
var assign = function(target) { | ||
var _source; | ||
|
||
for (var i = 1; i < arguments.length; i++) { | ||
_source = arguments[i] | ||
for (var prop in _source) { | ||
target[prop] = _source[prop] | ||
for (var i = 1; i < arguments.length; i++) { | ||
_source = arguments[i]; | ||
for (var prop in _source) { | ||
target[prop] = _source[prop]; | ||
} | ||
} | ||
} | ||
|
||
return target | ||
return target; | ||
} | ||
|
||
export default { | ||
id: 'tags-check', | ||
description: 'Checks html tags.', | ||
init: function (parser, reporter, options) { | ||
var self = this | ||
id: 'tags-check', | ||
description: 'Checks html tags.', | ||
init: function (parser, reporter, options) { | ||
var self = this; | ||
|
||
if (typeof options !== 'boolean') { | ||
assign(tagsTypings, options) | ||
} | ||
if (typeof options !== 'boolean') { | ||
assign(tagsTypings, options); | ||
} | ||
|
||
parser.addListener('tagstart', function (event) { | ||
var attrs = event.attrs | ||
var col = event.col + event.tagName.length + 1 | ||
parser.addListener('tagstart', function (event) { | ||
var attrs = event.attrs; | ||
var col = event.col + event.tagName.length + 1; | ||
|
||
var tagName = event.tagName.toLowerCase() | ||
var tagName = event.tagName.toLowerCase(); | ||
|
||
if (tagsTypings[tagName]) { | ||
var currentTagType = tagsTypings[tagName] | ||
if (tagsTypings[tagName]) { | ||
var currentTagType = tagsTypings[tagName]; | ||
|
||
if (currentTagType.selfclosing === true && !event.close) { | ||
reporter.warn( | ||
'The <' + tagName + '> tag must be selfclosing.', | ||
event.line, | ||
event.col, | ||
self, | ||
event.raw | ||
) | ||
} else if (currentTagType.selfclosing === false && event.close) { | ||
reporter.warn( | ||
'The <' + tagName + '> tag must not be selfclosing.', | ||
event.line, | ||
event.col, | ||
self, | ||
event.raw | ||
) | ||
} | ||
if (currentTagType.selfclosing === true && !event.close) { | ||
reporter.warn('The <' + tagName + '> tag must be selfclosing.', event.line, event.col, self, event.raw); | ||
} else if (currentTagType.selfclosing === false && event.close) { | ||
reporter.warn('The <' + tagName +'> tag must not be selfclosing.', event.line, event.col, self, event.raw); | ||
} | ||
|
||
if (currentTagType.attrsRequired) { | ||
currentTagType.attrsRequired.forEach(function (id) { | ||
if (Array.isArray(id)) { | ||
var copyOfId = id.map(function (a) { | ||
return a | ||
}) | ||
var realID = copyOfId.shift() | ||
var values = copyOfId | ||
if (currentTagType.attrsRequired) { | ||
currentTagType.attrsRequired.forEach(function (id) { | ||
if (Array.isArray(id)) { | ||
var copyOfId = id.map(function (a) { return a;}); | ||
var realID = copyOfId.shift(); | ||
var values = copyOfId; | ||
|
||
if ( | ||
attrs.some(function (attr) { | ||
return attr.name === realID | ||
}) | ||
) { | ||
attrs.forEach(function (attr) { | ||
if ( | ||
attr.name === realID && | ||
values.indexOf(attr.value) === -1 | ||
) { | ||
reporter.error( | ||
'The <' + | ||
tagName + | ||
"> tag must have attr '" + | ||
realID + | ||
"' with one value of '" + | ||
values.join("' or '") + | ||
"'.", | ||
event.line, | ||
col, | ||
self, | ||
event.raw | ||
) | ||
} | ||
}) | ||
} else { | ||
reporter.error( | ||
'The <' + tagName + "> tag must have attr '" + realID + "'.", | ||
event.line, | ||
col, | ||
self, | ||
event.raw | ||
) | ||
if (attrs.some(function (attr) {return attr.name === realID;})) { | ||
attrs.forEach(function (attr) { | ||
if (attr.name === realID && values.indexOf(attr.value) === -1) { | ||
reporter.error('The <' + tagName +'> tag must have attr \'' + realID + '\' with one value of \'' + values.join('\' or \'') + '\'.', event.line, col, self, event.raw); | ||
} | ||
}); | ||
} else { | ||
reporter.error('The <' + tagName + '> tag must have attr \'' + realID + '\'.', event.line, col, self, event.raw); | ||
} | ||
} else if (!attrs.some(function (attr) {return id.split('|').indexOf(attr.name) !== -1;})) { | ||
reporter.error('The <' + tagName + '> tag must have attr \'' + id + '\'.', event.line, col, self, event.raw); | ||
} | ||
}); | ||
} | ||
} else if ( | ||
!attrs.some(function (attr) { | ||
return id.split('|').indexOf(attr.name) !== -1 | ||
}) | ||
) { | ||
reporter.error( | ||
'The <' + tagName + "> tag must have attr '" + id + "'.", | ||
event.line, | ||
col, | ||
self, | ||
event.raw | ||
) | ||
} | ||
}) | ||
} | ||
if (currentTagType.attrsOptional) { | ||
currentTagType.attrsOptional.forEach(function (id) { | ||
if (Array.isArray(id)) { | ||
var copyOfId = id.map(function (a) { return a;}); | ||
var realID = copyOfId.shift(); | ||
var values = copyOfId; | ||
|
||
if (currentTagType.attrsOptional) { | ||
currentTagType.attrsOptional.forEach(function (id) { | ||
if (Array.isArray(id)) { | ||
var copyOfId = id.map(function (a) { | ||
return a | ||
}) | ||
var realID = copyOfId.shift() | ||
var values = copyOfId | ||
if (attrs.some(function (attr) {return attr.name === realID;})) { | ||
attrs.forEach(function (attr) { | ||
if (attr.name === realID && values.indexOf(attr.value) === -1) { | ||
reporter.error('The <' + tagName + '> tag must have optional attr \'' + realID + | ||
'\' with one value of \'' + values.join('\' or \'') + '\'.', event.line, col, self, event.raw); | ||
} | ||
}); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
if ( | ||
attrs.some(function (attr) { | ||
return attr.name === realID | ||
}) | ||
) { | ||
attrs.forEach(function (attr) { | ||
if ( | ||
attr.name === realID && | ||
values.indexOf(attr.value) === -1 | ||
) { | ||
reporter.error( | ||
'The <' + | ||
tagName + | ||
"> tag must have optional attr '" + | ||
realID + | ||
"' with one value of '" + | ||
values.join("' or '") + | ||
"'.", | ||
event.line, | ||
col, | ||
self, | ||
event.raw | ||
) | ||
} | ||
}) | ||
if (currentTagType.redundantAttrs) { | ||
currentTagType.redundantAttrs.forEach(function (attrName) { | ||
if (attrs.some(function (attr) { return attr.name === attrName;})) { | ||
reporter.error('The attr \'' + attrName + '\' is redundant for <' + tagName + '> and should be ommited.', event.line, col, self, event.raw); | ||
} | ||
}); | ||
} | ||
} | ||
}) | ||
} | ||
|
||
if (currentTagType.redundantAttrs) { | ||
currentTagType.redundantAttrs.forEach(function (attrName) { | ||
if ( | ||
attrs.some(function (attr) { | ||
return attr.name === attrName | ||
}) | ||
) { | ||
reporter.error( | ||
"The attr '" + | ||
attrName + | ||
"' is redundant for <" + | ||
tagName + | ||
'> and should be ommited.', | ||
event.line, | ||
col, | ||
self, | ||
event.raw | ||
) | ||
} | ||
}) | ||
} | ||
} | ||
}) | ||
}, | ||
} | ||
} | ||
}); | ||
} | ||
}; |
Oops, something went wrong.