govuk_publishing_components 21.22.1 → 21.22.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -3
  3. data/app/assets/stylesheets/govuk_publishing_components/components/_breadcrumbs.scss +34 -0
  4. data/app/assets/stylesheets/govuk_publishing_components/components/_document-list.scss +2 -2
  5. data/app/views/govuk_publishing_components/components/_breadcrumbs.html.erb +0 -3
  6. data/app/views/govuk_publishing_components/components/_contextual_breadcrumbs.html.erb +0 -2
  7. data/lib/govuk_publishing_components/version.rb +1 -1
  8. data/node_modules/axe-core/CHANGELOG.md +70 -10
  9. data/node_modules/axe-core/axe.js +1295 -632
  10. data/node_modules/axe-core/axe.min.js +2 -2
  11. data/node_modules/axe-core/bower.json +1 -1
  12. data/node_modules/axe-core/doc/API.md +1 -0
  13. data/node_modules/axe-core/doc/aria-supported.md +0 -1
  14. data/node_modules/axe-core/doc/developer-guide.md +2 -2
  15. data/node_modules/axe-core/doc/rule-descriptions.md +91 -87
  16. data/node_modules/axe-core/lib/checks/aria/abstractrole.js +10 -1
  17. data/node_modules/axe-core/lib/checks/aria/abstractrole.json +4 -1
  18. data/node_modules/axe-core/lib/checks/aria/fallbackrole.js +1 -0
  19. data/node_modules/axe-core/lib/checks/aria/fallbackrole.json +11 -0
  20. data/node_modules/axe-core/lib/checks/aria/invalidrole.js +14 -3
  21. data/node_modules/axe-core/lib/checks/aria/invalidrole.json +4 -1
  22. data/node_modules/axe-core/lib/checks/aria/required-children.js +41 -30
  23. data/node_modules/axe-core/lib/checks/aria/valid-attr-value.js +24 -9
  24. data/node_modules/axe-core/lib/checks/aria/valid-attr-value.json +2 -2
  25. data/node_modules/axe-core/lib/checks/color/color-contrast.js +23 -7
  26. data/node_modules/axe-core/lib/checks/color/color-contrast.json +7 -1
  27. data/node_modules/axe-core/lib/checks/keyboard/focusable-disabled.js +5 -0
  28. data/node_modules/axe-core/lib/checks/keyboard/focusable-modal-open.js +14 -0
  29. data/node_modules/axe-core/lib/checks/keyboard/focusable-modal-open.json +11 -0
  30. data/node_modules/axe-core/lib/checks/keyboard/focusable-not-tabbable.js +5 -0
  31. data/node_modules/axe-core/lib/checks/keyboard/page-has-elm.js +5 -1
  32. data/node_modules/axe-core/lib/checks/keyboard/page-no-duplicate-after.js +2 -0
  33. data/node_modules/axe-core/lib/checks/keyboard/page-no-duplicate-banner.json +1 -0
  34. data/node_modules/axe-core/lib/checks/keyboard/page-no-duplicate-contentinfo.json +1 -0
  35. data/node_modules/axe-core/lib/checks/keyboard/page-no-duplicate-main.json +1 -0
  36. data/node_modules/axe-core/lib/checks/keyboard/page-no-duplicate.js +14 -2
  37. data/node_modules/axe-core/lib/checks/lists/only-listitems.js +43 -49
  38. data/node_modules/axe-core/lib/checks/lists/only-listitems.json +4 -1
  39. data/node_modules/axe-core/lib/checks/media/no-autoplay-audio.js +93 -0
  40. data/node_modules/axe-core/lib/checks/media/no-autoplay-audio.json +15 -0
  41. data/node_modules/axe-core/lib/checks/navigation/identical-links-same-purpose-after.js +100 -0
  42. data/node_modules/axe-core/lib/checks/navigation/identical-links-same-purpose.js +31 -0
  43. data/node_modules/axe-core/lib/checks/navigation/identical-links-same-purpose.json +12 -0
  44. data/node_modules/axe-core/lib/checks/navigation/region.js +42 -8
  45. data/node_modules/axe-core/lib/checks/navigation/region.json +0 -1
  46. data/node_modules/axe-core/lib/checks/shared/svg-non-empty-title.js +4 -0
  47. data/node_modules/axe-core/lib/checks/shared/svg-non-empty-title.json +11 -0
  48. data/node_modules/axe-core/lib/commons/aria/index.js +12 -4
  49. data/node_modules/axe-core/lib/commons/color/get-background-color.js +5 -157
  50. data/node_modules/axe-core/lib/commons/dom/get-element-stack.js +272 -174
  51. data/node_modules/axe-core/lib/commons/dom/is-focusable.js +3 -1
  52. data/node_modules/axe-core/lib/commons/dom/is-hidden-with-css.js +2 -2
  53. data/node_modules/axe-core/lib/commons/dom/is-modal-open.js +98 -0
  54. data/node_modules/axe-core/lib/commons/dom/is-visible.js +57 -2
  55. data/node_modules/axe-core/lib/commons/dom/url-props-from-attribute.js +143 -0
  56. data/node_modules/axe-core/lib/commons/dom/visually-contains.js +62 -12
  57. data/node_modules/axe-core/lib/commons/matches/attributes.js +12 -8
  58. data/node_modules/axe-core/lib/commons/matches/from-definition.js +15 -10
  59. data/node_modules/axe-core/lib/commons/matches/index.js +11 -9
  60. data/node_modules/axe-core/lib/commons/matches/node-name.js +11 -21
  61. data/node_modules/axe-core/lib/commons/matches/properties.js +12 -9
  62. data/node_modules/axe-core/lib/commons/text/unicode.js +27 -24
  63. data/node_modules/axe-core/lib/core/base/virtual-node/virtual-node.js +11 -3
  64. data/node_modules/axe-core/lib/core/constants.js +1 -1
  65. data/node_modules/axe-core/lib/core/reporters/v1.js +6 -3
  66. data/node_modules/axe-core/lib/core/utils/contains.js +1 -1
  67. data/node_modules/axe-core/lib/core/utils/is-hidden.js +6 -6
  68. data/node_modules/axe-core/lib/core/utils/matches.js +263 -0
  69. data/node_modules/axe-core/lib/core/utils/preload-media.js +65 -0
  70. data/node_modules/axe-core/lib/core/utils/preload.js +33 -24
  71. data/node_modules/axe-core/lib/core/utils/qsa.js +7 -208
  72. data/node_modules/axe-core/lib/rules/aria-hidden-focus.json +5 -1
  73. data/node_modules/axe-core/lib/rules/aria-roles.json +1 -1
  74. data/node_modules/axe-core/lib/rules/button-name.json +1 -1
  75. data/node_modules/axe-core/lib/rules/color-contrast-matches.js +1 -1
  76. data/node_modules/axe-core/lib/rules/color-contrast.json +0 -3
  77. data/node_modules/axe-core/lib/rules/html-namespace-matches.js +1 -0
  78. data/node_modules/axe-core/lib/rules/identical-links-same-purpose-matches.js +13 -0
  79. data/node_modules/axe-core/lib/rules/identical-links-same-purpose.json +14 -0
  80. data/node_modules/axe-core/lib/rules/landmark-no-duplicate-banner.json +1 -1
  81. data/node_modules/axe-core/lib/rules/landmark-no-duplicate-contentinfo.json +1 -1
  82. data/node_modules/axe-core/lib/rules/landmark-no-duplicate-main.json +12 -0
  83. data/node_modules/axe-core/lib/rules/landmark-one-main.json +2 -2
  84. data/node_modules/axe-core/lib/rules/link-name.json +2 -4
  85. data/node_modules/axe-core/lib/rules/meta-viewport.json +1 -1
  86. data/node_modules/axe-core/lib/rules/no-autoplay-audio-matches.js +18 -0
  87. data/node_modules/axe-core/lib/rules/no-autoplay-audio.json +15 -0
  88. data/node_modules/axe-core/lib/rules/region.json +1 -2
  89. data/node_modules/axe-core/lib/rules/role-img-alt.json +2 -1
  90. data/node_modules/axe-core/lib/rules/svg-img-alt.json +24 -0
  91. data/node_modules/axe-core/lib/rules/svg-namespace-matches.js +1 -0
  92. data/node_modules/axe-core/locales/da.json +782 -0
  93. data/node_modules/axe-core/locales/fr.json +221 -42
  94. data/node_modules/axe-core/locales/ja.json +124 -24
  95. data/node_modules/axe-core/package.json +29 -26
  96. data/node_modules/axe-core/sri-history.json +26 -10
  97. metadata +27 -9
  98. data/node_modules/axe-core/doc/examples/jasmine/package-lock.json +0 -1489
  99. data/node_modules/axe-core/doc/examples/jest_react/package-lock.json +0 -7525
  100. data/node_modules/axe-core/doc/examples/mocha/package-lock.json +0 -1671
  101. data/node_modules/axe-core/doc/examples/phantomjs/package-lock.json +0 -862
  102. data/node_modules/axe-core/doc/examples/qunit/package-lock.json +0 -2951
  103. data/node_modules/axe-core/lib/checks/navigation/region-after.js +0 -1
  104. data/node_modules/axe-core/typings/axe-core/axe-core-tests.js +0 -151
@@ -1,23 +1,27 @@
1
1
  /* global matches */
2
2
  /**
3
- * Check if a node matches some attribute(s)
3
+ * Check if a virtual node matches some attribute(s)
4
4
  *
5
- * Note: matches.attributes(node, matcher) can be indirectly used through
6
- * matches(node, { attributes: matcher })
5
+ * Note: matches.attributes(vNode, matcher) can be indirectly used through
6
+ * matches(vNode, { attributes: matcher })
7
7
  *
8
8
  * Example:
9
9
  * ```js
10
- * matches.attributes(node, {
10
+ * matches.attributes(vNode, {
11
11
  * 'aria-live': 'assertive', // Simple string match
12
12
  * 'aria-expanded': /true|false/i, // either boolean, case insensitive
13
13
  * })
14
14
  * ```
15
15
  *
16
- * @param {HTMLElement|VirtualNode} node
16
+ * @deprecated HTMLElement is deprecated, use VirtualNode instead
17
+ *
18
+ * @param {HTMLElement|VirtualNode} vNode
17
19
  * @param {Object} Attribute matcher
18
20
  * @returns {Boolean}
19
21
  */
20
- matches.attributes = function matchesAttributes(node, matcher) {
21
- node = node.actualNode || node;
22
- return matches.fromFunction(attrName => node.getAttribute(attrName), matcher);
22
+ matches.attributes = function matchesAttributes(vNode, matcher) {
23
+ if (!(vNode instanceof axe.AbstractVirtualNode)) {
24
+ vNode = axe.utils.getNodeFromTree(vNode);
25
+ }
26
+ return matches.fromFunction(attrName => vNode.attr(attrName), matcher);
23
27
  };
@@ -2,14 +2,14 @@
2
2
  const matchers = ['nodeName', 'attributes', 'properties', 'condition'];
3
3
 
4
4
  /**
5
- * Check if a node matches some definition
5
+ * Check if a virtual node matches some definition
6
6
  *
7
- * Note: matches.fromDefinition(node, definition) can be indirectly used through
8
- * matches(node, definition)
7
+ * Note: matches.fromDefinition(vNode, definition) can be indirectly used through
8
+ * matches(vNode, definition)
9
9
  *
10
10
  * Example:
11
11
  * ```js
12
- * matches.fromDefinition(node, {
12
+ * matches.fromDefinition(vNode, {
13
13
  * nodeName: ['div', 'span']
14
14
  * attributes: {
15
15
  * 'aria-live': 'assertive'
@@ -17,18 +17,23 @@ const matchers = ['nodeName', 'attributes', 'properties', 'condition'];
17
17
  * })
18
18
  * ```
19
19
  *
20
+ * @deprecated HTMLElement is deprecated, use VirtualNode instead
21
+ *
20
22
  * @private
21
- * @param {HTMLElement|VirtualNode} node
23
+ * @param {HTMLElement|VirtualNode} vNode
22
24
  * @param {Object|Array<Object>} definition
23
25
  * @returns {Boolean}
24
26
  */
25
- matches.fromDefinition = function matchFromDefinition(node, definition) {
26
- node = node.actualNode || node;
27
+ matches.fromDefinition = function matchFromDefinition(vNode, definition) {
28
+ if (!(vNode instanceof axe.AbstractVirtualNode)) {
29
+ vNode = axe.utils.getNodeFromTree(vNode);
30
+ }
31
+
27
32
  if (Array.isArray(definition)) {
28
- return definition.some(definitionItem => matches(node, definitionItem));
33
+ return definition.some(definitionItem => matches(vNode, definitionItem));
29
34
  }
30
35
  if (typeof definition === 'string') {
31
- return axe.utils.matchesSelector(node, definition);
36
+ return axe.utils.matches(vNode, definition);
32
37
  }
33
38
 
34
39
  return Object.keys(definition).every(matcherName => {
@@ -42,6 +47,6 @@ matches.fromDefinition = function matchFromDefinition(node, definition) {
42
47
  // Find the matcher that goes into the matches method.
43
48
  // 'div', /^div$/, (str) => str === 'div', etc.
44
49
  const matcher = definition[matcherName];
45
- return matchMethod(node, matcher);
50
+ return matchMethod(vNode, matcher);
46
51
  });
47
52
  };
@@ -1,37 +1,39 @@
1
1
  /* exported matches */
2
2
 
3
3
  /**
4
- * Check if a DOM element matches a definition
4
+ * Check if a virtual node matches a definition
5
5
  *
6
6
  * Example:
7
7
  * ```js
8
8
  * // Match a single nodeName:
9
- * axe.commons.matches(elm, 'div')
9
+ * axe.commons.matches(vNode, 'div')
10
10
  *
11
11
  * // Match one of multiple nodeNames:
12
- * axe.commons.matches(elm, ['ul', 'ol'])
12
+ * axe.commons.matches(vNode, ['ul', 'ol'])
13
13
  *
14
14
  * // Match a node with nodeName 'button' and with aria-hidden: true:
15
- * axe.commons.matches(elm, {
15
+ * axe.commons.matches(vNode, {
16
16
  * nodeName: 'button',
17
17
  * attributes: { 'aria-hidden': 'true' }
18
18
  * })
19
19
  *
20
20
  * // Mixed input. Match button nodeName, input[type=button] and input[type=reset]
21
- * axe.commons.matches(elm, ['button', {
21
+ * axe.commons.matches(vNode, ['button', {
22
22
  * nodeName: 'input', // nodeName match isn't case sensitive
23
23
  * properties: { type: ['button', 'reset'] }
24
24
  * }])
25
25
  * ```
26
26
  *
27
+ * @deprecated HTMLElement is deprecated, use VirtualNode instead
28
+ *
27
29
  * @namespace matches
28
30
  * @memberof axe.commons
29
- * @param {HTMLElement|VirtualNode} node node to verify attributes against constraints
31
+ * @param {HTMLElement|VirtualNode} vNode virtual node to verify attributes against constraints
30
32
  * @param {Array<ElementDefinition>|String|Object|Function|Regex} definition
31
- * @return {Boolean} true/ false based on if node passes the constraints expected
33
+ * @return {Boolean} true/ false based on if vNode passes the constraints expected
32
34
  */
33
- function matches(node, definition) {
34
- return matches.fromDefinition(node, definition);
35
+ function matches(vNode, definition) {
36
+ return matches.fromDefinition(vNode, definition);
35
37
  }
36
38
 
37
39
  commons.matches = matches;
@@ -1,34 +1,24 @@
1
1
  /* global matches */
2
- let isXHTMLGlobal;
3
2
  /**
4
- * Check if the nodeName of a node matches some value
3
+ * Check if the nodeName of a virtual node matches some value.
5
4
  *
6
- * Note: matches.nodeName(node, matcher) can be indirectly used through
7
- * matches(node, { nodeName: matcher })
5
+ * Note: matches.nodeName(vNode, matcher) can be indirectly used through
6
+ * matches(vNode, { nodeName: matcher })
8
7
  *
9
8
  * Example:
10
9
  * ```js
11
- * matches.nodeName(node, ['div', 'span'])
10
+ * matches.nodeName(vNode, ['div', 'span'])
12
11
  * ```
13
12
  *
14
- * @param {HTMLElement|VirtualNode} node
13
+ * @deprecated HTMLElement is deprecated, use VirtualNode instead
14
+ *
15
+ * @param {HTMLElement|VirtualNode} vNode
15
16
  * @param {Object} Attribute matcher
16
17
  * @returns {Boolean}
17
18
  */
18
- matches.nodeName = function matchNodeName(node, matcher, { isXHTML } = {}) {
19
- node = node.actualNode || node;
20
- if (typeof isXHTML === 'undefined') {
21
- // When the matcher is a string, use native .matches() function:
22
- if (typeof matcher === 'string') {
23
- return axe.utils.matchesSelector(node, matcher);
24
- }
25
-
26
- if (typeof isXHTMLGlobal === 'undefined') {
27
- isXHTMLGlobal = axe.utils.isXHTML(node.ownerDocument);
28
- }
29
- isXHTML = isXHTMLGlobal;
19
+ matches.nodeName = function matchNodeName(vNode, matcher) {
20
+ if (!(vNode instanceof axe.AbstractVirtualNode)) {
21
+ vNode = axe.utils.getNodeFromTree(vNode);
30
22
  }
31
-
32
- const nodeName = isXHTML ? node.nodeName : node.nodeName.toLowerCase();
33
- return matches.fromPrimative(nodeName, matcher);
23
+ return matches.fromPrimative(vNode.props.nodeName, matcher);
34
24
  };
@@ -1,25 +1,28 @@
1
1
  /* global matches */
2
2
 
3
3
  /**
4
- * Check if a node matches some attribute(s)
4
+ * Check if a virtual node matches some attribute(s)
5
5
  *
6
- * Note: matches.properties(node, matcher) can be indirectly used through
7
- * matches(node, { properties: matcher })
6
+ * Note: matches.properties(vNode, matcher) can be indirectly used through
7
+ * matches(vNode, { properties: matcher })
8
8
  *
9
9
  * Example:
10
10
  * ```js
11
- * matches.properties(node, {
11
+ * matches.properties(vNode, {
12
12
  * type: 'text', // Simple string match
13
13
  * value: value => value.trim() !== '', // None-empty value, using a function matcher
14
14
  * })
15
15
  * ```
16
16
  *
17
- * @param {HTMLElement|VirtualNode} node
17
+ * @deprecated HTMLElement is deprecated, use VirtualNode instead
18
+ *
19
+ * @param {HTMLElement|VirtualNode} vNode
18
20
  * @param {Object} matcher
19
21
  * @returns {Boolean}
20
22
  */
21
- matches.properties = function matchesProperties(node, matcher) {
22
- node = node.actualNode || node;
23
- const out = matches.fromFunction(propName => node[propName], matcher);
24
- return out;
23
+ matches.properties = function matchesProperties(vNode, matcher) {
24
+ if (!(vNode instanceof axe.AbstractVirtualNode)) {
25
+ vNode = axe.utils.getNodeFromTree(vNode);
26
+ }
27
+ return matches.fromFunction(propName => vNode.props[propName], matcher);
25
28
  };
@@ -71,30 +71,33 @@ function getUnicodeNonBmpRegExp() {
71
71
  * Regex for matching astral plane unicode
72
72
  * - http://kourge.net/projects/regexp-unicode-block
73
73
  */
74
- return new RegExp(
75
- '[' +
76
- '\u1D00-\u1D7F' + // Phonetic Extensions
77
- '\u1D80-\u1DBF' + // Phonetic Extensions Supplement
78
- '\u1DC0-\u1DFF' + // Combining Diacritical Marks Supplement
79
- // '\u2000-\u206F' + // General punctuation - handled in -> getPunctuationRegExp
80
- '\u20A0-\u20CF' + // Currency symbols
81
- '\u20D0-\u20FF' + // Combining Diacritical Marks for Symbols
82
- '\u2100-\u214F' + // Letter like symbols
83
- '\u2150-\u218F' + // Number forms (eg: Roman numbers)
84
- '\u2190-\u21FF' + // Arrows
85
- '\u2200-\u22FF' + // Mathematical operators
86
- '\u2300-\u23FF' + // Misc Technical
87
- '\u2400-\u243F' + // Control pictures
88
- '\u2440-\u245F' + // OCR
89
- '\u2460-\u24FF' + // Enclosed alpha numerics
90
- '\u2500-\u257F' + // Box Drawing
91
- '\u2580-\u259F' + // Block Elements
92
- '\u25A0-\u25FF' + // Geometric Shapes
93
- '\u2600-\u26FF' + // Misc Symbols
94
- '\u2700-\u27BF' + // Dingbats
95
- '\uE000-\uF8FF' + // Private Use
96
- ']'
97
- );
74
+
75
+ /**
76
+ * Notes on various unicode planes being used in the regex below:
77
+ * '\u1D00-\u1D7F' Phonetic Extensions
78
+ * '\u1D80-\u1DBF' Phonetic Extensions Supplement
79
+ * '\u1DC0-\u1DFF' Combining Diacritical Marks Supplement
80
+ * '\u20A0-\u20CF' Currency symbols
81
+ * '\u20D0-\u20FF' Combining Diacritical Marks for Symbols
82
+ * '\u2100-\u214F' Letter like symbols
83
+ * '\u2150-\u218F' Number forms (eg: Roman numbers)
84
+ * '\u2190-\u21FF' Arrows
85
+ * '\u2200-\u22FF' Mathematical operators
86
+ * '\u2300-\u23FF' Misc Technical
87
+ * '\u2400-\u243F' Control pictures
88
+ * '\u2440-\u245F' OCR
89
+ * '\u2460-\u24FF' Enclosed alpha numerics
90
+ * '\u2500-\u257F' Box Drawing
91
+ * '\u2580-\u259F' Block Elements
92
+ * '\u25A0-\u25FF' Geometric Shapes
93
+ * '\u2600-\u26FF' Misc Symbols
94
+ * '\u2700-\u27BF' Dingbats
95
+ * '\uE000-\uF8FF' Private Use
96
+ *
97
+ * Note: plane '\u2000-\u206F' used for General punctuation is excluded as it is handled in -> getPunctuationRegExp
98
+ */
99
+
100
+ return /[\u1D00-\u1D7F\u1D80-\u1DBF\u1DC0-\u1DFF\u20A0-\u20CF\u20D0-\u20FF\u2100-\u214F\u2150-\u218F\u2190-\u21FF\u2200-\u22FF\u2300-\u23FF\u2400-\u243F\u2440-\u245F\u2460-\u24FF\u2500-\u257F\u2580-\u259F\u25A0-\u25FF\u2600-\u26FF\u2700-\u27BF\uE000-\uF8FF]/g;
98
101
  }
99
102
 
100
103
  /**
@@ -1,3 +1,5 @@
1
+ let isXHTMLGlobal;
2
+
1
3
  // class is unused in the file...
2
4
  // eslint-disable-next-line no-unused-vars
3
5
  class VirtualNode extends axe.AbstractVirtualNode {
@@ -17,6 +19,11 @@ class VirtualNode extends axe.AbstractVirtualNode {
17
19
  this._isHidden = null; // will be populated by axe.utils.isHidden
18
20
  this._cache = {};
19
21
 
22
+ if (typeof isXHTMLGlobal === 'undefined') {
23
+ isXHTMLGlobal = axe.utils.isXHTML(node.ownerDocument);
24
+ }
25
+ this._isXHTML = isXHTMLGlobal;
26
+
20
27
  if (axe._cache.get('nodeMap')) {
21
28
  axe._cache.get('nodeMap').set(node, this);
22
29
  }
@@ -25,13 +32,14 @@ class VirtualNode extends axe.AbstractVirtualNode {
25
32
  // abstract Node properties so we can run axe in DOM-less environments.
26
33
  // add to the prototype so memory is shared across all virtual nodes
27
34
  get props() {
28
- const { nodeType, nodeName, id, type } = this.actualNode;
35
+ const { nodeType, nodeName, id, type, multiple } = this.actualNode;
29
36
 
30
37
  return {
31
38
  nodeType,
32
- nodeName: nodeName.toLowerCase(),
39
+ nodeName: this._isXHTML ? nodeName : nodeName.toLowerCase(),
33
40
  id,
34
- type
41
+ type,
42
+ multiple
35
43
  };
36
44
  }
37
45
 
@@ -36,7 +36,7 @@
36
36
  /**
37
37
  * array of supported & preload(able) asset types.
38
38
  */
39
- assets: ['cssom'],
39
+ assets: ['cssom', 'media'],
40
40
  /**
41
41
  * timeout value when resolving preload(able) assets
42
42
  */
@@ -9,11 +9,14 @@ axe.addReporter('v1', function(results, options, callback) {
9
9
  }
10
10
  var out = helpers.processAggregate(results, options);
11
11
 
12
- out.violations.forEach(result =>
12
+ const addFailureSummaries = result => {
13
13
  result.nodes.forEach(nodeResult => {
14
14
  nodeResult.failureSummary = helpers.failureSummary(nodeResult);
15
- })
16
- );
15
+ });
16
+ };
17
+
18
+ out.incomplete.forEach(addFailureSummaries);
19
+ out.violations.forEach(addFailureSummaries);
17
20
 
18
21
  callback({
19
22
  ...helpers.getEnvironmentData(),
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Wrapper for Node#contains; PhantomJS does not support Node#contains and erroneously reports that it does
2
+ * Wrapper for Node#contains
3
3
  * @method contains
4
4
  * @memberof axe.utils
5
5
  * @param {VirtualNode} vNode The candidate container VirtualNode
@@ -28,12 +28,12 @@ axe.utils.isHidden = function isHidden(el, recursed) {
28
28
 
29
29
  if (
30
30
  !style ||
31
- (!el.parentNode ||
32
- (style.getPropertyValue('display') === 'none' ||
33
- (!recursed &&
34
- // visibility is only accurate on the first element
35
- style.getPropertyValue('visibility') === 'hidden') ||
36
- el.getAttribute('aria-hidden') === 'true'))
31
+ !el.parentNode ||
32
+ style.getPropertyValue('display') === 'none' ||
33
+ (!recursed &&
34
+ // visibility is only accurate on the first element
35
+ style.getPropertyValue('visibility') === 'hidden') ||
36
+ el.getAttribute('aria-hidden') === 'true'
37
37
  ) {
38
38
  return true;
39
39
  }
@@ -0,0 +1,263 @@
1
+ function matchesTag(vNode, exp) {
2
+ return (
3
+ vNode.props.nodeType === 1 &&
4
+ (exp.tag === '*' || vNode.props.nodeName === exp.tag)
5
+ );
6
+ }
7
+
8
+ function matchesClasses(vNode, exp) {
9
+ return !exp.classes || exp.classes.every(cl => vNode.hasClass(cl.value));
10
+ }
11
+
12
+ function matchesAttributes(vNode, exp) {
13
+ return (
14
+ !exp.attributes ||
15
+ exp.attributes.every(att => {
16
+ var nodeAtt = vNode.attr(att.key);
17
+ return nodeAtt !== null && (!att.value || att.test(nodeAtt));
18
+ })
19
+ );
20
+ }
21
+
22
+ function matchesId(vNode, exp) {
23
+ return !exp.id || vNode.props.id === exp.id;
24
+ }
25
+
26
+ function matchesPseudos(target, exp) {
27
+ if (
28
+ !exp.pseudos ||
29
+ exp.pseudos.every(pseudo => {
30
+ if (pseudo.name === 'not') {
31
+ return !axe.utils.matchesExpression(target, pseudo.expressions[0]);
32
+ }
33
+ throw new Error(
34
+ 'the pseudo selector ' + pseudo.name + ' has not yet been implemented'
35
+ );
36
+ })
37
+ ) {
38
+ return true;
39
+ }
40
+ return false;
41
+ }
42
+
43
+ function matchExpression(vNode, expression) {
44
+ return (
45
+ matchesTag(vNode, expression) &&
46
+ matchesClasses(vNode, expression) &&
47
+ matchesAttributes(vNode, expression) &&
48
+ matchesId(vNode, expression) &&
49
+ matchesPseudos(vNode, expression)
50
+ );
51
+ }
52
+
53
+ var escapeRegExp = (function() {
54
+ /*! Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License */
55
+ var from = /(?=[\-\[\]{}()*+?.\\\^$|,#\s])/g;
56
+ var to = '\\';
57
+ return function(string) {
58
+ return string.replace(from, to);
59
+ };
60
+ })();
61
+
62
+ const reUnescape = /\\/g;
63
+ function convertAttributes(atts) {
64
+ /*! Credit Mootools Copyright Mootools, MIT License */
65
+ if (!atts) {
66
+ return;
67
+ }
68
+ return atts.map(att => {
69
+ const attributeKey = att.name.replace(reUnescape, '');
70
+ const attributeValue = (att.value || '').replace(reUnescape, '');
71
+ let test, regexp;
72
+
73
+ switch (att.operator) {
74
+ case '^=':
75
+ regexp = new RegExp('^' + escapeRegExp(attributeValue));
76
+ break;
77
+ case '$=':
78
+ regexp = new RegExp(escapeRegExp(attributeValue) + '$');
79
+ break;
80
+ case '~=':
81
+ regexp = new RegExp(
82
+ '(^|\\s)' + escapeRegExp(attributeValue) + '(\\s|$)'
83
+ );
84
+ break;
85
+ case '|=':
86
+ regexp = new RegExp('^' + escapeRegExp(attributeValue) + '(-|$)');
87
+ break;
88
+ case '=':
89
+ test = function(value) {
90
+ return attributeValue === value;
91
+ };
92
+ break;
93
+ case '*=':
94
+ test = function(value) {
95
+ return value && value.includes(attributeValue);
96
+ };
97
+ break;
98
+ case '!=':
99
+ test = function(value) {
100
+ return attributeValue !== value;
101
+ };
102
+ break;
103
+ default:
104
+ test = function(value) {
105
+ return !!value;
106
+ };
107
+ }
108
+
109
+ if (attributeValue === '' && /^[*$^]=$/.test(att.operator)) {
110
+ test = function() {
111
+ return false;
112
+ };
113
+ }
114
+
115
+ if (!test) {
116
+ test = function(value) {
117
+ return value && regexp.test(value);
118
+ };
119
+ }
120
+ return {
121
+ key: attributeKey,
122
+ value: attributeValue,
123
+ test: test
124
+ };
125
+ });
126
+ }
127
+
128
+ function convertClasses(classes) {
129
+ if (!classes) {
130
+ return;
131
+ }
132
+ return classes.map(className => {
133
+ className = className.replace(reUnescape, '');
134
+
135
+ return {
136
+ value: className,
137
+ regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
138
+ };
139
+ });
140
+ }
141
+
142
+ function convertPseudos(pseudos) {
143
+ if (!pseudos) {
144
+ return;
145
+ }
146
+ return pseudos.map(p => {
147
+ var expressions;
148
+
149
+ if (p.name === 'not') {
150
+ expressions = p.value;
151
+ expressions = expressions.selectors
152
+ ? expressions.selectors
153
+ : [expressions];
154
+ expressions = convertExpressions(expressions);
155
+ }
156
+ return {
157
+ name: p.name,
158
+ expressions: expressions,
159
+ value: p.value
160
+ };
161
+ });
162
+ }
163
+
164
+ /**
165
+ * convert the css-selector-parser format into the Slick format
166
+ * @private
167
+ * @param Array {Object} expressions
168
+ * @return Array {Object}
169
+ *
170
+ */
171
+ function convertExpressions(expressions) {
172
+ return expressions.map(exp => {
173
+ var newExp = [];
174
+ var rule = exp.rule;
175
+ while (rule) {
176
+ /* eslint no-restricted-syntax: 0 */
177
+ // `.tagName` is a property coming from the `CSSSelectorParser` library
178
+ newExp.push({
179
+ tag: rule.tagName ? rule.tagName.toLowerCase() : '*',
180
+ combinator: rule.nestingOperator ? rule.nestingOperator : ' ',
181
+ id: rule.id,
182
+ attributes: convertAttributes(rule.attrs),
183
+ classes: convertClasses(rule.classNames),
184
+ pseudos: convertPseudos(rule.pseudos)
185
+ });
186
+ rule = rule.rule;
187
+ }
188
+ return newExp;
189
+ });
190
+ }
191
+
192
+ /**
193
+ * Convert a CSS selector to the Slick format expression
194
+ *
195
+ * @private
196
+ * @param {String} selector CSS selector to convert
197
+ * @returns {Object[]} Array of Slick format expressions
198
+ */
199
+ axe.utils.convertSelector = function convertSelector(selector) {
200
+ var expressions = axe.utils.cssParser.parse(selector);
201
+ expressions = expressions.selectors ? expressions.selectors : [expressions];
202
+ return convertExpressions(expressions);
203
+ };
204
+
205
+ /**
206
+ * Determine if a virtual node matches a Slick format CSS expression
207
+ *
208
+ * @private
209
+ * @method matchesExpression
210
+ * @memberof axe.utils
211
+ * @param {VirtualNode} vNode VirtualNode to match
212
+ * @param {Object|Object[]} expressions CSS selector expression or array of expressions
213
+ * @returns {Boolean}
214
+ */
215
+ axe.utils.matchesExpression = function matchesExpression(
216
+ vNode,
217
+ expressions,
218
+ matchAnyParent
219
+ ) {
220
+ let exps = [].concat(expressions);
221
+ let expression = exps.pop();
222
+ let matches = matchExpression(vNode, expression);
223
+
224
+ while (!matches && matchAnyParent && vNode.parent) {
225
+ vNode = vNode.parent;
226
+ matches = matchExpression(vNode, expression);
227
+ }
228
+
229
+ if (exps.length) {
230
+ if ([' ', '>'].includes(expression.combinator) === false) {
231
+ throw new Error(
232
+ 'axe.utils.matchesExpression does not support the combinator: ' +
233
+ expression.combinator
234
+ );
235
+ }
236
+
237
+ matches =
238
+ matches &&
239
+ axe.utils.matchesExpression(
240
+ vNode.parent,
241
+ exps,
242
+ expression.combinator === ' '
243
+ );
244
+ }
245
+
246
+ return matches;
247
+ };
248
+
249
+ /**
250
+ * matches implementation that operates on a VirtualNode
251
+ *
252
+ * @method matches
253
+ * @memberof axe.utils
254
+ * @param {VirtualNode} vNode VirtualNode to match
255
+ * @param {String} selector CSS selector string
256
+ * @return {Boolean}
257
+ */
258
+ axe.utils.matches = function matches(vNode, selector) {
259
+ let expressions = axe.utils.convertSelector(selector);
260
+ return expressions.some(expression =>
261
+ axe.utils.matchesExpression(vNode, expression)
262
+ );
263
+ };