accessibility-checker 4.0.1 → 4.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.
Files changed (209) hide show
  1. package/bin/achecker.js +213 -262
  2. package/bin/achecker.js.map +1 -1
  3. package/cjs/bin/achecker.d.ts +2 -0
  4. package/cjs/bin/achecker.js +306 -0
  5. package/cjs/bin/achecker.js.map +1 -0
  6. package/cjs/index.d.ts +319 -0
  7. package/cjs/index.js +402 -0
  8. package/cjs/index.js.map +1 -0
  9. package/cjs/lib/ACBrowserManager.d.ts +22 -0
  10. package/cjs/lib/ACBrowserManager.js +172 -0
  11. package/cjs/lib/ACBrowserManager.js.map +1 -0
  12. package/cjs/lib/ACEngineManager.d.ts +19 -0
  13. package/cjs/lib/ACEngineManager.js +457 -0
  14. package/cjs/lib/ACEngineManager.js.map +1 -0
  15. package/cjs/lib/ACHelper.d.ts +2 -0
  16. package/cjs/lib/ACHelper.js +678 -0
  17. package/cjs/lib/ACHelper.js.map +1 -0
  18. package/cjs/lib/api/IChecker.d.ts +28 -0
  19. package/cjs/lib/api/IChecker.js +11 -0
  20. package/cjs/lib/api/IChecker.js.map +1 -0
  21. package/cjs/lib/api/IMapper.d.ts +37 -0
  22. package/cjs/lib/api/IMapper.js +18 -0
  23. package/cjs/lib/api/IMapper.js.map +1 -0
  24. package/cjs/lib/common/api-ext/Fetch.d.ts +17 -0
  25. package/cjs/lib/common/api-ext/Fetch.js +95 -0
  26. package/cjs/lib/common/api-ext/Fetch.js.map +1 -0
  27. package/cjs/lib/common/api-ext/IAbstractAPI.d.ts +33 -0
  28. package/cjs/lib/common/api-ext/IAbstractAPI.js +18 -0
  29. package/cjs/lib/common/api-ext/IAbstractAPI.js.map +1 -0
  30. package/cjs/lib/common/config/ACConfigManager.d.ts +13 -0
  31. package/cjs/lib/common/config/ACConfigManager.js +483 -0
  32. package/cjs/lib/common/config/ACConfigManager.js.map +1 -0
  33. package/cjs/lib/common/config/ACConstants.d.ts +17 -0
  34. package/cjs/lib/common/config/ACConstants.js +111 -0
  35. package/cjs/lib/common/config/ACConstants.js.map +1 -0
  36. package/cjs/lib/common/config/IArchive.d.ts +37 -0
  37. package/cjs/lib/common/config/IArchive.js +18 -0
  38. package/cjs/lib/common/config/IArchive.js.map +1 -0
  39. package/cjs/lib/common/config/IConfig.d.ts +152 -0
  40. package/cjs/lib/common/config/IConfig.js +36 -0
  41. package/cjs/lib/common/config/IConfig.js.map +1 -0
  42. package/cjs/lib/common/engine/IBounds.d.ts +21 -0
  43. package/cjs/lib/common/engine/IBounds.js +18 -0
  44. package/cjs/lib/common/engine/IBounds.js.map +1 -0
  45. package/cjs/lib/common/engine/IChecker.d.ts +23 -0
  46. package/cjs/lib/common/engine/IChecker.js +18 -0
  47. package/cjs/lib/common/engine/IChecker.js.map +1 -0
  48. package/cjs/lib/common/engine/IEngine.d.ts +39 -0
  49. package/cjs/lib/common/engine/IEngine.js +18 -0
  50. package/cjs/lib/common/engine/IEngine.js.map +1 -0
  51. package/cjs/lib/common/engine/IGuideline.d.ts +53 -0
  52. package/cjs/lib/common/engine/IGuideline.js +37 -0
  53. package/cjs/lib/common/engine/IGuideline.js.map +1 -0
  54. package/cjs/lib/common/engine/IMapper.d.ts +32 -0
  55. package/cjs/lib/common/engine/IMapper.js +18 -0
  56. package/cjs/lib/common/engine/IMapper.js.map +1 -0
  57. package/cjs/lib/common/engine/IReport.d.ts +143 -0
  58. package/cjs/lib/common/engine/IReport.js +44 -0
  59. package/cjs/lib/common/engine/IReport.js.map +1 -0
  60. package/cjs/lib/common/engine/IRule.d.ts +100 -0
  61. package/cjs/lib/common/engine/IRule.js +87 -0
  62. package/cjs/lib/common/engine/IRule.js.map +1 -0
  63. package/cjs/lib/common/engine/IRuleset.d.ts +20 -0
  64. package/cjs/lib/common/engine/IRuleset.js +18 -0
  65. package/cjs/lib/common/engine/IRuleset.js.map +1 -0
  66. package/cjs/lib/common/report/ACReporterCSV.d.ts +28 -0
  67. package/cjs/lib/common/report/ACReporterCSV.js +75 -0
  68. package/cjs/lib/common/report/ACReporterCSV.js.map +1 -0
  69. package/cjs/lib/common/report/ACReporterHTML.d.ts +27 -0
  70. package/cjs/lib/common/report/ACReporterHTML.js +61 -0
  71. package/cjs/lib/common/report/ACReporterHTML.js.map +1 -0
  72. package/cjs/lib/common/report/ACReporterJSON.d.ts +36 -0
  73. package/cjs/lib/common/report/ACReporterJSON.js +109 -0
  74. package/cjs/lib/common/report/ACReporterJSON.js.map +1 -0
  75. package/cjs/lib/common/report/ACReporterMetrics.d.ts +78 -0
  76. package/cjs/lib/common/report/ACReporterMetrics.js +135 -0
  77. package/cjs/lib/common/report/ACReporterMetrics.js.map +1 -0
  78. package/cjs/lib/common/report/ACReporterXLSX.d.ts +38 -0
  79. package/cjs/lib/common/report/ACReporterXLSX.js +996 -0
  80. package/cjs/lib/common/report/ACReporterXLSX.js.map +1 -0
  81. package/cjs/lib/common/report/BaselineManager.d.ts +169 -0
  82. package/cjs/lib/common/report/BaselineManager.js +382 -0
  83. package/cjs/lib/common/report/BaselineManager.js.map +1 -0
  84. package/cjs/lib/common/report/ReporterManager.d.ts +79 -0
  85. package/cjs/lib/common/report/ReporterManager.js +469 -0
  86. package/cjs/lib/common/report/ReporterManager.js.map +1 -0
  87. package/cjs/lib/common/report/genReport.d.ts +1 -0
  88. package/cjs/lib/common/report/genReport.js +12 -0
  89. package/cjs/lib/common/report/genReport.js.map +1 -0
  90. package/cjs/package.json +3 -0
  91. package/index.js +21 -63
  92. package/index.js.map +1 -1
  93. package/lib/ACBrowserManager.js +138 -203
  94. package/lib/ACBrowserManager.js.map +1 -1
  95. package/lib/ACEngineManager.js +395 -402
  96. package/lib/ACEngineManager.js.map +1 -1
  97. package/lib/ACHelper.js +581 -642
  98. package/lib/ACHelper.js.map +1 -1
  99. package/lib/common/api-ext/Fetch.js +58 -78
  100. package/lib/common/api-ext/Fetch.js.map +1 -1
  101. package/lib/common/config/ACConfigManager.js +271 -281
  102. package/lib/common/config/ACConfigManager.js.map +1 -1
  103. package/lib/common/config/ACConstants.js +38 -4
  104. package/lib/common/config/ACConstants.js.map +1 -1
  105. package/lib/common/config/IConfig.d.ts +1 -1
  106. package/lib/common/report/ACReporterCSV.js +42 -77
  107. package/lib/common/report/ACReporterCSV.js.map +1 -1
  108. package/lib/common/report/ACReporterHTML.js +15 -48
  109. package/lib/common/report/ACReporterHTML.js.map +1 -1
  110. package/lib/common/report/ACReporterJSON.js +59 -94
  111. package/lib/common/report/ACReporterJSON.js.map +1 -1
  112. package/lib/common/report/ACReporterMetrics.js +45 -108
  113. package/lib/common/report/ACReporterMetrics.js.map +1 -1
  114. package/lib/common/report/ACReporterXLSX.js +282 -300
  115. package/lib/common/report/ACReporterXLSX.js.map +1 -1
  116. package/lib/common/report/BaselineManager.js +82 -56
  117. package/lib/common/report/BaselineManager.js.map +1 -1
  118. package/lib/common/report/ReporterManager.js +125 -190
  119. package/lib/common/report/ReporterManager.js.map +1 -1
  120. package/lib/common/report/genReport.js +2 -2
  121. package/mjs/bin/achecker.d.ts +2 -0
  122. package/mjs/bin/achecker.js +236 -0
  123. package/mjs/bin/achecker.js.map +1 -0
  124. package/mjs/index.d.ts +319 -0
  125. package/mjs/index.js +368 -0
  126. package/mjs/index.js.map +1 -0
  127. package/mjs/lib/ACBrowserManager.d.ts +22 -0
  128. package/mjs/lib/ACBrowserManager.js +121 -0
  129. package/mjs/lib/ACBrowserManager.js.map +1 -0
  130. package/mjs/lib/ACEngineManager.d.ts +19 -0
  131. package/mjs/lib/ACEngineManager.js +397 -0
  132. package/mjs/lib/ACEngineManager.js.map +1 -0
  133. package/mjs/lib/ACHelper.d.ts +2 -0
  134. package/mjs/lib/ACHelper.js +614 -0
  135. package/mjs/lib/ACHelper.js.map +1 -0
  136. package/mjs/lib/api/IChecker.d.ts +28 -0
  137. package/mjs/lib/api/IChecker.js +8 -0
  138. package/mjs/lib/api/IChecker.js.map +1 -0
  139. package/mjs/lib/api/IMapper.d.ts +37 -0
  140. package/mjs/lib/api/IMapper.js +17 -0
  141. package/mjs/lib/api/IMapper.js.map +1 -0
  142. package/mjs/lib/common/api-ext/Fetch.d.ts +17 -0
  143. package/mjs/lib/common/api-ext/Fetch.js +45 -0
  144. package/mjs/lib/common/api-ext/Fetch.js.map +1 -0
  145. package/mjs/lib/common/api-ext/IAbstractAPI.d.ts +33 -0
  146. package/mjs/lib/common/api-ext/IAbstractAPI.js +17 -0
  147. package/mjs/lib/common/api-ext/IAbstractAPI.js.map +1 -0
  148. package/mjs/lib/common/config/ACConfigManager.d.ts +13 -0
  149. package/mjs/lib/common/config/ACConfigManager.js +421 -0
  150. package/mjs/lib/common/config/ACConfigManager.js.map +1 -0
  151. package/mjs/lib/common/config/ACConstants.d.ts +17 -0
  152. package/mjs/lib/common/config/ACConstants.js +75 -0
  153. package/mjs/lib/common/config/ACConstants.js.map +1 -0
  154. package/mjs/lib/common/config/IArchive.d.ts +37 -0
  155. package/mjs/lib/common/config/IArchive.js +17 -0
  156. package/mjs/lib/common/config/IArchive.js.map +1 -0
  157. package/mjs/lib/common/config/IConfig.d.ts +152 -0
  158. package/mjs/lib/common/config/IConfig.js +33 -0
  159. package/mjs/lib/common/config/IConfig.js.map +1 -0
  160. package/mjs/lib/common/engine/IBounds.d.ts +21 -0
  161. package/mjs/lib/common/engine/IBounds.js +17 -0
  162. package/mjs/lib/common/engine/IBounds.js.map +1 -0
  163. package/mjs/lib/common/engine/IChecker.d.ts +23 -0
  164. package/mjs/lib/common/engine/IChecker.js +17 -0
  165. package/mjs/lib/common/engine/IChecker.js.map +1 -0
  166. package/mjs/lib/common/engine/IEngine.d.ts +39 -0
  167. package/mjs/lib/common/engine/IEngine.js +17 -0
  168. package/mjs/lib/common/engine/IEngine.js.map +1 -0
  169. package/mjs/lib/common/engine/IGuideline.d.ts +53 -0
  170. package/mjs/lib/common/engine/IGuideline.js +34 -0
  171. package/mjs/lib/common/engine/IGuideline.js.map +1 -0
  172. package/mjs/lib/common/engine/IMapper.d.ts +32 -0
  173. package/mjs/lib/common/engine/IMapper.js +17 -0
  174. package/mjs/lib/common/engine/IMapper.js.map +1 -0
  175. package/mjs/lib/common/engine/IReport.d.ts +143 -0
  176. package/mjs/lib/common/engine/IReport.js +36 -0
  177. package/mjs/lib/common/engine/IReport.js.map +1 -0
  178. package/mjs/lib/common/engine/IRule.d.ts +100 -0
  179. package/mjs/lib/common/engine/IRule.js +79 -0
  180. package/mjs/lib/common/engine/IRule.js.map +1 -0
  181. package/mjs/lib/common/engine/IRuleset.d.ts +20 -0
  182. package/mjs/lib/common/engine/IRuleset.js +17 -0
  183. package/mjs/lib/common/engine/IRuleset.js.map +1 -0
  184. package/mjs/lib/common/report/ACReporterCSV.d.ts +28 -0
  185. package/mjs/lib/common/report/ACReporterCSV.js +60 -0
  186. package/mjs/lib/common/report/ACReporterCSV.js.map +1 -0
  187. package/mjs/lib/common/report/ACReporterHTML.d.ts +27 -0
  188. package/mjs/lib/common/report/ACReporterHTML.js +46 -0
  189. package/mjs/lib/common/report/ACReporterHTML.js.map +1 -0
  190. package/mjs/lib/common/report/ACReporterJSON.d.ts +36 -0
  191. package/mjs/lib/common/report/ACReporterJSON.js +94 -0
  192. package/mjs/lib/common/report/ACReporterJSON.js.map +1 -0
  193. package/mjs/lib/common/report/ACReporterMetrics.d.ts +78 -0
  194. package/mjs/lib/common/report/ACReporterMetrics.js +122 -0
  195. package/mjs/lib/common/report/ACReporterMetrics.js.map +1 -0
  196. package/mjs/lib/common/report/ACReporterXLSX.d.ts +38 -0
  197. package/mjs/lib/common/report/ACReporterXLSX.js +948 -0
  198. package/mjs/lib/common/report/ACReporterXLSX.js.map +1 -0
  199. package/mjs/lib/common/report/BaselineManager.d.ts +169 -0
  200. package/mjs/lib/common/report/BaselineManager.js +348 -0
  201. package/mjs/lib/common/report/BaselineManager.js.map +1 -0
  202. package/mjs/lib/common/report/ReporterManager.d.ts +79 -0
  203. package/mjs/lib/common/report/ReporterManager.js +469 -0
  204. package/mjs/lib/common/report/ReporterManager.js.map +1 -0
  205. package/mjs/lib/common/report/genReport.d.ts +1 -0
  206. package/mjs/lib/common/report/genReport.js +9 -0
  207. package/mjs/lib/common/report/genReport.js.map +1 -0
  208. package/mjs/package.json +3 -0
  209. package/package.json +10 -4
