testilo 51.2.1 → 52.1.0
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/.claude/settings.local.json +13 -0
- package/package.json +1 -1
- package/procs/score/tic.js +42 -13
- package/procs/score/tsp50.js +24 -5
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(gh pr *)",
|
|
5
|
+
"Read(//opt/homebrew/bin/**)",
|
|
6
|
+
"Bash(/opt/homebrew/bin/gh --version)",
|
|
7
|
+
"WebFetch(domain:github.com)",
|
|
8
|
+
"WebFetch(domain:patch-diff.githubusercontent.com)",
|
|
9
|
+
"Bash(curl -sL https://patch-diff.githubusercontent.com/raw/jrpool/testilo/pull/1.patch -o /tmp/pr1.patch)",
|
|
10
|
+
"Read(//tmp/**)"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
}
|
package/package.json
CHANGED
package/procs/score/tic.js
CHANGED
|
@@ -6444,7 +6444,7 @@ exports.issues = {
|
|
|
6444
6444
|
weight: 1,
|
|
6445
6445
|
tools: {
|
|
6446
6446
|
ed11y: {
|
|
6447
|
-
|
|
6447
|
+
blockquoteIsShort: {
|
|
6448
6448
|
variable: false,
|
|
6449
6449
|
quality: 1,
|
|
6450
6450
|
what: 'Block quote is shorter than 25 characters'
|
|
@@ -6895,31 +6895,36 @@ exports.issues = {
|
|
|
6895
6895
|
'select-name': {
|
|
6896
6896
|
variable: false,
|
|
6897
6897
|
quality: 1,
|
|
6898
|
-
what: 'select
|
|
6898
|
+
what: 'Element is select but has no accessible name'
|
|
6899
6899
|
}
|
|
6900
6900
|
},
|
|
6901
6901
|
htmlcs: {
|
|
6902
6902
|
'E-AAA.4_1_2.H91.Select.Name': {
|
|
6903
6903
|
variable: false,
|
|
6904
6904
|
quality: 1,
|
|
6905
|
-
what: '
|
|
6905
|
+
what: 'Element is select but has no accessible name'
|
|
6906
|
+
},
|
|
6907
|
+
'E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Select.Name': {
|
|
6908
|
+
variable: false,
|
|
6909
|
+
quality: 1,
|
|
6910
|
+
what: 'select element has no accessible name'
|
|
6906
6911
|
},
|
|
6907
6912
|
'E-AAA.4_1_2.H91.Select.Value': {
|
|
6908
6913
|
variable: false,
|
|
6909
6914
|
quality: 1,
|
|
6910
|
-
what: '
|
|
6915
|
+
what: 'Element is select but its value has no accessible name'
|
|
6911
6916
|
},
|
|
6912
6917
|
'W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Select.Value': {
|
|
6913
6918
|
variable: false,
|
|
6914
6919
|
quality: 1,
|
|
6915
|
-
what: '
|
|
6920
|
+
what: 'Element is select but its value has no accessible name'
|
|
6916
6921
|
}
|
|
6917
6922
|
},
|
|
6918
6923
|
wave: {
|
|
6919
6924
|
select_missing_label: {
|
|
6920
6925
|
variable: false,
|
|
6921
6926
|
quality: 1,
|
|
6922
|
-
what: '
|
|
6927
|
+
what: 'Element is select but has no label'
|
|
6923
6928
|
}
|
|
6924
6929
|
}
|
|
6925
6930
|
}
|
|
@@ -6934,14 +6939,14 @@ exports.issues = {
|
|
|
6934
6939
|
'Element option without attribute label must not be empty.': {
|
|
6935
6940
|
variable: false,
|
|
6936
6941
|
quality: 1,
|
|
6937
|
-
what: '
|
|
6942
|
+
what: 'Element is option with no label attribute but is empty'
|
|
6938
6943
|
}
|
|
6939
6944
|
},
|
|
6940
6945
|
nuVnu: {
|
|
6941
6946
|
'Element option without attribute label must not be empty.': {
|
|
6942
6947
|
variable: false,
|
|
6943
6948
|
quality: 1,
|
|
6944
|
-
what: '
|
|
6949
|
+
what: 'Element is option with no label attribute but is empty'
|
|
6945
6950
|
}
|
|
6946
6951
|
}
|
|
6947
6952
|
}
|
|
@@ -8918,11 +8923,6 @@ exports.issues = {
|
|
|
8918
8923
|
variable: false,
|
|
8919
8924
|
quality: 1,
|
|
8920
8925
|
what: 'ARIA hidden element is focusable or contains a focusable element'
|
|
8921
|
-
},
|
|
8922
|
-
'presentation-role-conflict': {
|
|
8923
|
-
variable: false,
|
|
8924
|
-
quality: 1,
|
|
8925
|
-
what: 'Element has a none/presentation role but is focusable or has a global ARIA state or property'
|
|
8926
8926
|
}
|
|
8927
8927
|
},
|
|
8928
8928
|
ibm: {
|
|
@@ -9802,6 +9802,35 @@ exports.issues = {
|
|
|
9802
9802
|
}
|
|
9803
9803
|
}
|
|
9804
9804
|
},
|
|
9805
|
+
presentationGlobal: {
|
|
9806
|
+
summary: 'global ARIA attribute nullifies presentation role',
|
|
9807
|
+
why: 'User encounters content intended to be hidden',
|
|
9808
|
+
wcag: '1.3.1',
|
|
9809
|
+
weight: 1,
|
|
9810
|
+
tools: {
|
|
9811
|
+
axe: {
|
|
9812
|
+
'presentation-role-conflict': {
|
|
9813
|
+
variable: false,
|
|
9814
|
+
quality: 1,
|
|
9815
|
+
what: 'Element has a none/presentation role but is focusable or has a global ARIA state or property'
|
|
9816
|
+
}
|
|
9817
|
+
},
|
|
9818
|
+
nuVal: {
|
|
9819
|
+
'The presentation role does not affect elements that have global ARIA attributes.': {
|
|
9820
|
+
variable: false,
|
|
9821
|
+
quality: 1,
|
|
9822
|
+
what: 'Element has a presentation role but also a global ARIA attribute that nullifies the role'
|
|
9823
|
+
}
|
|
9824
|
+
},
|
|
9825
|
+
nuVnu: {
|
|
9826
|
+
'The presentation role does not affect elements that have global ARIA attributes.': {
|
|
9827
|
+
variable: false,
|
|
9828
|
+
quality: 1,
|
|
9829
|
+
what: 'Element has a presentation role but also a global ARIA attribute that nullifies the role'
|
|
9830
|
+
}
|
|
9831
|
+
}
|
|
9832
|
+
}
|
|
9833
|
+
},
|
|
9805
9834
|
presentationTabIndexed: {
|
|
9806
9835
|
summary: 'tabindex attribute nullifies presentation role',
|
|
9807
9836
|
why: 'User encounters content intended to be hidden',
|
package/procs/score/tsp50.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2026 Jeff Witt. All rights reserved.
|
|
3
4
|
|
|
4
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -263,11 +264,12 @@ exports.scorer = report => {
|
|
|
263
264
|
.texts
|
|
264
265
|
.push(what);
|
|
265
266
|
}
|
|
266
|
-
issuePaths[issueName] ??=
|
|
267
|
+
issuePaths[issueName] ??= {};
|
|
267
268
|
// If the element has a path ID:
|
|
268
269
|
if (pathID) {
|
|
269
|
-
// Ensure that it is in the issue-specific
|
|
270
|
-
issuePaths[issueName]
|
|
270
|
+
// Ensure that it is in the issue-specific map of paths to tools.
|
|
271
|
+
issuePaths[issueName][pathID] ??= new Set();
|
|
272
|
+
issuePaths[issueName][pathID].add(which);
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
}
|
|
@@ -323,6 +325,10 @@ exports.scorer = report => {
|
|
|
323
325
|
issueData.instanceCounts[toolName] = 0;
|
|
324
326
|
}
|
|
325
327
|
});
|
|
328
|
+
// Add the count of unique path-identified elements for the issue.
|
|
329
|
+
if (issuePaths[issueName]) {
|
|
330
|
+
issueData.uniqueElementCount = Object.keys(issuePaths[issueName]).length;
|
|
331
|
+
}
|
|
326
332
|
});
|
|
327
333
|
// Add the severity detail totals to the score.
|
|
328
334
|
details.severity.total = Object
|
|
@@ -333,9 +339,22 @@ exports.scorer = report => {
|
|
|
333
339
|
});
|
|
334
340
|
return severityTotals;
|
|
335
341
|
}, details.severity.total);
|
|
336
|
-
// Add the element details to the score.
|
|
342
|
+
// Add the element details to the score, grouped by detecting tools.
|
|
337
343
|
Object.keys(issuePaths).forEach(issueID => {
|
|
338
|
-
details.element[issueID] =
|
|
344
|
+
details.element[issueID] = {};
|
|
345
|
+
const issueElementDetails = details.element[issueID];
|
|
346
|
+
// For each element reported as exhibiting the issue:
|
|
347
|
+
Object.keys(issuePaths[issueID]).forEach(pathID => {
|
|
348
|
+
// Convert the set of tools reporting it to a string.
|
|
349
|
+
const toolList = Array.from(issuePaths[issueID][pathID]).sort().join(' + ');
|
|
350
|
+
issueElementDetails[toolList] ??= [];
|
|
351
|
+
// Classify the path by the set of tools reporting its element for the issue.
|
|
352
|
+
issueElementDetails[toolList].push(pathID);
|
|
353
|
+
});
|
|
354
|
+
// Sort the paths within each tool list.
|
|
355
|
+
Object.keys(issueElementDetails).forEach(toolList => {
|
|
356
|
+
issueElementDetails[toolList].sort();
|
|
357
|
+
});
|
|
339
358
|
});
|
|
340
359
|
// Add the summary issue-count total to the score.
|
|
341
360
|
summary.issueCount = Object.keys(details.issue).length * issueCountWeight;
|