accented 0.0.0-20250424114613 → 0.0.0-20250701143712

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +44 -193
  2. package/dist/accented.d.ts +7 -7
  3. package/dist/accented.d.ts.map +1 -1
  4. package/dist/accented.js +30 -27
  5. package/dist/accented.js.map +1 -1
  6. package/dist/common/tokens.d.ts +2 -0
  7. package/dist/common/tokens.d.ts.map +1 -0
  8. package/dist/common/tokens.js +2 -0
  9. package/dist/common/tokens.js.map +1 -0
  10. package/dist/constants.d.ts +1 -1
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +1 -1
  13. package/dist/constants.js.map +1 -1
  14. package/dist/dom-updater.d.ts +1 -1
  15. package/dist/dom-updater.d.ts.map +1 -1
  16. package/dist/dom-updater.js +14 -13
  17. package/dist/dom-updater.js.map +1 -1
  18. package/dist/elements/accented-dialog.d.ts +2 -3
  19. package/dist/elements/accented-dialog.d.ts.map +1 -1
  20. package/dist/elements/accented-dialog.js +14 -8
  21. package/dist/elements/accented-dialog.js.map +1 -1
  22. package/dist/elements/accented-trigger.d.ts +3 -4
  23. package/dist/elements/accented-trigger.d.ts.map +1 -1
  24. package/dist/elements/accented-trigger.js +10 -10
  25. package/dist/elements/accented-trigger.js.map +1 -1
  26. package/dist/fullscreen-listener.d.ts +1 -1
  27. package/dist/fullscreen-listener.d.ts.map +1 -1
  28. package/dist/fullscreen-listener.js +3 -4
  29. package/dist/fullscreen-listener.js.map +1 -1
  30. package/dist/intersection-observer.d.ts +1 -1
  31. package/dist/intersection-observer.d.ts.map +1 -1
  32. package/dist/intersection-observer.js +12 -6
  33. package/dist/intersection-observer.js.map +1 -1
  34. package/dist/log-and-rethrow.d.ts +1 -1
  35. package/dist/log-and-rethrow.d.ts.map +1 -1
  36. package/dist/log-and-rethrow.js +2 -3
  37. package/dist/log-and-rethrow.js.map +1 -1
  38. package/dist/logger.d.ts +1 -1
  39. package/dist/logger.d.ts.map +1 -1
  40. package/dist/logger.js +2 -2
  41. package/dist/logger.js.map +1 -1
  42. package/dist/register-elements.d.ts +1 -1
  43. package/dist/register-elements.d.ts.map +1 -1
  44. package/dist/register-elements.js +6 -7
  45. package/dist/register-elements.js.map +1 -1
  46. package/dist/resize-listener.d.ts +1 -1
  47. package/dist/resize-listener.d.ts.map +1 -1
  48. package/dist/resize-listener.js +3 -4
  49. package/dist/resize-listener.js.map +1 -1
  50. package/dist/scanner.d.ts +2 -2
  51. package/dist/scanner.d.ts.map +1 -1
  52. package/dist/scanner.js +36 -36
  53. package/dist/scanner.js.map +1 -1
  54. package/dist/scroll-listeners.d.ts +1 -1
  55. package/dist/scroll-listeners.d.ts.map +1 -1
  56. package/dist/scroll-listeners.js +3 -4
  57. package/dist/scroll-listeners.js.map +1 -1
  58. package/dist/state.d.ts +1 -1
  59. package/dist/state.d.ts.map +1 -1
  60. package/dist/state.js +4 -5
  61. package/dist/state.js.map +1 -1
  62. package/dist/task-queue.d.ts +2 -2
  63. package/dist/task-queue.d.ts.map +1 -1
  64. package/dist/task-queue.js +1 -1
  65. package/dist/task-queue.js.map +1 -1
  66. package/dist/types.d.ts +102 -46
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/types.js.map +1 -1
  69. package/dist/utils/are-elements-with-issues-equal.d.ts +2 -2
  70. package/dist/utils/are-elements-with-issues-equal.d.ts.map +1 -1
  71. package/dist/utils/are-elements-with-issues-equal.js +3 -3
  72. package/dist/utils/are-elements-with-issues-equal.js.map +1 -1
  73. package/dist/utils/are-issue-sets-equal.d.ts +2 -2
  74. package/dist/utils/are-issue-sets-equal.d.ts.map +1 -1
  75. package/dist/utils/are-issue-sets-equal.js +3 -3
  76. package/dist/utils/are-issue-sets-equal.js.map +1 -1
  77. package/dist/utils/containing-blocks.d.ts.map +1 -1
  78. package/dist/utils/containing-blocks.js +1 -1
  79. package/dist/utils/containing-blocks.js.map +1 -1
  80. package/dist/utils/contains.d.ts +1 -1
  81. package/dist/utils/contains.d.ts.map +1 -1
  82. package/dist/utils/contains.js +1 -1
  83. package/dist/utils/contains.js.map +1 -1
  84. package/dist/utils/deduplicate-nodes.js +0 -1
  85. package/dist/utils/deduplicate-nodes.js.map +1 -1
  86. package/dist/utils/deep-merge.d.ts +1 -1
  87. package/dist/utils/deep-merge.d.ts.map +1 -1
  88. package/dist/utils/deep-merge.js +8 -5
  89. package/dist/utils/deep-merge.js.map +1 -1
  90. package/dist/utils/dom-helpers.d.ts.map +1 -1
  91. package/dist/utils/dom-helpers.js +4 -2
  92. package/dist/utils/dom-helpers.js.map +1 -1
  93. package/dist/utils/ensure-non-empty.d.ts +1 -1
  94. package/dist/utils/ensure-non-empty.d.ts.map +1 -1
  95. package/dist/utils/ensure-non-empty.js +2 -2
  96. package/dist/utils/ensure-non-empty.js.map +1 -1
  97. package/dist/utils/get-element-html.d.ts +1 -1
  98. package/dist/utils/get-element-html.d.ts.map +1 -1
  99. package/dist/utils/get-element-html.js +4 -2
  100. package/dist/utils/get-element-html.js.map +1 -1
  101. package/dist/utils/get-element-position.d.ts +2 -2
  102. package/dist/utils/get-element-position.d.ts.map +1 -1
  103. package/dist/utils/get-element-position.js +21 -25
  104. package/dist/utils/get-element-position.js.map +1 -1
  105. package/dist/utils/get-parent.d.ts +1 -1
  106. package/dist/utils/get-parent.d.ts.map +1 -1
  107. package/dist/utils/get-parent.js +1 -1
  108. package/dist/utils/get-parent.js.map +1 -1
  109. package/dist/utils/get-scan-context.d.ts +2 -2
  110. package/dist/utils/get-scan-context.d.ts.map +1 -1
  111. package/dist/utils/get-scan-context.js +9 -9
  112. package/dist/utils/get-scan-context.js.map +1 -1
  113. package/dist/utils/get-scrollable-ancestors.d.ts +1 -1
  114. package/dist/utils/get-scrollable-ancestors.d.ts.map +1 -1
  115. package/dist/utils/get-scrollable-ancestors.js +5 -5
  116. package/dist/utils/get-scrollable-ancestors.js.map +1 -1
  117. package/dist/utils/is-node-in-scan-context.d.ts +2 -2
  118. package/dist/utils/is-node-in-scan-context.d.ts.map +1 -1
  119. package/dist/utils/is-node-in-scan-context.js +5 -5
  120. package/dist/utils/is-node-in-scan-context.js.map +1 -1
  121. package/dist/utils/is-non-empty.d.ts +2 -0
  122. package/dist/utils/is-non-empty.d.ts.map +1 -0
  123. package/dist/utils/is-non-empty.js +4 -0
  124. package/dist/utils/is-non-empty.js.map +1 -0
  125. package/dist/utils/normalize-context.d.ts +2 -2
  126. package/dist/utils/normalize-context.d.ts.map +1 -1
  127. package/dist/utils/normalize-context.js +10 -8
  128. package/dist/utils/normalize-context.js.map +1 -1
  129. package/dist/utils/recalculate-positions.d.ts +1 -1
  130. package/dist/utils/recalculate-positions.d.ts.map +1 -1
  131. package/dist/utils/recalculate-positions.js +5 -5
  132. package/dist/utils/recalculate-positions.js.map +1 -1
  133. package/dist/utils/recalculate-scrollable-ancestors.d.ts +1 -1
  134. package/dist/utils/recalculate-scrollable-ancestors.d.ts.map +1 -1
  135. package/dist/utils/recalculate-scrollable-ancestors.js +4 -4
  136. package/dist/utils/recalculate-scrollable-ancestors.js.map +1 -1
  137. package/dist/utils/shadow-dom-aware-mutation-observer.d.ts +1 -1
  138. package/dist/utils/shadow-dom-aware-mutation-observer.d.ts.map +1 -1
  139. package/dist/utils/shadow-dom-aware-mutation-observer.js +19 -22
  140. package/dist/utils/shadow-dom-aware-mutation-observer.js.map +1 -1
  141. package/dist/utils/supports-anchor-positioning.d.ts +1 -1
  142. package/dist/utils/supports-anchor-positioning.d.ts.map +1 -1
  143. package/dist/utils/supports-anchor-positioning.js +1 -1
  144. package/dist/utils/supports-anchor-positioning.js.map +1 -1
  145. package/dist/utils/transform-violations.d.ts +2 -2
  146. package/dist/utils/transform-violations.d.ts.map +1 -1
  147. package/dist/utils/transform-violations.js +9 -9
  148. package/dist/utils/transform-violations.js.map +1 -1
  149. package/dist/utils/update-elements-with-issues.d.ts +3 -3
  150. package/dist/utils/update-elements-with-issues.d.ts.map +1 -1
  151. package/dist/utils/update-elements-with-issues.js +34 -29
  152. package/dist/utils/update-elements-with-issues.js.map +1 -1
  153. package/dist/validate-options.d.ts +2 -2
  154. package/dist/validate-options.d.ts.map +1 -1
  155. package/dist/validate-options.js +24 -23
  156. package/dist/validate-options.js.map +1 -1
  157. package/package.json +7 -4
  158. package/src/accented.test.ts +2 -2
  159. package/src/accented.ts +39 -32
  160. package/src/common/tokens.ts +1 -0
  161. package/src/constants.ts +1 -1
  162. package/src/dom-updater.ts +26 -19
  163. package/src/elements/accented-dialog.ts +69 -43
  164. package/src/elements/accented-trigger.ts +54 -43
  165. package/src/fullscreen-listener.ts +15 -11
  166. package/src/intersection-observer.ts +27 -16
  167. package/src/log-and-rethrow.ts +2 -3
  168. package/src/logger.ts +8 -6
  169. package/src/register-elements.ts +7 -7
  170. package/src/resize-listener.ts +15 -11
  171. package/src/scanner.ts +66 -50
  172. package/src/scroll-listeners.ts +27 -19
  173. package/src/state.ts +24 -21
  174. package/src/task-queue.test.ts +5 -4
  175. package/src/task-queue.ts +2 -2
  176. package/src/types.ts +151 -95
  177. package/src/utils/are-elements-with-issues-equal.ts +7 -5
  178. package/src/utils/are-issue-sets-equal.test.ts +10 -6
  179. package/src/utils/are-issue-sets-equal.ts +8 -6
  180. package/src/utils/containing-blocks.ts +6 -3
  181. package/src/utils/contains.test.ts +2 -2
  182. package/src/utils/contains.ts +1 -1
  183. package/src/utils/deduplicate-nodes.ts +1 -1
  184. package/src/utils/deep-merge.test.ts +8 -1
  185. package/src/utils/deep-merge.ts +14 -8
  186. package/src/utils/dom-helpers.ts +6 -2
  187. package/src/utils/ensure-non-empty.ts +2 -2
  188. package/src/utils/get-element-html.ts +4 -2
  189. package/src/utils/get-element-position.ts +37 -24
  190. package/src/utils/get-parent.ts +1 -1
  191. package/src/utils/get-scan-context.test.ts +14 -8
  192. package/src/utils/get-scan-context.ts +12 -15
  193. package/src/utils/get-scrollable-ancestors.ts +8 -5
  194. package/src/utils/is-node-in-scan-context.test.ts +3 -3
  195. package/src/utils/is-node-in-scan-context.ts +6 -6
  196. package/src/utils/is-non-empty.ts +3 -0
  197. package/src/utils/normalize-context.test.ts +9 -9
  198. package/src/utils/normalize-context.ts +17 -10
  199. package/src/utils/recalculate-positions.ts +5 -5
  200. package/src/utils/recalculate-scrollable-ancestors.ts +4 -4
  201. package/src/utils/shadow-dom-aware-mutation-observer.ts +21 -24
  202. package/src/utils/supports-anchor-positioning.ts +3 -3
  203. package/src/utils/transform-violations.test.ts +22 -20
  204. package/src/utils/transform-violations.ts +14 -10
  205. package/src/utils/update-elements-with-issues.test.ts +49 -49
  206. package/src/utils/update-elements-with-issues.ts +96 -71
  207. package/src/validate-options.ts +91 -38
@@ -1,7 +1,7 @@
1
- import { JSDOM } from 'jsdom';
2
1
  import assert from 'node:assert/strict';
3
2
  import { suite, test } from 'node:test';
4
- import getScanContext from './get-scan-context';
3
+ import { JSDOM } from 'jsdom';
4
+ import { getScanContext } from './get-scan-context';
5
5
 
6
6
  suite('getScanContext', () => {
7
7
  test('when context doesn’t overlap with nodes, the result is empty', () => {
@@ -13,7 +13,7 @@ suite('getScanContext', () => {
13
13
 
14
14
  assert.deepEqual(scanContext, {
15
15
  include: [],
16
- exclude: []
16
+ exclude: [],
17
17
  });
18
18
  });
19
19
 
@@ -27,7 +27,7 @@ suite('getScanContext', () => {
27
27
 
28
28
  assert.deepEqual(scanContext, {
29
29
  include: [contextNode],
30
- exclude: []
30
+ exclude: [],
31
31
  });
32
32
  });
33
33
 
@@ -44,13 +44,16 @@ suite('getScanContext', () => {
44
44
  const { document } = dom.window;
45
45
  global.document = document;
46
46
  const mutatedNode = document.querySelector('#mutated-node')!;
47
- const scanContext = getScanContext([mutatedNode], {include: ['.include'], exclude: ['.exclude']});
47
+ const scanContext = getScanContext([mutatedNode], {
48
+ include: ['.include'],
49
+ exclude: ['.exclude'],
50
+ });
48
51
  const innerExclude = document.querySelector('#inner-exclude')!;
49
52
  const innerInclude = document.querySelector('#inner-include')!;
50
53
 
51
54
  assert.deepEqual(scanContext, {
52
55
  include: [mutatedNode, innerInclude],
53
- exclude: [innerExclude]
56
+ exclude: [innerExclude],
54
57
  });
55
58
  });
56
59
 
@@ -67,13 +70,16 @@ suite('getScanContext', () => {
67
70
  const { document } = dom.window;
68
71
  global.document = document;
69
72
  const mutatedNode = document.querySelector('#mutated-node')!;
70
- const scanContext = getScanContext([mutatedNode], {include: ['.include'], exclude: ['.exclude']});
73
+ const scanContext = getScanContext([mutatedNode], {
74
+ include: ['.include'],
75
+ exclude: ['.exclude'],
76
+ });
71
77
  const innerExclude = document.querySelector('#inner-exclude')!;
72
78
  const innerInclude = document.querySelector('#inner-include')!;
73
79
 
74
80
  assert.deepEqual(scanContext, {
75
81
  include: [innerInclude],
76
- exclude: [innerExclude]
82
+ exclude: [innerExclude],
77
83
  });
78
84
  });
79
85
  });
@@ -1,21 +1,18 @@
1
- import type { Context, ScanContext } from '../types';
2
- import contains from './contains.js';
1
+ import type { Context, ScanContext } from '../types.ts';
2
+ import { contains } from './contains.js';
3
3
  import { deduplicateNodes } from './deduplicate-nodes.js';
4
- import isNodeInScanContext from './is-node-in-scan-context.js';
5
- import normalizeContext from './normalize-context.js';
4
+ import { isNodeInScanContext } from './is-node-in-scan-context.js';
5
+ import { normalizeContext } from './normalize-context.js';
6
6
 
7
- export default function getScanContext(nodes: Array<Node>, context: Context): ScanContext {
8
- const {
9
- include: contextInclude,
10
- exclude: contextExclude
11
- } = normalizeContext(context);
7
+ export function getScanContext(nodes: Array<Node>, context: Context): ScanContext {
8
+ const { include: contextInclude, exclude: contextExclude } = normalizeContext(context);
12
9
 
13
10
  // Filter only nodes that are included by context (see isNodeInContext above).
14
- const nodesInContext = nodes.filter(node =>
11
+ const nodesInContext = nodes.filter((node) =>
15
12
  isNodeInScanContext(node, {
16
13
  include: contextInclude,
17
- exclude: contextExclude
18
- })
14
+ exclude: contextExclude,
15
+ }),
19
16
  );
20
17
 
21
18
  const include: Array<Node> = [];
@@ -26,14 +23,14 @@ export default function getScanContext(nodes: Array<Node>, context: Context): Sc
26
23
 
27
24
  // Now add any included and excluded context nodes that are contained by any of the original nodes.
28
25
  for (const node of nodes) {
29
- const includeDescendants = contextInclude.filter(item => contains(node, item));
26
+ const includeDescendants = contextInclude.filter((item) => contains(node, item));
30
27
  include.push(...includeDescendants);
31
- const excludeDescendants = contextExclude.filter(item => contains(node, item));
28
+ const excludeDescendants = contextExclude.filter((item) => contains(node, item));
32
29
  exclude.push(...excludeDescendants);
33
30
  }
34
31
 
35
32
  return {
36
33
  include: deduplicateNodes(include),
37
- exclude: deduplicateNodes(exclude)
34
+ exclude: deduplicateNodes(exclude),
38
35
  };
39
36
  }
@@ -1,19 +1,22 @@
1
- import getParent from './get-parent.js';
1
+ import { getParent } from './get-parent.js';
2
2
 
3
3
  const scrollableOverflowValues = new Set(['auto', 'scroll', 'hidden']);
4
4
 
5
- export default function getScrollableAncestors (element: Element, win: Window) {
5
+ export function getScrollableAncestors(element: Element, win: Window) {
6
6
  let currentElement: Element | null = element;
7
- let scrollableAncestors = new Set<Element>();
7
+ const scrollableAncestors = new Set<Element>();
8
8
  while (true) {
9
9
  currentElement = getParent(currentElement);
10
10
  if (!currentElement) {
11
11
  break;
12
12
  }
13
13
  const computedStyle = win.getComputedStyle(currentElement);
14
- if (scrollableOverflowValues.has(computedStyle.overflowX) || scrollableOverflowValues.has(computedStyle.overflowY)) {
14
+ if (
15
+ scrollableOverflowValues.has(computedStyle.overflowX) ||
16
+ scrollableOverflowValues.has(computedStyle.overflowY)
17
+ ) {
15
18
  scrollableAncestors.add(currentElement);
16
19
  }
17
20
  }
18
21
  return scrollableAncestors;
19
- };
22
+ }
@@ -1,7 +1,7 @@
1
- import { JSDOM } from 'jsdom';
2
1
  import assert from 'node:assert/strict';
3
- import {suite, test} from 'node:test';
4
- import isNodeInScanContext from './is-node-in-scan-context';
2
+ import { suite, test } from 'node:test';
3
+ import { JSDOM } from 'jsdom';
4
+ import { isNodeInScanContext } from './is-node-in-scan-context';
5
5
 
6
6
  suite('isNodeInScanContext', () => {
7
7
  test('doesn’t include an element if scan context is empty', () => {
@@ -1,8 +1,8 @@
1
1
  /* Adapted from https://github.com/dequelabs/axe-core/blob/fd6239bfc97ebc904044f93f68d7e49137f744ad/lib/core/utils/is-node-in-context.js */
2
2
 
3
- import type { ScanContext } from '../types';
4
- import contains from './contains.js';
5
- import ensureNonEmpty from './ensure-non-empty.js';
3
+ import type { ScanContext } from '../types.ts';
4
+ import { contains } from './contains.js';
5
+ import { ensureNonEmpty } from './ensure-non-empty.js';
6
6
 
7
7
  function getDeepest(nodes: [Node, ...Node[]]): Node {
8
8
  let deepest = nodes[0];
@@ -14,12 +14,12 @@ function getDeepest(nodes: [Node, ...Node[]]): Node {
14
14
  return deepest;
15
15
  }
16
16
 
17
- export default function isNodeInScanContext(node: Node, { include, exclude }: ScanContext): boolean {
18
- const filteredInclude = include.filter(includeNode => contains(includeNode, node));
17
+ export function isNodeInScanContext(node: Node, { include, exclude }: ScanContext): boolean {
18
+ const filteredInclude = include.filter((includeNode) => contains(includeNode, node));
19
19
  if (filteredInclude.length === 0) {
20
20
  return false;
21
21
  }
22
- const filteredExclude = exclude.filter(excludeNode => contains(excludeNode, node));
22
+ const filteredExclude = exclude.filter((excludeNode) => contains(excludeNode, node));
23
23
  if (filteredExclude.length === 0) {
24
24
  return true;
25
25
  }
@@ -0,0 +1,3 @@
1
+ export function isNonEmpty<T>(arr: T[]): arr is [T, ...T[]] {
2
+ return arr.length > 0;
3
+ }
@@ -1,7 +1,7 @@
1
- import { JSDOM } from 'jsdom';
2
1
  import assert from 'node:assert/strict';
3
2
  import { suite, test } from 'node:test';
4
- import normalizeContext from './normalize-context';
3
+ import { JSDOM } from 'jsdom';
4
+ import { normalizeContext } from './normalize-context';
5
5
 
6
6
  suite('normalizeContext', () => {
7
7
  test('when document is passed, only document is returned in include', () => {
@@ -11,7 +11,7 @@ suite('normalizeContext', () => {
11
11
 
12
12
  assert.deepEqual(normalizedContext, {
13
13
  include: [document],
14
- exclude: []
14
+ exclude: [],
15
15
  });
16
16
  });
17
17
 
@@ -23,7 +23,7 @@ suite('normalizeContext', () => {
23
23
 
24
24
  assert.deepEqual(normalizedContext, {
25
25
  include: [element],
26
- exclude: []
26
+ exclude: [],
27
27
  });
28
28
  });
29
29
 
@@ -41,7 +41,7 @@ suite('normalizeContext', () => {
41
41
  assert.equal(matchingElements.length, 2);
42
42
  assert.deepEqual(normalizedContext, {
43
43
  include: matchingElements,
44
- exclude: []
44
+ exclude: [],
45
45
  });
46
46
  });
47
47
 
@@ -57,7 +57,7 @@ suite('normalizeContext', () => {
57
57
 
58
58
  assert.deepEqual(normalizedContext, {
59
59
  include: [],
60
- exclude: []
60
+ exclude: [],
61
61
  });
62
62
  });
63
63
 
@@ -74,7 +74,7 @@ suite('normalizeContext', () => {
74
74
  assert.equal(matchingElements.length, 2);
75
75
  assert.deepEqual(normalizedContext, {
76
76
  include: Array.from(matchingElements),
77
- exclude: []
77
+ exclude: [],
78
78
  });
79
79
  });
80
80
 
@@ -94,12 +94,12 @@ suite('normalizeContext', () => {
94
94
  shadowRoot.appendChild(matchingElement);
95
95
  matchingElements.push(matchingElement);
96
96
  }
97
- const normalizedContext = normalizeContext({fromShadowDom: ['.host', '.matches']});
97
+ const normalizedContext = normalizeContext({ fromShadowDom: ['.host', '.matches'] });
98
98
 
99
99
  assert.equal(matchingElements.length, 2);
100
100
  assert.deepEqual(normalizedContext, {
101
101
  include: matchingElements,
102
- exclude: []
102
+ exclude: [],
103
103
  });
104
104
  });
105
105
  });
@@ -1,13 +1,20 @@
1
- import type { Context, ContextProp, Selector, ScanContext } from '../types';
2
- import { isNode, isNodeList } from './dom-helpers.js';
1
+ import type { Context, ContextProp, ScanContext, Selector } from '../types.ts';
3
2
  import { deduplicateNodes } from './deduplicate-nodes.js';
3
+ import { isNode, isNodeList } from './dom-helpers.js';
4
+ import { isNonEmpty } from './is-non-empty.js';
4
5
 
5
- function recursiveSelectAll(selectors: Array<string>, root: Document | ShadowRoot): Array<Node> {
6
- const nodesOnCurrentLevel = root.querySelectorAll(selectors[0]!);
6
+ function recursiveSelectAll(
7
+ selectors: [string, ...string[]],
8
+ root: Document | ShadowRoot,
9
+ ): Array<Node> {
10
+ const nodesOnCurrentLevel = root.querySelectorAll(selectors[0]);
7
11
  if (selectors.length === 1) {
8
12
  return Array.from(nodesOnCurrentLevel);
9
13
  }
10
14
  const restSelectors: Array<string> = selectors.slice(1);
15
+ if (!isNonEmpty(restSelectors)) {
16
+ throw new Error('Error: the restSelectors array must not be empty.');
17
+ }
11
18
  const selected = [];
12
19
  for (const node of nodesOnCurrentLevel) {
13
20
  if (node.shadowRoot) {
@@ -20,24 +27,24 @@ function recursiveSelectAll(selectors: Array<string>, root: Document | ShadowRoo
20
27
  function selectorToNodes(selector: Selector): Array<Node> {
21
28
  if (typeof selector === 'string') {
22
29
  return recursiveSelectAll([selector], document);
23
- } else if (isNode(selector)) {
30
+ }
31
+ if (isNode(selector)) {
24
32
  return [selector];
25
- } else {
26
- return recursiveSelectAll(selector.fromShadowDom, document);
27
33
  }
34
+ return recursiveSelectAll(selector.fromShadowDom, document);
28
35
  }
29
36
 
30
37
  function contextPropToNodes(contextProp: ContextProp): Array<Node> {
31
38
  let nodes: Array<Node> = [];
32
39
  if (typeof contextProp === 'object' && (Array.isArray(contextProp) || isNodeList(contextProp))) {
33
- nodes = Array.from(contextProp).map(item => selectorToNodes(item)).flat();
40
+ nodes = Array.from(contextProp).flatMap((item) => selectorToNodes(item));
34
41
  } else {
35
42
  nodes = selectorToNodes(contextProp);
36
43
  }
37
44
  return deduplicateNodes(nodes);
38
45
  }
39
46
 
40
- export default function normalizeContext(context: Context): ScanContext {
47
+ export function normalizeContext(context: Context): ScanContext {
41
48
  let contextInclude: Array<Node> = [];
42
49
  let contextExclude: Array<Node> = [];
43
50
  if (typeof context === 'object' && ('include' in context || 'exclude' in context)) {
@@ -53,6 +60,6 @@ export default function normalizeContext(context: Context): ScanContext {
53
60
 
54
61
  return {
55
62
  include: contextInclude,
56
- exclude: contextExclude
63
+ exclude: contextExclude,
57
64
  };
58
65
  }
@@ -1,11 +1,11 @@
1
1
  import { batch } from '@preact/signals-core';
2
+ import { logAndRethrow } from '../log-and-rethrow.js';
2
3
  import { extendedElementsWithIssues } from '../state.js';
3
- import getElementPosition from './get-element-position.js';
4
- import logAndRethrow from '../log-and-rethrow.js';
4
+ import { getElementPosition } from './get-element-position.js';
5
5
 
6
6
  let frameRequested = false;
7
7
 
8
- export default function recalculatePositions() {
8
+ export function recalculatePositions() {
9
9
  if (frameRequested) {
10
10
  return;
11
11
  }
@@ -14,11 +14,11 @@ export default function recalculatePositions() {
14
14
  try {
15
15
  frameRequested = false;
16
16
  batch(() => {
17
- extendedElementsWithIssues.value.forEach(({ element, position, visible }) => {
17
+ for (const { element, position, visible } of extendedElementsWithIssues.value) {
18
18
  if (visible.value && element.isConnected) {
19
19
  position.value = getElementPosition(element, window);
20
20
  }
21
- });
21
+ }
22
22
  });
23
23
  } catch (error) {
24
24
  logAndRethrow(error);
@@ -1,13 +1,13 @@
1
1
  import { batch } from '@preact/signals-core';
2
2
  import { extendedElementsWithIssues } from '../state.js';
3
- import getScrollableAncestors from './get-scrollable-ancestors.js';
3
+ import { getScrollableAncestors } from './get-scrollable-ancestors.js';
4
4
 
5
- export default function recalculateScrollableAncestors() {
5
+ export function recalculateScrollableAncestors() {
6
6
  batch(() => {
7
- extendedElementsWithIssues.value.forEach(({ element, scrollableAncestors }) => {
7
+ for (const { element, scrollableAncestors } of extendedElementsWithIssues.value) {
8
8
  if (element.isConnected) {
9
9
  scrollableAncestors.value = getScrollableAncestors(element, window);
10
10
  }
11
- });
11
+ }
12
12
  });
13
13
  }
@@ -1,7 +1,7 @@
1
- import { isElement, isDocument, isDocumentFragment } from './dom-helpers.js';
2
1
  import { getAccentedElementNames } from '../constants.js';
2
+ import { isDocument, isDocumentFragment, isElement } from './dom-helpers.js';
3
3
 
4
- export default function createShadowDOMAwareMutationObserver (name: string, callback: MutationCallback) {
4
+ export function createShadowDOMAwareMutationObserver(name: string, callback: MutationCallback) {
5
5
  class ShadowDOMAwareMutationObserver extends MutationObserver {
6
6
  #shadowRoots = new Set();
7
7
 
@@ -10,22 +10,19 @@ export default function createShadowDOMAwareMutationObserver (name: string, call
10
10
  constructor(callback: MutationCallback) {
11
11
  super((mutations, observer) => {
12
12
  const accentedElementNames = getAccentedElementNames(name);
13
- const childListMutations = mutations
14
- .filter(mutation => mutation.type === 'childList')
13
+ const childListMutations = mutations.filter((mutation) => mutation.type === 'childList');
15
14
 
16
15
  const newElements = childListMutations
17
- .map(mutation => [...mutation.addedNodes])
18
- .flat()
19
- .filter(node => isElement(node))
20
- .filter(node => !accentedElementNames.includes(node.nodeName.toLowerCase()));
16
+ .flatMap((mutation) => [...mutation.addedNodes])
17
+ .filter((node) => isElement(node))
18
+ .filter((node) => !accentedElementNames.includes(node.nodeName.toLowerCase()));
21
19
 
22
20
  this.#observeShadowRoots(newElements);
23
21
 
24
22
  const removedElements = childListMutations
25
- .map(mutation => [...mutation.removedNodes])
26
- .flat()
27
- .filter(node => isElement(node))
28
- .filter(node => !accentedElementNames.includes(node.nodeName.toLowerCase()));
23
+ .flatMap((mutation) => [...mutation.removedNodes])
24
+ .filter((node) => isElement(node))
25
+ .filter((node) => !accentedElementNames.includes(node.nodeName.toLowerCase()));
29
26
 
30
27
  // Mutation observer has no "unobserve" method, so we're simply deleting
31
28
  // the elements from the set of shadow roots.
@@ -50,28 +47,28 @@ export default function createShadowDOMAwareMutationObserver (name: string, call
50
47
 
51
48
  #observeShadowRoots = (elements: Array<Element | Document | DocumentFragment>) => {
52
49
  const shadowRoots = elements
53
- .map(element => [...element.querySelectorAll('*')])
54
- .flat()
55
- .filter(element => element.shadowRoot)
56
- .map(element => element.shadowRoot!);
50
+ .flatMap((element) => [...element.querySelectorAll('*')])
51
+ .filter((element) => element.shadowRoot)
52
+ .map((element) => element.shadowRoot);
57
53
 
58
54
  for (const shadowRoot of shadowRoots) {
59
- this.#shadowRoots.add(shadowRoot);
60
- this.observe(shadowRoot, this.#options);
55
+ if (shadowRoot) {
56
+ this.#shadowRoots.add(shadowRoot);
57
+ this.observe(shadowRoot, this.#options);
58
+ }
61
59
  }
62
- }
60
+ };
63
61
 
64
62
  #deleteShadowRoots = (elements: Array<Element | Document | DocumentFragment>) => {
65
63
  const shadowRoots = elements
66
- .map(element => [...element.querySelectorAll('*')])
67
- .flat()
68
- .filter(element => element.shadowRoot)
69
- .map(element => element.shadowRoot!);
64
+ .flatMap((element) => [...element.querySelectorAll('*')])
65
+ .filter((element) => element.shadowRoot)
66
+ .map((element) => element.shadowRoot);
70
67
 
71
68
  for (const shadowRoot of shadowRoots) {
72
69
  this.#shadowRoots.delete(shadowRoot);
73
70
  }
74
- }
71
+ };
75
72
  }
76
73
 
77
74
  return new ShadowDOMAwareMutationObserver(callback);
@@ -1,7 +1,7 @@
1
1
  type WindowWithCSS = Window & {
2
- CSS: typeof CSS
3
- }
2
+ CSS: typeof CSS;
3
+ };
4
4
 
5
- export default function supportsAnchorPositioning(win: WindowWithCSS) {
5
+ export function supportsAnchorPositioning(win: WindowWithCSS) {
6
6
  return win.CSS.supports('anchor-name: --foo') && win.CSS.supports('position-anchor: --foo');
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert/strict';
2
- import {suite, test} from 'node:test';
3
- import transformViolations from './transform-violations';
2
+ import { suite, test } from 'node:test';
3
+ import { transformViolations } from './transform-violations';
4
4
 
5
5
  import type { AxeResults } from 'axe-core';
6
6
  type Violation = AxeResults['violations'][number];
@@ -12,7 +12,7 @@ const commonViolationProps1: Omit<Violation, 'nodes'> = {
12
12
  helpUrl: 'http://example.com',
13
13
  description: 'description1',
14
14
  tags: [],
15
- impact: 'serious'
15
+ impact: 'serious',
16
16
  };
17
17
 
18
18
  const commonViolationProps2: Omit<Violation, 'nodes'> = {
@@ -21,51 +21,51 @@ const commonViolationProps2: Omit<Violation, 'nodes'> = {
21
21
  helpUrl: 'http://example.com',
22
22
  description: 'description2',
23
23
  tags: [],
24
- impact: 'serious'
24
+ impact: 'serious',
25
25
  };
26
26
 
27
- const getRootNode = (): Node => ({} as Node);
27
+ const getRootNode = (): Node => ({}) as Node;
28
28
 
29
29
  // @ts-expect-error element is not HTMLElement
30
- const element1: HTMLElement = {getRootNode};
30
+ const element1: HTMLElement = { getRootNode };
31
31
  // @ts-expect-error element is not HTMLElement
32
- const element2: HTMLElement = {getRootNode};
32
+ const element2: HTMLElement = { getRootNode };
33
33
  // @ts-expect-error element is not HTMLElement
34
- const element3: HTMLElement = {getRootNode};
34
+ const element3: HTMLElement = { getRootNode };
35
35
 
36
36
  const commonNodeProps = {
37
37
  html: '<div></div>',
38
38
  any: [],
39
39
  all: [],
40
- none: []
40
+ none: [],
41
41
  };
42
42
 
43
43
  const node1: Node = {
44
44
  ...commonNodeProps,
45
45
  element: element1,
46
46
  target: ['div'],
47
- failureSummary: 'summary1'
47
+ failureSummary: 'summary1',
48
48
  };
49
49
 
50
50
  const node2: Node = {
51
51
  ...commonNodeProps,
52
52
  element: element2,
53
53
  target: ['div'],
54
- failureSummary: 'summary2'
54
+ failureSummary: 'summary2',
55
55
  };
56
56
 
57
57
  const node3: Node = {
58
58
  ...commonNodeProps,
59
59
  element: element3,
60
60
  target: ['div'],
61
- failureSummary: 'summary3'
61
+ failureSummary: 'summary3',
62
62
  };
63
63
 
64
64
  suite('transformViolations', () => {
65
65
  test('one violation, one element', () => {
66
66
  const violation: Violation = {
67
67
  ...commonViolationProps1,
68
- nodes: [node1]
68
+ nodes: [node1],
69
69
  };
70
70
  const elementsWithIssues = transformViolations([violation], 'accented');
71
71
  assert.equal(elementsWithIssues.length, 1);
@@ -78,15 +78,17 @@ suite('transformViolations', () => {
78
78
  test('two violations, two elements each', () => {
79
79
  const violation1: Violation = {
80
80
  ...commonViolationProps1,
81
- nodes: [node1, node2]
81
+ nodes: [node1, node2],
82
82
  };
83
83
  const violation2: Violation = {
84
84
  ...commonViolationProps2,
85
- nodes: [node1, node3]
85
+ nodes: [node1, node3],
86
86
  };
87
87
  const elementsWithIssues = transformViolations([violation1, violation2], 'accented');
88
88
  assert.equal(elementsWithIssues.length, 3);
89
- const elementWithTwoIssues = elementsWithIssues.find(elementWithIssues => elementWithIssues.element === element1);
89
+ const elementWithTwoIssues = elementsWithIssues.find(
90
+ (elementWithIssues) => elementWithIssues.element === element1,
91
+ );
90
92
  assert.equal(elementWithTwoIssues?.issues.length, 2);
91
93
  });
92
94
 
@@ -96,11 +98,11 @@ suite('transformViolations', () => {
96
98
  element: element1,
97
99
  // A target array whose length is > 1 signifies an element in an iframe
98
100
  target: ['iframe', 'div'],
99
- failureSummary: 'summary1'
101
+ failureSummary: 'summary1',
100
102
  };
101
103
  const violation: Violation = {
102
104
  ...commonViolationProps1,
103
- nodes: [node]
105
+ nodes: [node],
104
106
  };
105
107
 
106
108
  const elementsWithIssues = transformViolations([violation], 'accented');
@@ -113,11 +115,11 @@ suite('transformViolations', () => {
113
115
  element: element1,
114
116
  // A target that contains an array within the outer array signifies an element in shadow DOM
115
117
  target: [['div', 'div']],
116
- failureSummary: 'summary1'
118
+ failureSummary: 'summary1',
117
119
  };
118
120
  const violation: Violation = {
119
121
  ...commonViolationProps1,
120
- nodes: [node]
122
+ nodes: [node],
121
123
  };
122
124
 
123
125
  const elementsWithIssues = transformViolations([violation], 'accented');
@@ -1,5 +1,5 @@
1
1
  import type { AxeResults, ImpactValue } from 'axe-core';
2
- import type { Issue, ElementWithIssues } from '../types';
2
+ import type { ElementWithIssues, Issue } from '../types.ts';
3
3
 
4
4
  // This is a list of axe-core violations (their ids) that may be flagged by axe-core
5
5
  // as false positives if an Accented trigger is a descendant of the element with the issue.
@@ -10,12 +10,14 @@ const violationsAffectedByAccentedTriggers = [
10
10
  'label-content-name-mismatch',
11
11
  'list',
12
12
  'nested-interactive',
13
- 'scrollable-region-focusable' // The Accented trigger might make the content grow such that scrolling is required.
13
+ 'scrollable-region-focusable', // The Accented trigger might make the content grow such that scrolling is required.
14
14
  ];
15
15
 
16
16
  function maybeCausedByAccented(violationId: string, element: HTMLElement, name: string) {
17
- return violationsAffectedByAccentedTriggers.includes(violationId)
18
- && Boolean(element.querySelector(`${name}-trigger`));
17
+ return (
18
+ violationsAffectedByAccentedTriggers.includes(violationId) &&
19
+ Boolean(element.querySelector(`${name}-trigger`))
20
+ );
19
21
  }
20
22
 
21
23
  function impactCompare(a: ImpactValue, b: ImpactValue) {
@@ -23,7 +25,7 @@ function impactCompare(a: ImpactValue, b: ImpactValue) {
23
25
  return impactOrder.indexOf(a) - impactOrder.indexOf(b);
24
26
  }
25
27
 
26
- export default function transformViolations(violations: typeof AxeResults.violations, name: string) {
28
+ export function transformViolations(violations: typeof AxeResults.violations, name: string) {
27
29
  const elementsWithIssues: Array<ElementWithIssues> = [];
28
30
 
29
31
  for (const violation of violations) {
@@ -44,17 +46,19 @@ export default function transformViolations(violations: typeof AxeResults.violat
44
46
  title: violation.help,
45
47
  description: node.failureSummary ?? violation.description,
46
48
  url: violation.helpUrl,
47
- impact: violation.impact ?? null
49
+ impact: violation.impact ?? null,
48
50
  };
49
- const existingElementIndex = elementsWithIssues.findIndex(elementWithIssues => elementWithIssues.element === element);
50
- if (existingElementIndex === -1) {
51
+ const existingElement = elementsWithIssues.find(
52
+ (elementWithIssues) => elementWithIssues.element === element,
53
+ );
54
+ if (existingElement === undefined) {
51
55
  elementsWithIssues.push({
52
56
  element,
53
57
  rootNode: element.getRootNode(),
54
- issues: [issue]
58
+ issues: [issue],
55
59
  });
56
60
  } else {
57
- elementsWithIssues[existingElementIndex]!.issues.push(issue);
61
+ existingElement.issues.push(issue);
58
62
  }
59
63
  }
60
64
  }