@@ -0,0 +1,948 @@
1
+ /******************************************************************************
2
+ Copyright:: 2020- IBM, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ *****************************************************************************/
16
+ import { eRuleLevel } from "../config/IConfig.js";
17
+ import { eToolkitLevel } from "../engine/IGuideline.js";
18
+ import { eRuleConfidence } from "../engine/IRule.js";
19
+ import { ReporterManager } from "./ReporterManager.js";
20
+ import * as ExcelJS from "exceljs";
21
+ function dropDupes(arr) {
22
+ let dupes = {};
23
+ return arr.filter(item => {
24
+ if (item.toString() in dupes) {
25
+ return false;
26
+ }
27
+ {
28
+ return dupes[item.toString()] = true;
29
+ }
30
+ });
31
+ }
32
+ export class ACReporterXLSX {
33
+ name() {
34
+ return "xlsx";
35
+ }
36
+ generateReport(_reportData) {
37
+ }
38
+ async generateSummary(config, rulesets, endReport, summaryData) {
39
+ let storedReport = ReporterManager.uncompressReport(summaryData[0]);
40
+ let cfgRulesets = rulesets.filter(rs => config.policies.includes(rs.id));
41
+ let policyInfo = {};
42
+ for (const rs of cfgRulesets) {
43
+ for (const cp of rs.checkpoints) {
44
+ for (const rule of cp.rules) {
45
+ policyInfo[rule.id] = policyInfo[rule.id] || {
46
+ tkLevels: [],
47
+ cps: []
48
+ };
49
+ policyInfo[rule.id].tkLevels.push(rule.toolkitLevel);
50
+ policyInfo[rule.id].cps.push(cp);
51
+ }
52
+ }
53
+ }
54
+ for (const ruleId in policyInfo) {
55
+ policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels);
56
+ policyInfo[ruleId].tkLevels.sort();
57
+ }
58
+ // const buffer: any = await workbook.xlsx.writeBuffer();
59
+ let startScan = new Date(storedReport.engineReport.summary.startScan);
60
+ let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`;
61
+ if (config.outputFilenameTimestamp === false) {
62
+ reportFilename = `results.xlsx`;
63
+ }
64
+ return {
65
+ summaryPath: reportFilename,
66
+ summary: async (filename) => {
67
+ // @ts-ignore
68
+ const workbook = new ExcelJS.stream.xlsx.WorkbookWriter({ filename, useStyles: true });
69
+ // const workbook = new ExcelJS.Workbook({ useStyles: true });
70
+ ACReporterXLSX.createOverviewSheet(config, summaryData, workbook);
71
+ ACReporterXLSX.createScanSummarySheet(config, summaryData, workbook);
72
+ ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData, workbook);
73
+ ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData, workbook);
74
+ ACReporterXLSX.createDefinitionsSheet(workbook);
75
+ workbook.commit();
76
+ }
77
+ };
78
+ }
79
+ static createOverviewSheet(config, compressedScans, workbook) {
80
+ let violations = 0;
81
+ let needsReviews = 0;
82
+ let recommendations = 0;
83
+ let archived = 0;
84
+ let totalIssues = 0;
85
+ let startScan = 0;
86
+ // BIG QUESTION: is report
87
+ // 1. for current scan (from menu)
88
+ // 2. all stored scans (from menu)
89
+ // 3. selected stored scans (from scan manager)
90
+ for (const compressedScan of compressedScans) {
91
+ let storedScan = ReporterManager.uncompressReport(compressedScan);
92
+ if (startScan === 0)
93
+ startScan = storedScan.engineReport.summary.startScan;
94
+ const counts = storedScan.engineReport.summary.counts;
95
+ violations += counts.violation;
96
+ needsReviews += counts.potentialviolation + counts.manual;
97
+ recommendations += counts.recommendation + counts.potentialrecommendation;
98
+ archived += counts.ignored;
99
+ }
100
+ totalIssues = violations + needsReviews + recommendations + archived;
101
+ const worksheet = workbook.addWorksheet("Overview");
102
+ // Report Title
103
+ worksheet.mergeCells('A1', "E1");
104
+ const titleRow = worksheet.getRow(1);
105
+ titleRow.height = 27;
106
+ const cellA1 = worksheet.getCell('A1');
107
+ cellA1.value = "Accessibility Scan Report";
108
+ cellA1.alignment = { vertical: "middle", horizontal: "left" };
109
+ cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
110
+ cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
111
+ // what are column widths - can't get it till you set it
112
+ const colWidthData = [
113
+ { col: 'A', width: 15.1 },
114
+ { col: 'B', width: 15.9 },
115
+ { col: 'C', width: 16.23 },
116
+ { col: 'D', width: 19.4 },
117
+ ];
118
+ for (let i = 0; i < 4; i++) {
119
+ worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
120
+ }
121
+ // note except for Report Date this is the same for all scans
122
+ const rowData = [
123
+ { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' },
124
+ // {key1: 'Version:', key2: "chrome.runtime.getManifest().version"},
125
+ { key1: 'Version:', key2: config.toolID },
126
+ //@ts-ignore
127
+ // {key1: 'Rule set:', key2: (theCurrentScan.ruleSet === "Latest Deployment") ? archives[1].name : theCurrentScan.ruleSet },
128
+ { key1: 'Rule set:', key2: config.ruleArchiveLabel },
129
+ { key1: 'Guidelines:', key2: config.policies.join(", ") },
130
+ { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, // do we need to get actual date?
131
+ { key1: 'Scans:', key2: "" + compressedScans.length }, // *** NEED TO FIX FOR selected
132
+ // { key1: 'Pages:', key2: "" }
133
+ ];
134
+ for (let idx = 0; idx < rowData.length; ++idx) {
135
+ worksheet.mergeCells(`B${idx + 2}`, `E${idx + 2}`);
136
+ let i = idx + 2;
137
+ worksheet.getRow(i).height = 12; // results in a row height of 16
138
+ worksheet.getRow(i).getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
139
+ worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
140
+ worksheet.getRow(i).getCell(1).alignment = { horizontal: "left" };
141
+ worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" };
142
+ // if (i == 7) {
143
+ // worksheet.getRow(i).getCell(1).alignment = { vertical: "top" };
144
+ // worksheet.getRow(i).getCell(2).alignment = { wrapText: true };
145
+ // }
146
+ worksheet.getRow(i).getCell(1).value = rowData[i - 2].key1;
147
+ worksheet.getRow(i).getCell(2).value = rowData[i - 2].key2;
148
+ }
149
+ // Summary Title
150
+ worksheet.mergeCells('A11', "E11");
151
+ const summaryRow = worksheet.getRow(11);
152
+ summaryRow.height = 27;
153
+ const cellA11 = worksheet.getCell('A11');
154
+ cellA11.value = "Summary";
155
+ cellA11.alignment = { vertical: "middle", horizontal: "left" };
156
+ cellA11.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
157
+ cellA11.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
158
+ // Scans info Headers
159
+ worksheet.getRow(12).height = 16; // actual height is
160
+ const cellA12 = worksheet.getCell('A12');
161
+ cellA12.value = "Total issues";
162
+ const cellB12 = worksheet.getCell('B12');
163
+ cellB12.value = "Violations";
164
+ const cellC12 = worksheet.getCell('C12');
165
+ cellC12.value = "Needs review";
166
+ const cellD12 = worksheet.getCell('D12');
167
+ cellD12.value = "Recommendations";
168
+ const cellE12 = worksheet.getCell('E12');
169
+ cellE12.value = "Archived";
170
+ const cellObjects1 = [cellA12, cellB12, cellC12, cellD12, cellE12];
171
+ for (let i = 0; i < cellObjects1.length; i++) {
172
+ cellObjects1[i].alignment = { vertical: "middle", horizontal: "center" };
173
+ if (i == 1 || i == 2 || i == 3 || i === 4) {
174
+ cellObjects1[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
175
+ }
176
+ else {
177
+ cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
178
+ }
179
+ // cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} };
180
+ cellObjects1[i].border = {
181
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
182
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
183
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
184
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
185
+ };
186
+ }
187
+ cellA12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
188
+ cellB12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } };
189
+ cellC12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } };
190
+ cellD12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } };
191
+ // Scans info Values
192
+ worksheet.getRow(13).height = 27; // actual height is
193
+ const cellA13 = worksheet.getCell('A13');
194
+ cellA13.value = totalIssues;
195
+ const cellB13 = worksheet.getCell('B13');
196
+ cellB13.value = violations;
197
+ const cellC13 = worksheet.getCell('C13');
198
+ cellC13.value = needsReviews;
199
+ const cellD13 = worksheet.getCell('D13');
200
+ cellD13.value = recommendations;
201
+ const cellE13 = worksheet.getCell('E13');
202
+ cellE13.value = archived;
203
+ const cellObjects2 = [cellA13, cellB13, cellC13, cellD13, cellE13];
204
+ for (let i = 0; i < cellObjects2.length; i++) {
205
+ cellObjects2[i].alignment = { vertical: "middle", horizontal: "center" };
206
+ cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
207
+ // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
208
+ cellObjects2[i].border = {
209
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
210
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
211
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
212
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
213
+ };
214
+ }
215
+ }
216
+ static createScanSummarySheet(config, compressedScans, workbook) {
217
+ const worksheet = workbook.addWorksheet("Scan summary");
218
+ // Scans info Headers
219
+ worksheet.getRow(1).height = 39; // actual height is 52
220
+ const colWidthData = [
221
+ { col: 'A', width: 27.0 },
222
+ { col: 'B', width: 46.0 },
223
+ { col: 'C', width: 20.17 },
224
+ { col: 'D', width: 18.5 },
225
+ { col: 'E', width: 17.17 },
226
+ { col: 'F', width: 17.17 },
227
+ { col: 'G', width: 17.17 },
228
+ { col: 'H', width: 17.17 },
229
+ { col: 'I', width: 17.17 },
230
+ ];
231
+ for (let i = 0; i < 9; i++) {
232
+ worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
233
+ }
234
+ const cellA1 = worksheet.getCell('A1');
235
+ cellA1.value = "Page title";
236
+ const cellB1 = worksheet.getCell('B1');
237
+ cellB1.value = "Page url";
238
+ const cellC1 = worksheet.getCell('C1');
239
+ cellC1.value = "Scan label";
240
+ const cellObjects1 = [cellA1, cellB1, cellC1];
241
+ for (let i = 0; i < cellObjects1.length; i++) {
242
+ cellObjects1[i].alignment = { vertical: "middle", horizontal: "left" };
243
+ cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
244
+ cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
245
+ cellObjects1[i].border = {
246
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
247
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
248
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
249
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
250
+ };
251
+ }
252
+ const cellD1 = worksheet.getCell('D1');
253
+ cellD1.value = "Violations";
254
+ const cellE1 = worksheet.getCell('E1');
255
+ cellE1.value = "Needs review";
256
+ const cellF1 = worksheet.getCell('F1');
257
+ cellF1.value = "Recommendations";
258
+ const cellG1 = worksheet.getCell('G1');
259
+ cellG1.value = "Archived";
260
+ const cellH1 = worksheet.getCell('H1');
261
+ cellH1.value = "% elements without violations";
262
+ const cellI1 = worksheet.getCell('I1');
263
+ cellI1.value = "% elements without violations or items to review";
264
+ const cellObjects2 = [cellD1, cellE1, cellF1, cellG1, cellH1, cellI1];
265
+ for (let i = 0; i < cellObjects2.length; i++) {
266
+ cellObjects2[i].alignment = { vertical: "middle", horizontal: "center", wrapText: true };
267
+ if (i == 0 || i == 1 || i == 2 || i == 3) {
268
+ cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
269
+ }
270
+ else {
271
+ cellObjects2[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
272
+ }
273
+ // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} };
274
+ cellObjects2[i].border = {
275
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
276
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
277
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
278
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
279
+ };
280
+ }
281
+ cellD1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } };
282
+ cellE1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } };
283
+ cellF1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } };
284
+ cellG1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFFFF' } };
285
+ cellH1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
286
+ cellI1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
287
+ for (const compressedScan of compressedScans) {
288
+ let storedScan = ReporterManager.uncompressReport(compressedScan);
289
+ let counts = storedScan.engineReport.summary.counts;
290
+ let row = worksheet.addRow([
291
+ storedScan.pageTitle,
292
+ storedScan.engineReport.summary.URL,
293
+ storedScan.label,
294
+ counts.violation,
295
+ counts.potentialviolation + counts.manual,
296
+ counts.recommendation + counts.potentialrecommendation,
297
+ counts.ignored,
298
+ (100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0),
299
+ (100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0),
300
+ ]);
301
+ row.height = 37; // actual height is
302
+ for (let i = 1; i < 4; i++) {
303
+ row.getCell(i).alignment = { vertical: "middle", horizontal: "left", wrapText: true };
304
+ row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 };
305
+ }
306
+ for (let i = 4; i < 10; i++) {
307
+ row.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true };
308
+ row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 };
309
+ // row.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
310
+ row.getCell(i).border = {
311
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
312
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
313
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
314
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
315
+ };
316
+ }
317
+ row.commit();
318
+ }
319
+ worksheet.commit();
320
+ }
321
+ static buildIssueSummaryLevel(worksheet, fillColor, title, levelCount, levelrowValues) {
322
+ // Level 1 Violation title
323
+ const level1ViolationRow = worksheet.addRow(["", 0]);
324
+ level1ViolationRow.height = 18; // target is 21
325
+ const cellA6 = level1ViolationRow.getCell(1);
326
+ cellA6.value = ` ${title}`;
327
+ cellA6.alignment = { vertical: "middle", horizontal: "left" };
328
+ cellA6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
329
+ cellA6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } };
330
+ level1ViolationRow.getCell(1).border = {
331
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
332
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
333
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
334
+ // right: {style:'thin', color: {argb: 'FFA6A6A6'}}
335
+ };
336
+ const cellB6 = level1ViolationRow.getCell(2);
337
+ cellB6.value = levelCount; // total level violations
338
+ cellB6.alignment = { vertical: "middle", horizontal: "right" };
339
+ cellB6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
340
+ cellB6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } };
341
+ level1ViolationRow.getCell(2).border = {
342
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
343
+ // left: {style:'thin', color: {argb: 'FFA6A6A6'}},
344
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
345
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
346
+ };
347
+ // Level 1 Violation Rows
348
+ // build rows
349
+ let rowArray = [];
350
+ // let row:any =[];
351
+ for (const property in levelrowValues) {
352
+ let row = [" " + `${property}`, parseInt(`${levelrowValues[property]}`)
353
+ ];
354
+ rowArray.push(row);
355
+ }
356
+ // sort array according to count
357
+ rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1);
358
+ // add array of rows
359
+ for (const rowInfo of rowArray) {
360
+ const row = worksheet.addRow(rowInfo);
361
+ row.height = 14;
362
+ row.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
363
+ row.getCell(2).alignment = { vertical: "middle", horizontal: "right" };
364
+ row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
365
+ // row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
366
+ // row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
367
+ row.getCell(1).border = {
368
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
369
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
370
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
371
+ // right: {style:'thin', color: {argb: 'FFA6A6A6'}}
372
+ };
373
+ row.getCell(2).border = {
374
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
375
+ // left: {style:'thin', color: {argb: 'FFA6A6A6'}},
376
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
377
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
378
+ };
379
+ row.commit();
380
+ }
381
+ }
382
+ static buildIssueSummaryTKLevel(worksheet, title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) {
383
+ /////////////////////////////
384
+ // build Level title
385
+ /////////////////////////////
386
+ const level1Row = worksheet.addRow(["", 0]);
387
+ level1Row.height = 27; // actual is 36
388
+ const cellA5 = level1Row.getCell(1);
389
+ cellA5.value = title;
390
+ cellA5.alignment = { vertical: "middle", horizontal: "left" };
391
+ cellA5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
392
+ cellA5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
393
+ const cellB5 = level1Row.getCell(2);
394
+ cellB5.value = levelCounts[0]; // total Level 1 issues
395
+ cellB5.alignment = { vertical: "middle", horizontal: "right" };
396
+ cellB5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
397
+ cellB5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
398
+ ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFE4AAAF", "Violation", levelCounts[1], levelVrowValues);
399
+ ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFF4E08A", "Needs review", levelCounts[2], levelNRrowValues);
400
+ ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FF96A9D7", "Recommendation", levelCounts[3], levelRrowValues);
401
+ if (levelCounts[4] > 0) {
402
+ ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFCCCCCC", "Archived", levelCounts[4], levelArowValues);
403
+ }
404
+ }
405
+ static createIssueSummarySheet(config, policyInfo, compressedScans, workbook) {
406
+ let violations = 0;
407
+ let needsReviews = 0;
408
+ let recommendations = 0;
409
+ let archive = 0;
410
+ let totalIssues = 0;
411
+ for (let i = 0; i < compressedScans.length; i++) {
412
+ let storedScan = ReporterManager.uncompressReport(compressedScans[i]);
413
+ let counts = storedScan.engineReport.summary.counts;
414
+ violations += counts.violation;
415
+ needsReviews += counts.potentialviolation + counts.manual;
416
+ recommendations += counts.recommendation + counts.potentialrecommendation;
417
+ archive += counts.ignored;
418
+ }
419
+ totalIssues = violations + needsReviews + recommendations;
420
+ // counts
421
+ let level1Counts = [0, 0, 0, 0, 0]; // level 1 total issues, violations, needs reviews, recommendations
422
+ let level2Counts = [0, 0, 0, 0, 0];
423
+ let level3Counts = [0, 0, 0, 0, 0];
424
+ let level4Counts = [0, 0, 0, 0, 0];
425
+ let level1V = [];
426
+ let level2V = [];
427
+ let level3V = [];
428
+ let level4V = [];
429
+ let level1NR = [];
430
+ let level2NR = [];
431
+ let level3NR = [];
432
+ let level4NR = [];
433
+ let level1R = [];
434
+ let level2R = [];
435
+ let level3R = [];
436
+ let level4R = [];
437
+ let level1A = [];
438
+ let level2A = [];
439
+ let level3A = [];
440
+ let level4A = [];
441
+ for (const compressedScan of compressedScans) {
442
+ let scan = ReporterManager.uncompressReport(compressedScan);
443
+ for (const issue of scan.engineReport.results) {
444
+ if (!(issue.ruleId in policyInfo)) {
445
+ policyInfo[issue.ruleId] = {
446
+ tkLevels: [],
447
+ cps: []
448
+ };
449
+ }
450
+ let levelCounts, levelV, levelNR, levelR, levelA;
451
+ const issuePolicyInfo = policyInfo[issue.ruleId];
452
+ if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_ONE)) {
453
+ levelCounts = level1Counts;
454
+ levelV = level1V;
455
+ levelNR = level1NR;
456
+ levelR = level1R;
457
+ levelA = level1A;
458
+ }
459
+ else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_TWO)) {
460
+ levelCounts = level2Counts;
461
+ levelV = level2V;
462
+ levelNR = level2NR;
463
+ levelR = level2R;
464
+ levelA = level2A;
465
+ }
466
+ else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_THREE)) {
467
+ levelCounts = level3Counts;
468
+ levelV = level3V;
469
+ levelNR = level3NR;
470
+ levelR = level3R;
471
+ levelA = level3A;
472
+ }
473
+ else if (issuePolicyInfo.tkLevels.includes(eToolkitLevel.LEVEL_FOUR)) {
474
+ levelCounts = level4Counts;
475
+ levelV = level4V;
476
+ levelNR = level4NR;
477
+ levelR = level4R;
478
+ levelA = level4A;
479
+ }
480
+ if (issue.value[1] !== eRuleConfidence.PASS) {
481
+ ++levelCounts[0];
482
+ }
483
+ if (issue.ignored) {
484
+ ++levelCounts[4];
485
+ levelA.push(issue.message.substring(0, 32767));
486
+ }
487
+ else if (issue.level === eRuleLevel.violation) {
488
+ ++levelCounts[1];
489
+ levelV.push(issue.message.substring(0, 32767));
490
+ }
491
+ else if (issue.level === eRuleLevel.potentialviolation || issue.level === eRuleLevel.manual) {
492
+ ++levelCounts[2];
493
+ levelNR.push(issue.message.substring(0, 32767));
494
+ }
495
+ else if (issue.level === eRuleLevel.recommendation || issue.level === eRuleLevel.potentialrecommendation) {
496
+ ++levelCounts[3];
497
+ levelR.push(issue.message.substring(0, 32767));
498
+ }
499
+ }
500
+ }
501
+ // @ts-ignore
502
+ let level1VrowValues = this.countDuplicatesInArray(level1V); // note this returns an object
503
+ // @ts-ignore
504
+ let level1NRrowValues = this.countDuplicatesInArray(level1NR);
505
+ // @ts-ignore
506
+ let level1RrowValues = this.countDuplicatesInArray(level1R);
507
+ // @ts-ignore
508
+ let level1ArowValues = this.countDuplicatesInArray(level1A);
509
+ // @ts-ignore
510
+ let level2VrowValues = this.countDuplicatesInArray(level2V); // note this returns an object
511
+ // @ts-ignore
512
+ let level2NRrowValues = this.countDuplicatesInArray(level2NR);
513
+ // @ts-ignore
514
+ let level2RrowValues = this.countDuplicatesInArray(level2R);
515
+ // @ts-ignore
516
+ let level2ArowValues = this.countDuplicatesInArray(level2A);
517
+ // @ts-ignore
518
+ let level3VrowValues = this.countDuplicatesInArray(level3V); // note this returns an object
519
+ // @ts-ignore
520
+ let level3NRrowValues = this.countDuplicatesInArray(level3NR);
521
+ // @ts-ignore
522
+ let level3RrowValues = this.countDuplicatesInArray(level3R);
523
+ // @ts-ignore
524
+ let level3ArowValues = this.countDuplicatesInArray(level3A);
525
+ // @ts-ignore
526
+ let level4VrowValues = this.countDuplicatesInArray(level4V); // note this returns an object
527
+ // @ts-ignore
528
+ let level4NRrowValues = this.countDuplicatesInArray(level4NR);
529
+ // @ts-ignore
530
+ let level4RrowValues = this.countDuplicatesInArray(level4R);
531
+ // @ts-ignore
532
+ let level4ArowValues = this.countDuplicatesInArray(level4A);
533
+ const worksheet = workbook.addWorksheet("Issue summary");
534
+ // Approach:
535
+ // 1. sort by levels
536
+ // 2. for each level sort by V, NR and R
537
+ // 3. for each V, NR, and R in a level get issue dup counts
538
+ // 4. build the rows
539
+ // build Issue summary title
540
+ worksheet.mergeCells('A1', "B1");
541
+ const titleRow = worksheet.getRow(1);
542
+ titleRow.height = 27; // actual is 36
543
+ const cellA1 = worksheet.getCell('A1');
544
+ cellA1.value = "Issue summary";
545
+ cellA1.alignment = { vertical: "middle", horizontal: "left" };
546
+ cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
547
+ cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
548
+ const colWidthData = [
549
+ { col: 'A', width: 155.51 }, // note .84 added to actual width
550
+ { col: 'B', width: 21.16 },
551
+ ];
552
+ for (let i = 0; i < 2; i++) {
553
+ worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
554
+ }
555
+ // build Description title
556
+ worksheet.mergeCells('A2', "B2");
557
+ const descriptionRow = worksheet.getRow(2);
558
+ descriptionRow.height = 20.25; // actual is 27
559
+ const cellA2 = worksheet.getCell("A2");
560
+ cellA2.value = " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.";
561
+ cellA2.alignment = { vertical: "middle", horizontal: "left" };
562
+ cellA2.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
563
+ // cellA2.fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFCCC0DA'} };
564
+ // build Total issues found: title
565
+ // worksheet.mergeCells('A3', "B3");
566
+ const totalIssuesRow = worksheet.getRow(3);
567
+ totalIssuesRow.height = 27; // actual is 36
568
+ const cellA3 = worksheet.getCell("A3");
569
+ cellA3.value = "Total issues found:";
570
+ cellA3.alignment = { vertical: "middle", horizontal: "left" };
571
+ cellA3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
572
+ cellA3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
573
+ const cellB3 = worksheet.getCell("B3");
574
+ cellB3.value = totalIssues;
575
+ cellB3.alignment = { vertical: "middle", horizontal: "right" };
576
+ cellB3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
577
+ cellB3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
578
+ // build Number of issues title
579
+ const numberOfIssuesRow = worksheet.getRow(4);
580
+ numberOfIssuesRow.height = 20.25; // actual is 27
581
+ const cellA4 = worksheet.getCell("A4");
582
+ // no value
583
+ cellA4.alignment = { vertical: "middle", horizontal: "left" };
584
+ cellA4.border = {
585
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
586
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
587
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
588
+ right: { style: 'thin', color: { argb: 'FFFFFFFF' } }
589
+ };
590
+ const cellB4 = worksheet.getCell("B4");
591
+ cellB4.value = "Number of issues";
592
+ cellB4.alignment = { vertical: "middle", horizontal: "right" };
593
+ cellB4.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
594
+ cellB4.border = {
595
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
596
+ left: { style: 'thin', color: { argb: 'FFFFFFFF' } },
597
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
598
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
599
+ };
600
+ ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues);
601
+ ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues);
602
+ ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues);
603
+ ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues);
604
+ worksheet.commit();
605
+ }
606
+ static createIssuesSheet(config, policyInfo, compressedScans, workbook) {
607
+ const valueMap = {
608
+ "VIOLATION": {
609
+ "POTENTIAL": "Needs review",
610
+ "FAIL": "Violation",
611
+ "PASS": "Pass",
612
+ "MANUAL": "Needs review"
613
+ },
614
+ "RECOMMENDATION": {
615
+ "POTENTIAL": "Recommendation",
616
+ "FAIL": "Recommendation",
617
+ "PASS": "Pass",
618
+ "MANUAL": "Recommendation"
619
+ },
620
+ "INFORMATION": {
621
+ "POTENTIAL": "Needs review",
622
+ "FAIL": "Violation",
623
+ "PASS": "Pass",
624
+ "MANUAL": "Recommendation"
625
+ }
626
+ };
627
+ const worksheet = workbook.addWorksheet("Issues");
628
+ // build rows
629
+ let rowArray = [];
630
+ for (const compressedScan of compressedScans) {
631
+ let storedScan = ReporterManager.uncompressReport(compressedScan);
632
+ for (const item of storedScan.engineReport.results) {
633
+ if (!(item.ruleId in policyInfo)) {
634
+ policyInfo[item.ruleId] = {
635
+ tkLevels: [],
636
+ cps: []
637
+ };
638
+ }
639
+ let polInfo = policyInfo[item.ruleId];
640
+ let cps = polInfo.cps.filter(cp => {
641
+ let ruleInfo = cp.rules.find(ruleInfo => ruleInfo.id === item.ruleId && (!ruleInfo.reasonCodes || ruleInfo.reasonCodes.includes("" + item.reasonId)));
642
+ return !!ruleInfo;
643
+ });
644
+ let wcagLevels = dropDupes(cps.map(cp => cp.wcagLevel));
645
+ wcagLevels.sort();
646
+ let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`));
647
+ cpStrs.sort();
648
+ let row = [
649
+ storedScan.pageTitle,
650
+ storedScan.engineReport.summary.URL,
651
+ storedScan.label,
652
+ this.stringHash(item.ruleId + item.path.dom),
653
+ `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}`,
654
+ polInfo.tkLevels.join(", "),
655
+ cpStrs.join("; "),
656
+ wcagLevels.join(", "),
657
+ item.ruleId,
658
+ item.message.substring(0, 32767), //max ength for MS Excel 32767 characters
659
+ this.get_element(item.snippet),
660
+ item.snippet.substring(0, 32767),
661
+ item.path.dom,
662
+ item.help
663
+ // engine_end_point + '/tools/help/' + item.ruleId
664
+ ];
665
+ // let row = [myStoredData[i][0], myStoredData[i][1], storedScans[j].label,
666
+ // myStoredData[i][3], myStoredData[i][4], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][5],
667
+ // myStoredData[i][6], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][7], myStoredData[i][8],
668
+ // myStoredData[i][9], myStoredData[i][10], myStoredData[i][11],
669
+ // myStoredData[i][12], myStoredData[i][13]
670
+ // ];
671
+ rowArray.push(row);
672
+ }
673
+ }
674
+ // column widths
675
+ const colWidthData = [
676
+ { col: 'A', width: 18.0, alignment: { vertical: "middle", horizontal: "left" } },
677
+ { col: 'B', width: 20.5, alignment: { vertical: "middle", horizontal: "left" } },
678
+ { col: 'C', width: 21.0, alignment: { vertical: "middle", horizontal: "center" } },
679
+ { col: 'D', width: 18.5, alignment: { vertical: "middle", horizontal: "left" } },
680
+ { col: 'E', width: 17.0, alignment: { vertical: "middle", horizontal: "center" } },
681
+ { col: 'F', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } },
682
+ { col: 'G', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
683
+ { col: 'H', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } },
684
+ { col: 'I', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
685
+ { col: 'J', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
686
+ { col: 'K', width: 14.00, alignment: { vertical: "middle", horizontal: "center" } },
687
+ { col: 'L', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
688
+ { col: 'M', width: 43.00, alignment: { vertical: "middle", horizontal: "left" } },
689
+ { col: 'N', width: 17.17, alignment: { vertical: "middle", horizontal: "fill" } },
690
+ ];
691
+ for (let i = 0; i < 14; i++) {
692
+ worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
693
+ worksheet.getColumn(colWidthData[i].col).alignment = colWidthData[i].alignment;
694
+ }
695
+ // add table to a sheet
696
+ let headRow = worksheet.addRow([
697
+ "Page title",
698
+ "Page URL",
699
+ "Scan label",
700
+ "Issue ID",
701
+ "Issue type",
702
+ "Toolkit level",
703
+ "Checkpoint",
704
+ "WCAG level",
705
+ "Rule",
706
+ "Issue",
707
+ "Element",
708
+ "Code",
709
+ "Xpath",
710
+ "Help",
711
+ ""
712
+ ]);
713
+ // set font and alignment for the header cells
714
+ for (let i = 1; i < 15; i++) {
715
+ headRow.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true };
716
+ headRow.getCell(i).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
717
+ headRow.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
718
+ headRow.getCell(i).border = {
719
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
720
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
721
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
722
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
723
+ };
724
+ }
725
+ // height for header row
726
+ headRow.height = 24;
727
+ headRow.commit();
728
+ for (const rowInfo of rowArray) {
729
+ const row = worksheet.addRow(rowInfo);
730
+ row.height = 14;
731
+ for (let j = 1; j <= 14; j++) {
732
+ row.getCell(j).border = {
733
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
734
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
735
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
736
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
737
+ };
738
+ }
739
+ row.commit();
740
+ }
741
+ for (const key in worksheet) {
742
+ if (typeof worksheet[key] === "function") {
743
+ console.log(key);
744
+ }
745
+ }
746
+ // worksheet.addTable({
747
+ // name: 'MyTable',
748
+ // ref: 'A1',
749
+ // headerRow: true,
750
+ // // totalsRow: true,
751
+ // style: {
752
+ // theme: 'TableStyleMedium2',
753
+ // showRowStripes: true,
754
+ // },
755
+ // columns: [
756
+ // { name: 'Page title', filterButton: true },
757
+ // { name: 'Page URL', filterButton: true },
758
+ // { name: 'Scan label', filterButton: true },
759
+ // { name: 'Issue ID', filterButton: true },
760
+ // { name: 'Issue type', filterButton: true },
761
+ // { name: 'Toolkit level', filterButton: true },
762
+ // { name: 'Checkpoint', filterButton: true },
763
+ // { name: 'WCAG level', filterButton: true },
764
+ // { name: 'Rule', filterButton: true },
765
+ // { name: 'Issue', filterButton: true },
766
+ // { name: 'Element', filterButton: true },
767
+ // { name: 'Code', filterButton: true },
768
+ // { name: 'Xpath', filterButton: true },
769
+ // { name: 'Help', filterButton: true },
770
+ // ],
771
+ // rows: rowArray
772
+ // });
773
+ // for (let i = 2; i <= rowArray.length + 1; i++) {
774
+ // worksheet.getRow(i).height = 14;
775
+ // for (let j = 1; j <= 14; j++) {
776
+ // worksheet.getRow(i).getCell(j).border = {
777
+ // top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
778
+ // left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
779
+ // bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
780
+ // right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
781
+ // }
782
+ // }
783
+ // worksheet.getRow(i).commit();
784
+ // }
785
+ worksheet.commit();
786
+ }
787
+ static createDefinitionsSheet(workbook) {
788
+ const worksheet = workbook.addWorksheet("Definition of fields");
789
+ // "Definition of fields" title
790
+ worksheet.mergeCells('A1', "B1");
791
+ const titleRow = worksheet.getRow(1);
792
+ titleRow.height = 36; // actual is 48
793
+ titleRow.getCell(1).value = "Definition of fields";
794
+ titleRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
795
+ titleRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: "20" };
796
+ titleRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
797
+ const colWidthData = [
798
+ { col: 'A', width: '41.51' }, // note .84 added to actual width
799
+ { col: 'B', width: '119.51' },
800
+ ];
801
+ for (let i = 0; i < 2; i++) {
802
+ worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
803
+ }
804
+ // blank row
805
+ worksheet.mergeCells('A2', "B2");
806
+ const blankRow = worksheet.getRow(2);
807
+ blankRow.height = 12; // actual is 16
808
+ // "Scan summary and Issue summary" title
809
+ worksheet.mergeCells('A3', "B3");
810
+ const summaryRow = worksheet.getRow(3);
811
+ summaryRow.height = 20; // actual is 26.75
812
+ summaryRow.getCell(1).value = "Scan summary and Issue summary";
813
+ summaryRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
814
+ summaryRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
815
+ summaryRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
816
+ // row 4 Field / Definition
817
+ const row4 = worksheet.getRow(4);
818
+ row4.height = 16; // actual is
819
+ row4.getCell(1).value = "Field";
820
+ row4.getCell(2).value = "Definition";
821
+ row4.getCell(1).alignment = row4.getCell(2).alignment = { vertical: "middle", horizontal: "left" };
822
+ row4.getCell(1).font = row4.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 };
823
+ row4.getCell(1).fill = row4.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } };
824
+ row4.getCell(1).border = row4.getCell(2).border = {
825
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
826
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
827
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
828
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
829
+ };
830
+ // rows 5-13
831
+ // set row height for rows 5-13
832
+ for (let i = 5; i < 14; i++) {
833
+ worksheet.getRow(i).height = 12; // results in a row height of 16
834
+ }
835
+ let rowData = [
836
+ { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' },
837
+ { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' },
838
+ { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' },
839
+ { key1: 'Needs review', key2: 'Issues that may not be a violation. These need a manual review to identify whether there is an accessibility problem.' },
840
+ { key1: 'Recommendations', key2: 'Opportunities to apply best practices to further improve accessibility.' },
841
+ { key1: '% elements without violations', key2: 'Percentage of elements on the page that had no violations found.' },
842
+ { key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' },
843
+ { key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' }
844
+ ];
845
+ for (let i = 5; i < rowData.length + 5; i++) {
846
+ worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
847
+ worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" };
848
+ }
849
+ for (let i = 5; i < rowData.length + 5; i++) {
850
+ worksheet.getRow(i).getCell(1).value = rowData[i - 5].key1;
851
+ worksheet.getRow(i).getCell(2).value = rowData[i - 5].key2;
852
+ }
853
+ // "Scan summary and Issue summary" title
854
+ worksheet.mergeCells('A14', "B14");
855
+ const issuesRow = worksheet.getRow(14);
856
+ issuesRow.height = 20; // actual is 26.75
857
+ issuesRow.getCell(1).value = "Issues";
858
+ issuesRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
859
+ issuesRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
860
+ issuesRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
861
+ // row 15 Field / Definition
862
+ const row15 = worksheet.getRow(15);
863
+ row15.height = 16; // actual is
864
+ row15.getCell(1).value = "Field";
865
+ row15.getCell(2).value = "Definition";
866
+ row15.getCell(1).alignment = row15.getCell(2).alignment = { vertical: "middle", horizontal: "left" };
867
+ row15.getCell(1).font = row15.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 };
868
+ row15.getCell(1).fill = row15.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } };
869
+ row15.getCell(1).border = row15.getCell(2).border = {
870
+ top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
871
+ left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
872
+ bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
873
+ right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
874
+ };
875
+ // rows 16-28
876
+ // set row height for rows 16-28
877
+ for (let i = 16; i < 29; i++) {
878
+ worksheet.getRow(i).height = 12; // results in a row height of 16
879
+ }
880
+ rowData = [];
881
+ rowData = [
882
+ { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' },
883
+ { key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' },
884
+ { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' },
885
+ { key1: 'Issue type', key2: 'Violation, needs review, or recommendation' },
886
+ { key1: 'Toolkit level', key2: '1, 2 or 3. Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details' },
887
+ { key1: 'Checkpoint', key2: 'Web Content Accessibility Guidelines (WCAG) checkpoints this issue falls into.' },
888
+ { key1: 'WCAG level', key2: 'A, AA or AAA. WCAG level for this issue.' },
889
+ { key1: 'Rule', key2: 'Name of the accessibility test rule that detected this issue.' },
890
+ { key1: 'Issue', key2: 'Message describing the issue.' },
891
+ { key1: 'Element', key2: 'Type of HTML element where the issue is found.' },
892
+ { key1: 'Code', key2: 'Actual HTML element where the issue is found.' },
893
+ { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' },
894
+ { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' },
895
+ ];
896
+ for (let i = 16; i < 29; i++) {
897
+ worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
898
+ worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" };
899
+ }
900
+ for (let i = 16; i < 29; i++) {
901
+ worksheet.getRow(i).getCell(1).value = rowData[i - 16].key1;
902
+ worksheet.getRow(i).getCell(2).value = rowData[i - 16].key2;
903
+ }
904
+ worksheet.commit();
905
+ }
906
+ static countDuplicatesInArray(array) {
907
+ let count = {};
908
+ // let result = [];
909
+ array.forEach(item => {
910
+ if (count[item]) {
911
+ //@ts-ignore
912
+ count[item] += 1;
913
+ return;
914
+ }
915
+ //@ts-ignore
916
+ count[item] = 1;
917
+ });
918
+ return count;
919
+ }
920
+ static get_element(code) {
921
+ if (code) {
922
+ const ind_s = code.indexOf(' ');
923
+ const ind_br = code.indexOf('>');
924
+ return (ind_s > 0 && ind_s < ind_br) ? code.substring(1, ind_s) : code.substring(1, ind_br);
925
+ }
926
+ return '';
927
+ }
928
+ static format_date(timestamp) {
929
+ var date = new Date(timestamp);
930
+ return date.getFullYear() + '-' + ("00" + (date.getMonth() + 1)).slice(-2) + "-" +
931
+ ("00" + date.getDate()).slice(-2) + "-" +
932
+ ("00" + date.getHours()).slice(-2) + "-" +
933
+ ("00" + date.getMinutes()).slice(-2) + "-" +
934
+ ("00" + date.getSeconds()).slice(-2);
935
+ }
936
+ // From https://github.com/darkskyapp/string-hash/blob/master/index.js
937
+ static stringHash(str) {
938
+ var hash = 5381, i = str.length;
939
+ while (i) {
940
+ hash = (hash * 33) ^ str.charCodeAt(--i);
941
+ }
942
+ /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
943
+ * integers. Since we want the results to be always positive, convert the
944
+ * signed int to an unsigned by doing an unsigned bitshift. */
945
+ return hash >>> 0;
946
+ }
947
+ }
948
+ //# sourceMappingURL=ACReporterXLSX.js.map