
org.sonar.plugins.html.api.HtmlConstants Maven / Gradle / Ivy
The newest version!
/*
* SonarQube HTML
* Copyright (C) 2010-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonar.plugins.html.api;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.sonar.plugins.html.api.accessibility.AriaRole;
import org.sonar.plugins.html.node.TagNode;
public class HtmlConstants {
/** The language key. */
public static final String LANGUAGE_KEY = "web";
public static final String LANGUAGE_NAME = "HTML";
/** JSP language key. */
public static final String JSP_LANGUAGE_KEY = "jsp";
public static final String JSP_LANGUAGE_NAME = "JSP";
// ================ Plugin properties ================
public static final String FILE_EXTENSIONS_PROP_KEY = "sonar.html.file.suffixes";
public static final String FILE_EXTENSIONS_DEF_VALUE = ".html,.xhtml,.cshtml,.vbhtml,.aspx,.ascx,.rhtml,.erb,.shtm,.shtml,.cmp,.twig";
public static final String JSP_FILE_EXTENSIONS_PROP_KEY = "sonar.jsp.file.suffixes";
public static final String JSP_FILE_EXTENSIONS_DEF_VALUE = ".jsp,.jspf,.jspx";
public static final List KNOWN_HTML_TAGS = List.of(
"a",
"acronym", // deprecated
"area",
"abbr",
"address",
"applet", // deprecated
"article",
"aside",
"audio",
"b",
"base",
"bdi",
"bdo",
"big", // deprecated
"blink", // deprecated
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"center", // deprecated
"cite",
"code",
"col",
"colgroup",
"content", // deprecated
"data",
"datalist",
"dd",
"del",
"details",
"dfn",
"dialog",
"dir", // deprecated
"div",
"dl",
"dt",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"footer",
"font", // deprecated
"form",
"frame", // deprecated
"frameset", // deprecated
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"image", // deprecated
"img",
"input",
"ins",
"kbd",
"keygen", // deprecated
"label",
"legend",
"li",
"link",
"main",
"map",
"mark",
"marquee", // deprecated
"menu",
"menuitem", // deprecated
"meta",
"meter",
"nav",
"nobr", // deprecated
"noembed", // deprecated
"noframes", // deprecated
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param", // deprecated
"picture",
"plaintext", // deprecated
"pre",
"progress",
"q",
"rb", // deprecated
"rp",
"rt", // deprecated
"rtc", // deprecated
"ruby",
"s",
"samp",
"script",
"search",
"section",
"select",
"shadow", // deprecated
"small",
"source",
"spacer", // deprecated
"span",
"strike", // deprecated
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"tt", // deprecated
"u",
"ul",
"var",
"video",
"wbr",
"xmp" // deprecated
);
// computed from https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/util/isInteractiveElement.js
public static final Set INTERACTIVE_ELEMENTS = Set.of("a", "audio", "button", "canvas", "datalist", "embed", "input", "menuitem", "option", "select", "summary",
"td", "textarea", "th", "tr", "video");
// computed from https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/util/isNonInteractiveElement.js
public static final Set NON_INTERACTIVE_ELEMENTS = Set.of("abbr", "address", "article", "aside", "blockquote", "br", "caption", "code", "dd", "del", "details", "dfn",
"dialog", "dir", "dl", "dt", "em", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "html", "iframe", "img", "ins", "label",
"legend", "li", "main", "mark", "marquee", "menu", "meter", "nav", "ol", "optgroup", "output", "p", "pre", "progress", "ruby", "strong", "sub", "sup", "table", "tbody",
"tfoot", "thead", "time", "ul");
// computed as https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/util/isInteractiveRole.js
public static final Set INTERACTIVE_ROLES = Set.of("button", "checkbox", "columnheader", "combobox", "grid", "gridcell", "link", "listbox", "menu", "menubar", "menuitem",
"menuitemcheckbox", "menuitemradio", "option", "progressbar", "radio", "radiogroup", "row", "rowheader", "scrollbar", "searchbox", "slider", "spinbutton", "switch", "tab",
"tablist", "textbox", "tree", "treegrid", "treeitem", "doc-backlink", "doc-biblioref", "doc-glossref", "doc-noteref");
// computed from https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/util/isNonInteractiveRole.js
public static final Set NON_INTERACTIVE_ROLES = Set.of("alert", "alertdialog", "application", "article", "banner", "blockquote", "caption", "cell", "code",
"complementary", "contentinfo", "definition", "deletion", "dialog", "directory", "document", "emphasis", "feed", "figure", "form", "generic", "group", "heading", "img",
"insertion", "list", "listitem", "log", "main", "mark", "marquee", "math", "meter", "navigation", "none", "note", "paragraph", "presentation", "region", "rowgroup", "search",
"separator", "status", "strong", "subscript", "superscript", "table", "tabpanel", "term", "time", "timer", "toolbar", "tooltip", "doc-abstract", "doc-acknowledgments",
"doc-afterword", "doc-appendix", "doc-biblioentry", "doc-bibliography", "doc-chapter", "doc-colophon", "doc-conclusion", "doc-cover", "doc-credit", "doc-credits",
"doc-dedication", "doc-endnote", "doc-endnotes", "doc-epigraph", "doc-epilogue", "doc-errata", "doc-example", "doc-footnote", "doc-foreword", "doc-glossary", "doc-index",
"doc-introduction", "doc-notice", "doc-pagebreak", "doc-pagelist", "doc-part", "doc-preface", "doc-prologue", "doc-pullquote", "doc-qna", "doc-subtitle", "doc-tip", "doc-toc",
"graphics-document", "graphics-object", "graphics-symbol");
// inspired by https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/util/isPresentationRole.js
public static final Set PRESENTATION_ROLES = Set.of("none", "presentation");
// computed from https://github.com/A11yance/aria-query/blob/main/src/etc/roles/ariaAbstractRoles.js
protected static final Set ABSTRACT_ROLES = EnumSet.of(
AriaRole.COMMAND, AriaRole.COMPOSITE, AriaRole.INPUT, AriaRole.LANDMARK, AriaRole.RANGE, AriaRole.ROLETYPE,
AriaRole.SECTION, AriaRole.SECTIONHEAD, AriaRole.SELECT, AriaRole.STRUCTURE, AriaRole.TOOLBAR, AriaRole.WIDGET,
AriaRole.WINDOW);
// computed from https://github.com/A11yance/aria-query/blob/main/src/domMap.js
public static final Set RESERVED_NODE_SET = Set.of(
"base", "col", "colgroup", "head", "html", "link", "meta", "noembed", "noscript", "param", "picture", "script", "source", "style", "title", "track"
);
public static boolean isInteractiveElement(TagNode element) {
var tagName = element.getNodeName();
return INTERACTIVE_ELEMENTS.stream().anyMatch(tagName::equalsIgnoreCase);
}
public static boolean isNonInteractiveElement(TagNode element) {
var tagName = element.getNodeName();
return NON_INTERACTIVE_ELEMENTS.stream().anyMatch(tagName::equalsIgnoreCase);
}
public static boolean hasInteractiveRole(TagNode element) {
var role = element.getAttribute("role");
return role != null && INTERACTIVE_ROLES.stream().anyMatch(role::equalsIgnoreCase);
}
public static boolean hasNonInteractiveRole(TagNode element) {
var role = element.getAttribute("role");
return role != null && NON_INTERACTIVE_ROLES.stream().anyMatch(role::equalsIgnoreCase);
}
public static boolean hasPresentationRole(TagNode element) {
var role = element.getAttribute("role");
return role != null && PRESENTATION_ROLES.stream().anyMatch(role::equalsIgnoreCase);
}
public static boolean hasAbstractRole(TagNode element) {
var role = element.getAttribute("role");
if (role == null) {
return false;
}
var ariaRole = AriaRole.of(role.toLowerCase(Locale.ROOT));
return ariaRole != null && ABSTRACT_ROLES.stream().anyMatch(ariaRole::equals);
}
public static boolean hasKnownHTMLTag(TagNode element) {
return KNOWN_HTML_TAGS.stream().anyMatch(tag -> tag.equalsIgnoreCase(element.getNodeName()));
}
public static boolean isReservedNode(TagNode element) {
return RESERVED_NODE_SET.contains(element.getNodeName());
}
public static boolean isAbstractRole(AriaRole ariaRole) {
return ABSTRACT_ROLES.contains(ariaRole);
}
private HtmlConstants() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy