testaro 40.0.0 → 40.0.2
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.
- package/package.json +1 -1
- package/testaro/role-old.js +0 -552
package/package.json
CHANGED
package/testaro/role-old.js
DELETED
|
@@ -1,552 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
© 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
-
|
|
4
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
-
in the Software without restriction, including without limitation the rights
|
|
7
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
-
furnished to do so, subject to the following conditions:
|
|
10
|
-
|
|
11
|
-
The above copyright notice and this permission notice shall be included in all
|
|
12
|
-
copies or substantial portions of the Software.
|
|
13
|
-
|
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
-
SOFTWARE.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
/*
|
|
24
|
-
role
|
|
25
|
-
This test reports role assignments that violate either an applicable standard or an applicable
|
|
26
|
-
recommendation from WAI-ARIA. Invalid roles include those that are abstract and thus prohibited
|
|
27
|
-
from direct use, and those that are implicit in HTML elements and thus advised against. Roles
|
|
28
|
-
that explicitly confirm implicit roles are deemed redundant and can be scored as less serious
|
|
29
|
-
than roles that override implicit roles. The math role has been removed, because of poor
|
|
30
|
-
adoption and exclusion from HTML5. The img role has accessibility uses, so is not classified
|
|
31
|
-
as deprecated. See:
|
|
32
|
-
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Role_Img
|
|
33
|
-
https://www.w3.org/TR/html-aria/
|
|
34
|
-
https://www.w3.org/TR/wai-aria/#roles_categorization
|
|
35
|
-
*/
|
|
36
|
-
exports.reporter = async page => await page.evaluate(() => {
|
|
37
|
-
|
|
38
|
-
// CONSTANTS
|
|
39
|
-
|
|
40
|
-
// All roles implicit in HTML elements.
|
|
41
|
-
const badRoles = new Set([
|
|
42
|
-
'article',
|
|
43
|
-
'banner',
|
|
44
|
-
'button',
|
|
45
|
-
'cell',
|
|
46
|
-
'checkbox',
|
|
47
|
-
'columnheader',
|
|
48
|
-
'combobox',
|
|
49
|
-
'complementary',
|
|
50
|
-
'contentinfo',
|
|
51
|
-
'definition',
|
|
52
|
-
'figure',
|
|
53
|
-
'graphics-document',
|
|
54
|
-
'gridcell',
|
|
55
|
-
'group',
|
|
56
|
-
'heading',
|
|
57
|
-
'link',
|
|
58
|
-
'list',
|
|
59
|
-
'listbox',
|
|
60
|
-
'listitem',
|
|
61
|
-
'main',
|
|
62
|
-
'navigation',
|
|
63
|
-
'option',
|
|
64
|
-
'progressbar',
|
|
65
|
-
'radio',
|
|
66
|
-
'row',
|
|
67
|
-
'rowgroup',
|
|
68
|
-
'rowheader',
|
|
69
|
-
'searchbox',
|
|
70
|
-
'separator',
|
|
71
|
-
'slider',
|
|
72
|
-
'spinbutton',
|
|
73
|
-
'status',
|
|
74
|
-
'table',
|
|
75
|
-
'term',
|
|
76
|
-
'textbox'
|
|
77
|
-
]);
|
|
78
|
-
// All non-abstract roles.
|
|
79
|
-
const goodRoles = new Set([
|
|
80
|
-
'alert',
|
|
81
|
-
'alertdialog',
|
|
82
|
-
'application',
|
|
83
|
-
'article',
|
|
84
|
-
'banner',
|
|
85
|
-
'button',
|
|
86
|
-
'cell',
|
|
87
|
-
'checkbox',
|
|
88
|
-
'columnheader',
|
|
89
|
-
'combobox',
|
|
90
|
-
'complementary',
|
|
91
|
-
'contentinfo',
|
|
92
|
-
'definition',
|
|
93
|
-
'dialog',
|
|
94
|
-
'directory',
|
|
95
|
-
'document',
|
|
96
|
-
'feed',
|
|
97
|
-
'figure',
|
|
98
|
-
'form',
|
|
99
|
-
'grid',
|
|
100
|
-
'gridcell',
|
|
101
|
-
'group',
|
|
102
|
-
'heading',
|
|
103
|
-
'img',
|
|
104
|
-
'link',
|
|
105
|
-
'list',
|
|
106
|
-
'listbox',
|
|
107
|
-
'listitem',
|
|
108
|
-
'log',
|
|
109
|
-
'main',
|
|
110
|
-
'marquee',
|
|
111
|
-
'menu',
|
|
112
|
-
'menubar',
|
|
113
|
-
'menuitem',
|
|
114
|
-
'menuitemcheckbox',
|
|
115
|
-
'menuitemradio',
|
|
116
|
-
'navigation',
|
|
117
|
-
'none',
|
|
118
|
-
'note',
|
|
119
|
-
'option',
|
|
120
|
-
'presentation',
|
|
121
|
-
'progressbar',
|
|
122
|
-
'radio',
|
|
123
|
-
'radiogroup',
|
|
124
|
-
'region',
|
|
125
|
-
'row',
|
|
126
|
-
'rowgroup',
|
|
127
|
-
'rowheader',
|
|
128
|
-
'scrollbar',
|
|
129
|
-
'search',
|
|
130
|
-
'searchbox',
|
|
131
|
-
'separator',
|
|
132
|
-
'separator',
|
|
133
|
-
'slider',
|
|
134
|
-
'spinbutton',
|
|
135
|
-
'status',
|
|
136
|
-
'switch',
|
|
137
|
-
'tab',
|
|
138
|
-
'table',
|
|
139
|
-
'tablist',
|
|
140
|
-
'tabpanel',
|
|
141
|
-
'term',
|
|
142
|
-
'textbox',
|
|
143
|
-
'timer',
|
|
144
|
-
'toolbar',
|
|
145
|
-
'tooltip',
|
|
146
|
-
'tree',
|
|
147
|
-
'treegrid',
|
|
148
|
-
'treeitem',
|
|
149
|
-
]);
|
|
150
|
-
// Implicit roles
|
|
151
|
-
const implicitRoles = {
|
|
152
|
-
article: 'article',
|
|
153
|
-
aside: 'complementary',
|
|
154
|
-
button: 'button',
|
|
155
|
-
datalist: 'listbox',
|
|
156
|
-
dd: 'definition',
|
|
157
|
-
details: 'group',
|
|
158
|
-
dfn: 'term',
|
|
159
|
-
dialog: 'dialog',
|
|
160
|
-
dt: 'term',
|
|
161
|
-
fieldset: 'group',
|
|
162
|
-
figure: 'figure',
|
|
163
|
-
hr: 'separator',
|
|
164
|
-
html: 'document',
|
|
165
|
-
li: 'listitem',
|
|
166
|
-
main: 'main',
|
|
167
|
-
math: 'math',
|
|
168
|
-
menu: 'list',
|
|
169
|
-
nav: 'navigation',
|
|
170
|
-
ol: 'list',
|
|
171
|
-
output: 'status',
|
|
172
|
-
progress: 'progressbar',
|
|
173
|
-
summary: 'button',
|
|
174
|
-
SVG: 'graphics-document',
|
|
175
|
-
table: 'table',
|
|
176
|
-
tbody: 'rowgroup',
|
|
177
|
-
textarea: 'textbox',
|
|
178
|
-
tfoot: 'rowgroup',
|
|
179
|
-
thead: 'rowgroup',
|
|
180
|
-
tr: 'row',
|
|
181
|
-
ul: 'list'
|
|
182
|
-
};
|
|
183
|
-
const implicitAttributes = {
|
|
184
|
-
a: [
|
|
185
|
-
{
|
|
186
|
-
role: 'link',
|
|
187
|
-
attributes: {
|
|
188
|
-
href: /./
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
],
|
|
192
|
-
area: [
|
|
193
|
-
{
|
|
194
|
-
role: 'link',
|
|
195
|
-
attributes: {
|
|
196
|
-
href: /./
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
],
|
|
200
|
-
h1: [
|
|
201
|
-
{
|
|
202
|
-
role: 'heading',
|
|
203
|
-
attributes: {
|
|
204
|
-
'aria-level': /^1$/
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
],
|
|
208
|
-
h2: [
|
|
209
|
-
{
|
|
210
|
-
role: 'heading',
|
|
211
|
-
attributes: {
|
|
212
|
-
'aria-level': /^2$/
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
role: 'heading',
|
|
217
|
-
attributes: {
|
|
218
|
-
'aria-level': false
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
],
|
|
222
|
-
h3: [
|
|
223
|
-
{
|
|
224
|
-
role: 'heading',
|
|
225
|
-
attributes: {
|
|
226
|
-
'aria-level': /^3$/
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
],
|
|
230
|
-
h4: [
|
|
231
|
-
{
|
|
232
|
-
role: 'heading',
|
|
233
|
-
attributes: {
|
|
234
|
-
'aria-level': /^4$/
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
],
|
|
238
|
-
h5: [
|
|
239
|
-
{
|
|
240
|
-
role: 'heading',
|
|
241
|
-
attributes: {
|
|
242
|
-
'aria-level': /^5$/
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
],
|
|
246
|
-
h6: [
|
|
247
|
-
{
|
|
248
|
-
role: 'heading',
|
|
249
|
-
attributes: {
|
|
250
|
-
'aria-level': /^6$/
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
],
|
|
254
|
-
input: [
|
|
255
|
-
{
|
|
256
|
-
role: 'checkbox',
|
|
257
|
-
attributes: {
|
|
258
|
-
type: /^checkbox$/
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
role: 'button',
|
|
263
|
-
attributes: {
|
|
264
|
-
type: /^(?:button|image|reset|submit)$/
|
|
265
|
-
}
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
role: 'combobox',
|
|
269
|
-
attributes: {
|
|
270
|
-
type: /^(?:email|search|tel|text|url)$/,
|
|
271
|
-
list: true
|
|
272
|
-
}
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
role: 'combobox',
|
|
276
|
-
attributes: {
|
|
277
|
-
type: false,
|
|
278
|
-
list: true
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
role: 'radio',
|
|
283
|
-
attributes: {
|
|
284
|
-
type: /^radio$/
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
role: 'searchbox',
|
|
289
|
-
attributes: {
|
|
290
|
-
type: /^search$/,
|
|
291
|
-
list: false
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
role: 'slider',
|
|
296
|
-
attributes: {
|
|
297
|
-
type: /^range$/
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
role: 'spinbutton',
|
|
302
|
-
attributes: {
|
|
303
|
-
type: /^number$/
|
|
304
|
-
}
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
role: 'textbox',
|
|
308
|
-
attributes: {
|
|
309
|
-
type: /^(?:email|tel|text|url)$/,
|
|
310
|
-
list: false
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
role: 'textbox',
|
|
315
|
-
attributes: {
|
|
316
|
-
type: false,
|
|
317
|
-
list: false
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
role: 'checkbox',
|
|
322
|
-
attributes: {
|
|
323
|
-
type: /^checkbox$/
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
role: 'checkbox',
|
|
328
|
-
attributes: {
|
|
329
|
-
type: /^checkbox$/
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
],
|
|
333
|
-
img: [
|
|
334
|
-
{
|
|
335
|
-
role: 'presentation',
|
|
336
|
-
attributes: {
|
|
337
|
-
alt: /^$/
|
|
338
|
-
}
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
role: 'img',
|
|
342
|
-
attributes: {
|
|
343
|
-
alt: /./
|
|
344
|
-
}
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
role: 'img',
|
|
348
|
-
attributes: {
|
|
349
|
-
alt: false
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
],
|
|
353
|
-
select: [
|
|
354
|
-
{
|
|
355
|
-
role: 'listbox',
|
|
356
|
-
attributes: {
|
|
357
|
-
multiple: true
|
|
358
|
-
}
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
role: 'listbox',
|
|
362
|
-
attributes: {
|
|
363
|
-
size: /^(?:[2-9]|[1-9]\d+)$/
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
role: 'combobox',
|
|
368
|
-
attributes: {
|
|
369
|
-
multiple: false,
|
|
370
|
-
size: false
|
|
371
|
-
}
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
role: 'combobox',
|
|
375
|
-
attributes: {
|
|
376
|
-
multiple: false,
|
|
377
|
-
size: /^1$/
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
]
|
|
381
|
-
};
|
|
382
|
-
// Array of th and td elements with redundant roles.
|
|
383
|
-
const redundantCells = [];
|
|
384
|
-
const {body} = document;
|
|
385
|
-
// Elements with role attributes.
|
|
386
|
-
const roleElements = Array.from(body.querySelectorAll('[role]'));
|
|
387
|
-
// th and td elements with redundant roles.
|
|
388
|
-
const gridHeaders = Array.from(
|
|
389
|
-
body.querySelectorAll('table[role=grid] th, table[role=treegrid] th')
|
|
390
|
-
);
|
|
391
|
-
const gridCells = Array.from(
|
|
392
|
-
body.querySelectorAll('table[role=grid] td, table[role=treegrid] td')
|
|
393
|
-
);
|
|
394
|
-
const tableHeaders = Array.from(
|
|
395
|
-
body.querySelectorAll('table[role=table] th, table:not([role]) th')
|
|
396
|
-
);
|
|
397
|
-
const tableCells = Array.from(
|
|
398
|
-
body.querySelectorAll('table[role=table] td, table:not([role]) td')
|
|
399
|
-
);
|
|
400
|
-
// Initialized result summrary.
|
|
401
|
-
const data = {
|
|
402
|
-
roleElements: roleElements.length,
|
|
403
|
-
badRoleElements: 0,
|
|
404
|
-
redundantRoleElements: 0,
|
|
405
|
-
tagNames: {}
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
// FUNCTIONS
|
|
409
|
-
|
|
410
|
-
// Initializes the result summary.
|
|
411
|
-
const dataInit = (data, tagName, role) => {
|
|
412
|
-
if (! data.tagNames[tagName]) {
|
|
413
|
-
data.tagNames[tagName] = {};
|
|
414
|
-
}
|
|
415
|
-
if (! data.tagNames[tagName][role]) {
|
|
416
|
-
data.tagNames[tagName][role] = {
|
|
417
|
-
bad: 0,
|
|
418
|
-
redundant: 0
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
// Adds table-element data to the result summary.
|
|
423
|
-
const tallyTableRedundancy = (elements, redundantRoles, tagName) => {
|
|
424
|
-
elements.forEach(element => {
|
|
425
|
-
const role = element.getAttribute('role');
|
|
426
|
-
if (redundantRoles.includes(role)) {
|
|
427
|
-
dataInit(data, tagName, role);
|
|
428
|
-
data.redundantRoleElements++;
|
|
429
|
-
data.tagNames[tagName][role].redundant++;
|
|
430
|
-
redundantCells.push(element);
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
// OPERATION
|
|
436
|
-
|
|
437
|
-
// Get the good (non-abstract, non-element-implicit) roles.
|
|
438
|
-
goodRoles.forEach(role => {
|
|
439
|
-
if (badRoles.has(role)) {
|
|
440
|
-
goodRoles.delete(role);
|
|
441
|
-
}
|
|
442
|
-
});
|
|
443
|
-
// Identify the table elements with redundant roles.
|
|
444
|
-
tallyTableRedundancy(gridHeaders, ['columnheader', 'rowheader', 'gridcell'], 'TH');
|
|
445
|
-
tallyTableRedundancy(gridCells, ['gridcell'], 'TD');
|
|
446
|
-
tallyTableRedundancy(tableHeaders, ['columnheader', 'rowheader', 'cell'], 'TH');
|
|
447
|
-
tallyTableRedundancy(tableCells, ['cell'], 'TD');
|
|
448
|
-
// Identify the additional elements with redundant roles and bad roles.
|
|
449
|
-
roleElements.filter(element => ! redundantCells.includes(element)).forEach(element => {
|
|
450
|
-
const role = element.getAttribute('role');
|
|
451
|
-
const tagName = element.tagName;
|
|
452
|
-
// If the role is not absolutely valid:
|
|
453
|
-
if (! goodRoles.has(role)) {
|
|
454
|
-
// If it is bad or redundant:
|
|
455
|
-
if (badRoles.has(role)) {
|
|
456
|
-
dataInit(data, tagName, role);
|
|
457
|
-
const lcTagName = tagName.toLowerCase();
|
|
458
|
-
// If it is simply redundant:
|
|
459
|
-
if (role === implicitRoles[lcTagName]) {
|
|
460
|
-
// Update the result summary.
|
|
461
|
-
data.redundantRoleElements++;
|
|
462
|
-
data.tagNames[tagName][role].redundant++;
|
|
463
|
-
}
|
|
464
|
-
// Otherwise, if it is attributionally redundant:
|
|
465
|
-
else if (
|
|
466
|
-
implicitAttributes[lcTagName] && implicitAttributes[lcTagName].some(
|
|
467
|
-
criterion => role === criterion.role && Object.keys(criterion.attributes).every(
|
|
468
|
-
attributeName => {
|
|
469
|
-
const rule = criterion.attributes[attributeName];
|
|
470
|
-
const exists = element.hasAttribute(attributeName);
|
|
471
|
-
const value = exists ? element.getAttribute(attributeName) : null;
|
|
472
|
-
if (rule === true) {
|
|
473
|
-
return exists;
|
|
474
|
-
}
|
|
475
|
-
else if (rule === false) {
|
|
476
|
-
return ! exists;
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
return rule.test(value);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
)
|
|
483
|
-
)
|
|
484
|
-
) {
|
|
485
|
-
// Update the results.
|
|
486
|
-
data.redundantRoleElements++;
|
|
487
|
-
data.tagNames[tagName][role].redundant++;
|
|
488
|
-
}
|
|
489
|
-
// Otherwise, i.e. if it is absolutely invalid:
|
|
490
|
-
else {
|
|
491
|
-
// Update the results.
|
|
492
|
-
data.badRoleElements++;
|
|
493
|
-
data.tagNames[tagName][role].bad++;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
// Otherwise, i.e. if it is absolutely invalid:
|
|
497
|
-
else {
|
|
498
|
-
// Update the results.
|
|
499
|
-
data.badRoleElements++;
|
|
500
|
-
dataInit(data, tagName, role);
|
|
501
|
-
data.tagNames[tagName][role].bad++;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
const standardInstances = [];
|
|
506
|
-
Object.keys(data.tagNames).forEach(tagName => {
|
|
507
|
-
Object.keys(data.tagNames[tagName]).forEach(role => {
|
|
508
|
-
const pairTotals = data.tagNames[tagName][role];
|
|
509
|
-
const redCount = pairTotals.redundant;
|
|
510
|
-
if (redCount) {
|
|
511
|
-
standardInstances.push({
|
|
512
|
-
ruleID: 'role',
|
|
513
|
-
what: `Elements have redundant explicit role ${role}`,
|
|
514
|
-
count: redCount,
|
|
515
|
-
ordinalSeverity: 1,
|
|
516
|
-
tagName,
|
|
517
|
-
id: '',
|
|
518
|
-
location: {
|
|
519
|
-
doc: '',
|
|
520
|
-
type: '',
|
|
521
|
-
spec: ''
|
|
522
|
-
},
|
|
523
|
-
excerpt: ''
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
const badCount = pairTotals.bad;
|
|
527
|
-
if (badCount) {
|
|
528
|
-
standardInstances.push({
|
|
529
|
-
ruleID: 'role',
|
|
530
|
-
what:
|
|
531
|
-
`Elements have invalid or native-replaceable explicit role ${role}`,
|
|
532
|
-
count: badCount,
|
|
533
|
-
ordinalSeverity: 3,
|
|
534
|
-
tagName,
|
|
535
|
-
id: '',
|
|
536
|
-
location: {
|
|
537
|
-
doc: '',
|
|
538
|
-
type: '',
|
|
539
|
-
spec: ''
|
|
540
|
-
},
|
|
541
|
-
excerpt: ''
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
});
|
|
546
|
-
// Return the result.
|
|
547
|
-
return {
|
|
548
|
-
data,
|
|
549
|
-
totals: [0, data.redundantRoleElements, 0, data.badRoleElements],
|
|
550
|
-
standardInstances
|
|
551
|
-
};
|
|
552
|
-
});
|