accessibility-checker 4.0.30 → 4.0.32

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 (35) hide show
  1. package/README.md +29 -0
  2. package/cjs/lib/ACHelper.js +20 -7
  3. package/cjs/lib/ACHelper.js.map +1 -1
  4. package/cjs/lib/common/config/ACConfigManager.js +15 -1
  5. package/cjs/lib/common/config/ACConfigManager.js.map +1 -1
  6. package/cjs/lib/common/config/ACConstants.js +4 -4
  7. package/cjs/lib/common/config/ACConstants.js.map +1 -1
  8. package/cjs/lib/common/report/ACReporterXLSX.d.ts +2 -2
  9. package/cjs/lib/common/report/ACReporterXLSX.js +408 -649
  10. package/cjs/lib/common/report/ACReporterXLSX.js.map +1 -1
  11. package/cjs/lib/common/report/genReport.js +2 -2
  12. package/cjs/lib/common/report/genReport.js.map +1 -1
  13. package/lib/ACHelper.js +20 -7
  14. package/lib/ACHelper.js.map +1 -1
  15. package/lib/common/config/ACConfigManager.js +15 -1
  16. package/lib/common/config/ACConfigManager.js.map +1 -1
  17. package/lib/common/config/ACConstants.js +4 -4
  18. package/lib/common/config/ACConstants.js.map +1 -1
  19. package/lib/common/report/ACReporterXLSX.d.ts +2 -2
  20. package/lib/common/report/ACReporterXLSX.js +408 -649
  21. package/lib/common/report/ACReporterXLSX.js.map +1 -1
  22. package/lib/common/report/genReport.js +2 -2
  23. package/lib/common/report/genReport.js.map +1 -1
  24. package/mjs/lib/ACHelper.js +20 -7
  25. package/mjs/lib/ACHelper.js.map +1 -1
  26. package/mjs/lib/common/config/ACConfigManager.js +15 -1
  27. package/mjs/lib/common/config/ACConfigManager.js.map +1 -1
  28. package/mjs/lib/common/config/ACConstants.js +4 -4
  29. package/mjs/lib/common/config/ACConstants.js.map +1 -1
  30. package/mjs/lib/common/report/ACReporterXLSX.d.ts +2 -2
  31. package/mjs/lib/common/report/ACReporterXLSX.js +421 -650
  32. package/mjs/lib/common/report/ACReporterXLSX.js.map +1 -1
  33. package/mjs/lib/common/report/genReport.js +2 -2
  34. package/mjs/lib/common/report/genReport.js.map +1 -1
  35. package/package.json +4 -11
@@ -62,23 +62,22 @@ const IConfig_js_1 = require("../config/IConfig.js");
62
62
  const IGuideline_js_1 = require("../engine/IGuideline.js");
63
63
  const IRule_js_1 = require("../engine/IRule.js");
64
64
  const ReporterManager_js_1 = require("./ReporterManager.js");
65
- // Lazy load exceljs - will be null if not installed
66
- let exceljsLoadPromise = null;
67
- let exceljsWarningShown = false;
68
- function loadExcelJS() {
69
- if (!exceljsLoadPromise) {
70
- // Use dynamic import with a variable to avoid TypeScript checking the module at compile time
71
- const moduleName = "exceljs";
72
- exceljsLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => module)
73
- .catch(e => null);
65
+ // Lazy-load write-excel-file — will be null if not installed
66
+ let writeExcelLoadPromise = null;
67
+ let writeExcelWarningShown = false;
68
+ function loadWriteExcel() {
69
+ if (!writeExcelLoadPromise) {
70
+ const moduleName = "write-excel-file/node";
71
+ writeExcelLoadPromise = Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))).then(module => { var _a; return (_a = module.default) !== null && _a !== void 0 ? _a : module; })
72
+ .catch(() => null);
74
73
  }
75
- return exceljsLoadPromise;
74
+ return writeExcelLoadPromise;
76
75
  }
77
- function showExcelJSWarning() {
78
- if (!exceljsWarningShown) {
79
- exceljsWarningShown = true;
80
- console.warn("Warning: exceljs is not installed. XLSX report generation is disabled.");
81
- console.warn("To enable XLSX reports, install exceljs: npm install exceljs");
76
+ function showWriteExcelWarning() {
77
+ if (!writeExcelWarningShown) {
78
+ writeExcelWarningShown = true;
79
+ console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled.");
80
+ console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file");
82
81
  }
83
82
  }
84
83
  function dropDupes(arr) {
@@ -92,6 +91,109 @@ function dropDupes(arr) {
92
91
  }
93
92
  });
94
93
  }
94
+ // Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB)
95
+ function argbToHex(argb) {
96
+ if (!argb || argb.length < 6)
97
+ return "#000000";
98
+ // Strip leading alpha if 8 chars
99
+ const rgb = argb.length === 8 ? argb.slice(2) : argb;
100
+ return `#${rgb}`;
101
+ }
102
+ // Helper: cell with dark purple header style
103
+ function headerCell(value, columnSpan) {
104
+ const cell = {
105
+ value,
106
+ backgroundColor: "#403151",
107
+ textColor: "#FFFFFF",
108
+ fontFamily: "Calibri",
109
+ fontSize: 16,
110
+ alignVertical: "center",
111
+ align: "left",
112
+ height: 36,
113
+ };
114
+ if (columnSpan && columnSpan > 1)
115
+ cell.columnSpan = columnSpan;
116
+ return cell;
117
+ }
118
+ // Helper: standard data cell
119
+ function dataCell(value, opts) {
120
+ return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000" }, opts);
121
+ }
122
+ // Helper: bordered cell
123
+ function borderedCell(value, opts) {
124
+ return Object.assign({ value, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin" }, opts);
125
+ }
126
+ // ─── XLSX table injection ──────────────────────────────────────────────────────
127
+ // write-excel-file has no native Excel table API. We post-process the output
128
+ // file: unzip it with Node's built-in zlib, inject the table definition XML,
129
+ // wire the sheet to reference it, and re-zip.
130
+ //
131
+ // The Issues sheet is always sheet index 3 (0-based) → sheetId "4".
132
+ // TableStyleMedium2 + showRowStripes matches the original ExcelJS output.
133
+ const ISSUES_SHEET_ID = "4";
134
+ const ISSUES_TABLE_ID = "1";
135
+ const ISSUES_COL_COUNT = 14;
136
+ const ISSUES_COL_NAMES = [
137
+ "Page title", "Page URL", "Scan label", "Issue ID", "Issue type",
138
+ "Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue",
139
+ "Element", "Code", "Xpath", "Help",
140
+ ];
141
+ function buildTableXml(rowCount) {
142
+ const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1];
143
+ const ref = `A1:${lastCol}${rowCount}`;
144
+ const cols = ISSUES_COL_NAMES.map((name, i) => `<tableColumn id="${i + 1}" name="${name}"/>`).join("");
145
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
146
+ `<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"` +
147
+ ` id="${ISSUES_TABLE_ID}" name="IssuesTable" displayName="IssuesTable" ref="${ref}" headerRowCount="1">` +
148
+ `<autoFilter ref="${ref}"/>` +
149
+ `<tableColumns count="${ISSUES_COL_COUNT}">${cols}</tableColumns>` +
150
+ `<tableStyleInfo name="TableStyleMedium2" showFirstColumn="0"` +
151
+ ` showLastColumn="0" showRowStripes="1" showColumnStripes="0"/>` +
152
+ `</table>`;
153
+ }
154
+ function injectTableIntoFile(filePath, issueRowCount) {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ let AdmZip;
157
+ try {
158
+ // webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module.
159
+ // The try/catch ensures graceful degradation if adm-zip is not installed.
160
+ AdmZip = require(/* webpackIgnore: true */ "adm-zip");
161
+ }
162
+ catch (_a) {
163
+ // adm-zip not available — skip table injection gracefully
164
+ return;
165
+ }
166
+ const zip = new AdmZip(filePath);
167
+ // 1. Add xl/tables/table1.xml
168
+ const tableXml = buildTableXml(issueRowCount);
169
+ zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8"));
170
+ // 2. Patch xl/worksheets/_rels/sheet4.xml.rels
171
+ const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`;
172
+ const relsEntry = zip.getEntry(relsPath);
173
+ const tableRel = `<Relationship Id="rIdTbl"` +
174
+ ` Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"` +
175
+ ` Target="../tables/table${ISSUES_TABLE_ID}.xml"/>`;
176
+ if (relsEntry) {
177
+ const existing = relsEntry.getData().toString("utf8");
178
+ zip.updateFile(relsPath, Buffer.from(existing.replace("</Relationships>", tableRel + "</Relationships>"), "utf8"));
179
+ }
180
+ else {
181
+ zip.addFile(relsPath, Buffer.from(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
182
+ `<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">` +
183
+ tableRel + `</Relationships>`, "utf8"));
184
+ }
185
+ // 3. Patch xl/worksheets/sheet4.xml — add <tableParts> before </worksheet>
186
+ const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`;
187
+ const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8");
188
+ zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("</worksheet>", `<tableParts count="1"><tablePart r:id="rIdTbl"/></tableParts></worksheet>`), "utf8"));
189
+ // 4. Patch [Content_Types].xml
190
+ const ctPath = "[Content_Types].xml";
191
+ const ctXml = zip.getEntry(ctPath).getData().toString("utf8");
192
+ zip.updateFile(ctPath, Buffer.from(ctXml.replace("</Types>", `<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"` +
193
+ ` PartName="/xl/tables/table${ISSUES_TABLE_ID}.xml"/></Types>`), "utf8"));
194
+ zip.writeZip(filePath);
195
+ });
196
+ }
95
197
  class ACReporterXLSX {
96
198
  name() {
97
199
  return "xlsx";
@@ -119,7 +221,6 @@ class ACReporterXLSX {
119
221
  policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels);
120
222
  policyInfo[ruleId].tkLevels.sort();
121
223
  }
122
- // const buffer: any = await workbook.xlsx.writeBuffer();
123
224
  let startScan = new Date(storedReport.engineReport.summary.startScan);
124
225
  let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`;
125
226
  if (config.outputFilenameTimestamp === false) {
@@ -128,35 +229,34 @@ class ACReporterXLSX {
128
229
  return {
129
230
  summaryPath: reportFilename,
130
231
  summary: (filename) => __awaiter(this, void 0, void 0, function* () {
131
- const ExcelJSModule = yield loadExcelJS();
132
- if (!ExcelJSModule) {
133
- showExcelJSWarning();
232
+ const writeExcelFile = yield loadWriteExcel();
233
+ if (!writeExcelFile) {
234
+ showWriteExcelWarning();
134
235
  return;
135
236
  }
136
- // @ts-ignore
137
- const workbook = new ExcelJSModule.stream.xlsx.WorkbookWriter({ filename, useStyles: true });
138
- // const workbook = new ExcelJS.Workbook({ useStyles: true });
139
- ACReporterXLSX.createOverviewSheet(config, summaryData, workbook);
140
- ACReporterXLSX.createScanSummarySheet(config, summaryData, workbook);
141
- ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData, workbook);
142
- ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData, workbook);
143
- ACReporterXLSX.createDefinitionsSheet(workbook);
144
- workbook.commit();
237
+ const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData);
238
+ const issueRowCount = issuesSheet._issueRowCount;
239
+ delete issuesSheet._issueRowCount;
240
+ const sheets = [
241
+ ACReporterXLSX.createOverviewSheet(config, summaryData),
242
+ ACReporterXLSX.createScanSummarySheet(config, summaryData),
243
+ ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData),
244
+ issuesSheet,
245
+ ACReporterXLSX.createDefinitionsSheet(),
246
+ ];
247
+ yield writeExcelFile(sheets).toFile(filename);
248
+ yield injectTableIntoFile(filename, issueRowCount);
145
249
  })
146
250
  };
147
251
  });
148
252
  }
149
- static createOverviewSheet(config, compressedScans, workbook) {
253
+ static createOverviewSheet(config, compressedScans) {
150
254
  let violations = 0;
151
255
  let needsReviews = 0;
152
256
  let recommendations = 0;
153
257
  let archived = 0;
154
258
  let totalIssues = 0;
155
259
  let startScan = 0;
156
- // BIG QUESTION: is report
157
- // 1. for current scan (from menu)
158
- // 2. all stored scans (from menu)
159
- // 3. selected stored scans (from scan manager)
160
260
  for (const compressedScan of compressedScans) {
161
261
  let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan);
162
262
  if (startScan === 0)
@@ -168,311 +268,147 @@ class ACReporterXLSX {
168
268
  archived += counts.ignored;
169
269
  }
170
270
  totalIssues = violations + needsReviews + recommendations + archived;
171
- const worksheet = workbook.addWorksheet("Overview");
172
- // Report Title
173
- worksheet.mergeCells('A1', "E1");
174
- const titleRow = worksheet.getRow(1);
175
- titleRow.height = 27;
176
- const cellA1 = worksheet.getCell('A1');
177
- cellA1.value = "Accessibility Scan Report";
178
- cellA1.alignment = { vertical: "middle", horizontal: "left" };
179
- cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
180
- cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
181
- // what are column widths - can't get it till you set it
182
- const colWidthData = [
183
- { col: 'A', width: 15.1 },
184
- { col: 'B', width: 15.9 },
185
- { col: 'C', width: 16.23 },
186
- { col: 'D', width: 19.4 },
271
+ const columns = [
272
+ { width: 15.1 },
273
+ { width: 15.9 },
274
+ { width: 16.23 },
275
+ { width: 19.4 },
276
+ { width: 15 },
187
277
  ];
188
- for (let i = 0; i < 4; i++) {
189
- worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
190
- }
191
- // note except for Report Date this is the same for all scans
192
278
  const rowData = [
193
279
  { key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' },
194
- // {key1: 'Version:', key2: "chrome.runtime.getManifest().version"},
195
280
  { key1: 'Version:', key2: config.toolID },
196
- //@ts-ignore
197
- // {key1: 'Rule set:', key2: (theCurrentScan.ruleSet === "Latest Deployment") ? archives[1].name : theCurrentScan.ruleSet },
198
281
  { key1: 'Rule set:', key2: config.ruleArchiveLabel },
199
282
  { key1: 'Guidelines:', key2: config.policies.join(", ") },
200
- { key1: 'Report date:', key2: new Date(startScan).toLocaleString() }, // do we need to get actual date?
201
- { key1: 'Scans:', key2: "" + compressedScans.length }, // *** NEED TO FIX FOR selected
202
- // { key1: 'Pages:', key2: "" }
283
+ { key1: 'Report date:', key2: new Date(startScan).toLocaleString() },
284
+ { key1: 'Scans:', key2: "" + compressedScans.length },
203
285
  ];
204
- for (let idx = 0; idx < rowData.length; ++idx) {
205
- worksheet.mergeCells(`B${idx + 2}`, `E${idx + 2}`);
206
- let i = idx + 2;
207
- worksheet.getRow(i).height = 12; // results in a row height of 16
208
- worksheet.getRow(i).getCell(1).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
209
- worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
210
- worksheet.getRow(i).getCell(1).alignment = { horizontal: "left" };
211
- worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" };
212
- // if (i == 7) {
213
- // worksheet.getRow(i).getCell(1).alignment = { vertical: "top" };
214
- // worksheet.getRow(i).getCell(2).alignment = { wrapText: true };
215
- // }
216
- worksheet.getRow(i).getCell(1).value = rowData[i - 2].key1;
217
- worksheet.getRow(i).getCell(2).value = rowData[i - 2].key2;
218
- }
219
- // Summary Title
220
- worksheet.mergeCells('A11', "E11");
221
- const summaryRow = worksheet.getRow(11);
222
- summaryRow.height = 27;
223
- const cellA11 = worksheet.getCell('A11');
224
- cellA11.value = "Summary";
225
- cellA11.alignment = { vertical: "middle", horizontal: "left" };
226
- cellA11.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
227
- cellA11.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
228
- // Scans info Headers
229
- worksheet.getRow(12).height = 16; // actual height is
230
- const cellA12 = worksheet.getCell('A12');
231
- cellA12.value = "Total issues";
232
- const cellB12 = worksheet.getCell('B12');
233
- cellB12.value = "Violations";
234
- const cellC12 = worksheet.getCell('C12');
235
- cellC12.value = "Needs review";
236
- const cellD12 = worksheet.getCell('D12');
237
- cellD12.value = "Recommendations";
238
- const cellE12 = worksheet.getCell('E12');
239
- cellE12.value = "Archived";
240
- const cellObjects1 = [cellA12, cellB12, cellC12, cellD12, cellE12];
241
- for (let i = 0; i < cellObjects1.length; i++) {
242
- cellObjects1[i].alignment = { vertical: "middle", horizontal: "center" };
243
- if (i == 1 || i == 2 || i == 3 || i === 4) {
244
- cellObjects1[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
245
- }
246
- else {
247
- cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
248
- }
249
- // cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} };
250
- cellObjects1[i].border = {
251
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
252
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
253
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
254
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
255
- };
256
- }
257
- cellA12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
258
- cellB12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } };
259
- cellC12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } };
260
- cellD12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } };
261
- // Scans info Values
262
- worksheet.getRow(13).height = 27; // actual height is
263
- const cellA13 = worksheet.getCell('A13');
264
- cellA13.value = totalIssues;
265
- const cellB13 = worksheet.getCell('B13');
266
- cellB13.value = violations;
267
- const cellC13 = worksheet.getCell('C13');
268
- cellC13.value = needsReviews;
269
- const cellD13 = worksheet.getCell('D13');
270
- cellD13.value = recommendations;
271
- const cellE13 = worksheet.getCell('E13');
272
- cellE13.value = archived;
273
- const cellObjects2 = [cellA13, cellB13, cellC13, cellD13, cellE13];
274
- for (let i = 0; i < cellObjects2.length; i++) {
275
- cellObjects2[i].alignment = { vertical: "middle", horizontal: "center" };
276
- cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
277
- // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
278
- cellObjects2[i].border = {
279
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
280
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
281
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
282
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
283
- };
286
+ const data = [];
287
+ // Row 1: Title spanning 5 cols
288
+ data.push([
289
+ { value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 },
290
+ null, null, null, null
291
+ ]);
292
+ // Rows 2–7: metadata key/value pairs
293
+ for (const row of rowData) {
294
+ data.push([
295
+ dataCell(row.key1, { align: "left", height: 12 }),
296
+ { value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 },
297
+ null, null, null
298
+ ]);
284
299
  }
300
+ // Row 8: blank spacer
301
+ data.push([null]);
302
+ // Row 9: blank spacer
303
+ data.push([null]);
304
+ // Row 10: blank spacer
305
+ data.push([null]);
306
+ // Row 11: "Summary" title spanning 5 cols
307
+ data.push([
308
+ { value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 },
309
+ null, null, null, null
310
+ ]);
311
+ // Row 12: column headers
312
+ data.push([
313
+ borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }),
314
+ borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }),
315
+ borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }),
316
+ borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }),
317
+ borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }),
318
+ ]);
319
+ // Row 13: values
320
+ data.push([
321
+ borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }),
322
+ borderedCell(violations, { align: "center", alignVertical: "center" }),
323
+ borderedCell(needsReviews, { align: "center", alignVertical: "center" }),
324
+ borderedCell(recommendations, { align: "center", alignVertical: "center" }),
325
+ borderedCell(archived, { align: "center", alignVertical: "center" }),
326
+ ]);
327
+ return { data, sheet: "Overview", columns };
285
328
  }
286
- static createScanSummarySheet(config, compressedScans, workbook) {
287
- const worksheet = workbook.addWorksheet("Scan summary");
288
- // Scans info Headers
289
- worksheet.getRow(1).height = 39; // actual height is 52
290
- const colWidthData = [
291
- { col: 'A', width: 27.0 },
292
- { col: 'B', width: 46.0 },
293
- { col: 'C', width: 20.17 },
294
- { col: 'D', width: 18.5 },
295
- { col: 'E', width: 17.17 },
296
- { col: 'F', width: 17.17 },
297
- { col: 'G', width: 17.17 },
298
- { col: 'H', width: 17.17 },
299
- { col: 'I', width: 17.17 },
329
+ static createScanSummarySheet(config, compressedScans) {
330
+ const columns = [
331
+ { width: 27.0 },
332
+ { width: 46.0 },
333
+ { width: 20.17 },
334
+ { width: 18.5 },
335
+ { width: 17.17 },
336
+ { width: 17.17 },
337
+ { width: 17.17 },
338
+ { width: 17.17 },
339
+ { width: 17.17 },
300
340
  ];
301
- for (let i = 0; i < 9; i++) {
302
- worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
303
- }
304
- const cellA1 = worksheet.getCell('A1');
305
- cellA1.value = "Page title";
306
- const cellB1 = worksheet.getCell('B1');
307
- cellB1.value = "Page url";
308
- const cellC1 = worksheet.getCell('C1');
309
- cellC1.value = "Scan label";
310
- const cellObjects1 = [cellA1, cellB1, cellC1];
311
- for (let i = 0; i < cellObjects1.length; i++) {
312
- cellObjects1[i].alignment = { vertical: "middle", horizontal: "left" };
313
- cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
314
- cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
315
- cellObjects1[i].border = {
316
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
317
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
318
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
319
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
320
- };
321
- }
322
- const cellD1 = worksheet.getCell('D1');
323
- cellD1.value = "Violations";
324
- const cellE1 = worksheet.getCell('E1');
325
- cellE1.value = "Needs review";
326
- const cellF1 = worksheet.getCell('F1');
327
- cellF1.value = "Recommendations";
328
- const cellG1 = worksheet.getCell('G1');
329
- cellG1.value = "Archived";
330
- const cellH1 = worksheet.getCell('H1');
331
- cellH1.value = "% elements without violations";
332
- const cellI1 = worksheet.getCell('I1');
333
- cellI1.value = "% elements without violations or items to review";
334
- const cellObjects2 = [cellD1, cellE1, cellF1, cellG1, cellH1, cellI1];
335
- for (let i = 0; i < cellObjects2.length; i++) {
336
- cellObjects2[i].alignment = { vertical: "middle", horizontal: "center", wrapText: true };
337
- if (i == 0 || i == 1 || i == 2 || i == 3) {
338
- cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
339
- }
340
- else {
341
- cellObjects2[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
342
- }
343
- // cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} };
344
- cellObjects2[i].border = {
345
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
346
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
347
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
348
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
349
- };
350
- }
351
- cellD1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } };
352
- cellE1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } };
353
- cellF1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } };
354
- cellG1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFFFF' } };
355
- cellH1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
356
- cellI1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
341
+ const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 };
342
+ const countHeaderStyle = Object.assign(Object.assign({}, headerStyle), { align: "center", wrap: true });
343
+ const data = [];
344
+ // Row 1: header row
345
+ data.push([
346
+ Object.assign(Object.assign({ value: "Page title" }, headerStyle), { align: "left" }),
347
+ Object.assign(Object.assign({ value: "Page url" }, headerStyle), { align: "left" }),
348
+ Object.assign(Object.assign({ value: "Scan label" }, headerStyle), { align: "left" }),
349
+ Object.assign(Object.assign({ value: "Violations" }, countHeaderStyle), { backgroundColor: "#E4AAAF", textColor: "#000000" }),
350
+ Object.assign(Object.assign({ value: "Needs review" }, countHeaderStyle), { backgroundColor: "#F4E08A", textColor: "#000000" }),
351
+ Object.assign(Object.assign({ value: "Recommendations" }, countHeaderStyle), { backgroundColor: "#96A9D7", textColor: "#000000" }),
352
+ Object.assign(Object.assign({ value: "Archived" }, countHeaderStyle), { backgroundColor: "#FFFFFF", textColor: "#000000" }),
353
+ Object.assign({ value: "% elements without violations" }, countHeaderStyle),
354
+ Object.assign({ value: "% elements without violations or items to review" }, countHeaderStyle),
355
+ ]);
357
356
  for (const compressedScan of compressedScans) {
358
357
  let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan);
359
358
  let counts = storedScan.engineReport.summary.counts;
360
- let row = worksheet.addRow([
361
- storedScan.pageTitle,
362
- storedScan.engineReport.summary.URL,
363
- storedScan.label,
364
- counts.violation,
365
- counts.potentialviolation + counts.manual,
366
- counts.recommendation + counts.potentialrecommendation,
367
- counts.ignored,
368
- (100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0),
369
- (100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0),
359
+ const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true };
360
+ const numStyle = Object.assign(Object.assign({}, textStyle), { align: "center", borderColor: "#A6A6A6", borderStyle: "thin" });
361
+ data.push([
362
+ Object.assign(Object.assign({ value: storedScan.pageTitle }, textStyle), { align: "left" }),
363
+ Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, textStyle), { align: "left" }),
364
+ Object.assign(Object.assign({ value: storedScan.label }, textStyle), { align: "left" }),
365
+ Object.assign({ value: counts.violation }, numStyle),
366
+ Object.assign({ value: counts.potentialviolation + counts.manual }, numStyle),
367
+ Object.assign({ value: counts.recommendation + counts.potentialrecommendation }, numStyle),
368
+ Object.assign({ value: counts.ignored }, numStyle),
369
+ Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0 }, numStyle),
370
+ Object.assign({ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0 }, numStyle),
370
371
  ]);
371
- row.height = 37; // actual height is
372
- for (let i = 1; i < 4; i++) {
373
- row.getCell(i).alignment = { vertical: "middle", horizontal: "left", wrapText: true };
374
- row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 };
375
- }
376
- for (let i = 4; i < 10; i++) {
377
- row.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true };
378
- row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 };
379
- // row.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
380
- row.getCell(i).border = {
381
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
382
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
383
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
384
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
385
- };
386
- }
387
- row.commit();
388
372
  }
389
- worksheet.commit();
373
+ return { data, sheet: "Scan summary", columns };
390
374
  }
391
- static buildIssueSummaryLevel(worksheet, fillColor, title, levelCount, levelrowValues) {
392
- // Level 1 Violation title
393
- const level1ViolationRow = worksheet.addRow(["", 0]);
394
- level1ViolationRow.height = 18; // target is 21
395
- const cellA6 = level1ViolationRow.getCell(1);
396
- cellA6.value = ` ${title}`;
397
- cellA6.alignment = { vertical: "middle", horizontal: "left" };
398
- cellA6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
399
- cellA6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } };
400
- level1ViolationRow.getCell(1).border = {
401
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
402
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
403
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
404
- // right: {style:'thin', color: {argb: 'FFA6A6A6'}}
405
- };
406
- const cellB6 = level1ViolationRow.getCell(2);
407
- cellB6.value = levelCount; // total level violations
408
- cellB6.alignment = { vertical: "middle", horizontal: "right" };
409
- cellB6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
410
- cellB6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } };
411
- level1ViolationRow.getCell(2).border = {
412
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
413
- // left: {style:'thin', color: {argb: 'FFA6A6A6'}},
414
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
415
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
416
- };
417
- // Level 1 Violation Rows
418
- // build rows
419
- let rowArray = [];
420
- // let row:any =[];
375
+ static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) {
376
+ const rows = [];
377
+ // Level type title row (e.g. "Violations")
378
+ rows.push([
379
+ { value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 },
380
+ { value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" },
381
+ ]);
382
+ // Individual issue message rows, sorted descending by count
383
+ const rowArray = [];
421
384
  for (const property in levelrowValues) {
422
- let row = [" " + `${property}`, parseInt(`${levelrowValues[property]}`)
423
- ];
424
- rowArray.push(row);
385
+ rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]);
425
386
  }
426
- // sort array according to count
427
- rowArray.sort((a, b) => (a[1] < b[1]) ? 1 : -1);
428
- // add array of rows
429
- for (const rowInfo of rowArray) {
430
- const row = worksheet.addRow(rowInfo);
431
- row.height = 14;
432
- row.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
433
- row.getCell(2).alignment = { vertical: "middle", horizontal: "right" };
434
- row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
435
- // row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
436
- // row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
437
- row.getCell(1).border = {
438
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
439
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
440
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
441
- // right: {style:'thin', color: {argb: 'FFA6A6A6'}}
442
- };
443
- row.getCell(2).border = {
444
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
445
- // left: {style:'thin', color: {argb: 'FFA6A6A6'}},
446
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
447
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
448
- };
449
- row.commit();
387
+ rowArray.sort((a, b) => b[1] - a[1]);
388
+ for (const [msg, count] of rowArray) {
389
+ rows.push([
390
+ { value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 },
391
+ { value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" },
392
+ ]);
450
393
  }
394
+ return rows;
451
395
  }
452
- static buildIssueSummaryTKLevel(worksheet, title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) {
453
- /////////////////////////////
454
- // build Level title
455
- /////////////////////////////
456
- const level1Row = worksheet.addRow(["", 0]);
457
- level1Row.height = 27; // actual is 36
458
- const cellA5 = level1Row.getCell(1);
459
- cellA5.value = title;
460
- cellA5.alignment = { vertical: "middle", horizontal: "left" };
461
- cellA5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
462
- cellA5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
463
- const cellB5 = level1Row.getCell(2);
464
- cellB5.value = levelCounts[0]; // total Level 1 issues
465
- cellB5.alignment = { vertical: "middle", horizontal: "right" };
466
- cellB5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
467
- cellB5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
468
- ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFE4AAAF", "Violation", levelCounts[1], levelVrowValues);
469
- ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFF4E08A", "Needs review", levelCounts[2], levelNRrowValues);
470
- ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FF96A9D7", "Recommendation", levelCounts[3], levelRrowValues);
396
+ static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) {
397
+ const rows = [];
398
+ // Level title row (e.g. "Level 1 - the most essential...")
399
+ rows.push([
400
+ { value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 },
401
+ { value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" },
402
+ ]);
403
+ rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues));
404
+ rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues));
405
+ rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues));
471
406
  if (levelCounts[4] > 0) {
472
- ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFCCCCCC", "Archived", levelCounts[4], levelArowValues);
407
+ rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues));
473
408
  }
409
+ return rows;
474
410
  }
475
- static createIssueSummarySheet(config, policyInfo, compressedScans, workbook) {
411
+ static createIssueSummarySheet(config, policyInfo, compressedScans) {
476
412
  let violations = 0;
477
413
  let needsReviews = 0;
478
414
  let recommendations = 0;
@@ -487,8 +423,7 @@ class ACReporterXLSX {
487
423
  archive += counts.ignored;
488
424
  }
489
425
  totalIssues = violations + needsReviews + recommendations;
490
- // counts
491
- let level1Counts = [0, 0, 0, 0, 0]; // level 1 total issues, violations, needs reviews, recommendations
426
+ let level1Counts = [0, 0, 0, 0, 0];
492
427
  let level2Counts = [0, 0, 0, 0, 0];
493
428
  let level3Counts = [0, 0, 0, 0, 0];
494
429
  let level4Counts = [0, 0, 0, 0, 0];
@@ -512,10 +447,7 @@ class ACReporterXLSX {
512
447
  let scan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan);
513
448
  for (const issue of scan.engineReport.results) {
514
449
  if (!(issue.ruleId in policyInfo)) {
515
- policyInfo[issue.ruleId] = {
516
- tkLevels: [],
517
- cps: []
518
- };
450
+ policyInfo[issue.ruleId] = { tkLevels: [], cps: [] };
519
451
  }
520
452
  let levelCounts, levelV, levelNR, levelR, levelA;
521
453
  const issuePolicyInfo = policyInfo[issue.ruleId];
@@ -569,111 +501,69 @@ class ACReporterXLSX {
569
501
  }
570
502
  }
571
503
  // @ts-ignore
572
- let level1VrowValues = this.countDuplicatesInArray(level1V); // note this returns an object
504
+ let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V);
573
505
  // @ts-ignore
574
- let level1NRrowValues = this.countDuplicatesInArray(level1NR);
506
+ let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR);
575
507
  // @ts-ignore
576
- let level1RrowValues = this.countDuplicatesInArray(level1R);
508
+ let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R);
577
509
  // @ts-ignore
578
- let level1ArowValues = this.countDuplicatesInArray(level1A);
510
+ let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A);
579
511
  // @ts-ignore
580
- let level2VrowValues = this.countDuplicatesInArray(level2V); // note this returns an object
512
+ let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V);
581
513
  // @ts-ignore
582
- let level2NRrowValues = this.countDuplicatesInArray(level2NR);
514
+ let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR);
583
515
  // @ts-ignore
584
- let level2RrowValues = this.countDuplicatesInArray(level2R);
516
+ let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R);
585
517
  // @ts-ignore
586
- let level2ArowValues = this.countDuplicatesInArray(level2A);
518
+ let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A);
587
519
  // @ts-ignore
588
- let level3VrowValues = this.countDuplicatesInArray(level3V); // note this returns an object
520
+ let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V);
589
521
  // @ts-ignore
590
- let level3NRrowValues = this.countDuplicatesInArray(level3NR);
522
+ let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR);
591
523
  // @ts-ignore
592
- let level3RrowValues = this.countDuplicatesInArray(level3R);
524
+ let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R);
593
525
  // @ts-ignore
594
- let level3ArowValues = this.countDuplicatesInArray(level3A);
526
+ let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A);
595
527
  // @ts-ignore
596
- let level4VrowValues = this.countDuplicatesInArray(level4V); // note this returns an object
528
+ let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V);
597
529
  // @ts-ignore
598
- let level4NRrowValues = this.countDuplicatesInArray(level4NR);
530
+ let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR);
599
531
  // @ts-ignore
600
- let level4RrowValues = this.countDuplicatesInArray(level4R);
532
+ let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R);
601
533
  // @ts-ignore
602
- let level4ArowValues = this.countDuplicatesInArray(level4A);
603
- const worksheet = workbook.addWorksheet("Issue summary");
604
- // Approach:
605
- // 1. sort by levels
606
- // 2. for each level sort by V, NR and R
607
- // 3. for each V, NR, and R in a level get issue dup counts
608
- // 4. build the rows
609
- // build Issue summary title
610
- worksheet.mergeCells('A1', "B1");
611
- const titleRow = worksheet.getRow(1);
612
- titleRow.height = 27; // actual is 36
613
- const cellA1 = worksheet.getCell('A1');
614
- cellA1.value = "Issue summary";
615
- cellA1.alignment = { vertical: "middle", horizontal: "left" };
616
- cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
617
- cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
618
- const colWidthData = [
619
- { col: 'A', width: 155.51 }, // note .84 added to actual width
620
- { col: 'B', width: 21.16 },
534
+ let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A);
535
+ const columns = [
536
+ { width: 155.51 },
537
+ { width: 21.16 },
621
538
  ];
622
- for (let i = 0; i < 2; i++) {
623
- worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
624
- }
625
- // build Description title
626
- worksheet.mergeCells('A2', "B2");
627
- const descriptionRow = worksheet.getRow(2);
628
- descriptionRow.height = 20.25; // actual is 27
629
- const cellA2 = worksheet.getCell("A2");
630
- 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.";
631
- cellA2.alignment = { vertical: "middle", horizontal: "left" };
632
- cellA2.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
633
- // cellA2.fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFCCC0DA'} };
634
- // build Total issues found: title
635
- // worksheet.mergeCells('A3', "B3");
636
- const totalIssuesRow = worksheet.getRow(3);
637
- totalIssuesRow.height = 27; // actual is 36
638
- const cellA3 = worksheet.getCell("A3");
639
- cellA3.value = "Total issues found:";
640
- cellA3.alignment = { vertical: "middle", horizontal: "left" };
641
- cellA3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
642
- cellA3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
643
- const cellB3 = worksheet.getCell("B3");
644
- cellB3.value = totalIssues;
645
- cellB3.alignment = { vertical: "middle", horizontal: "right" };
646
- cellB3.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
647
- cellB3.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
648
- // build Number of issues title
649
- const numberOfIssuesRow = worksheet.getRow(4);
650
- numberOfIssuesRow.height = 20.25; // actual is 27
651
- const cellA4 = worksheet.getCell("A4");
652
- // no value
653
- cellA4.alignment = { vertical: "middle", horizontal: "left" };
654
- cellA4.border = {
655
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
656
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
657
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
658
- right: { style: 'thin', color: { argb: 'FFFFFFFF' } }
659
- };
660
- const cellB4 = worksheet.getCell("B4");
661
- cellB4.value = "Number of issues";
662
- cellB4.alignment = { vertical: "middle", horizontal: "right" };
663
- cellB4.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
664
- cellB4.border = {
665
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
666
- left: { style: 'thin', color: { argb: 'FFFFFFFF' } },
667
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
668
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
669
- };
670
- ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues);
671
- ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues);
672
- ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues);
673
- ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues);
674
- worksheet.commit();
539
+ const data = [];
540
+ // Row 1: "Issue summary" title spanning 2 cols
541
+ data.push([
542
+ { value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 },
543
+ null
544
+ ]);
545
+ // Row 2: description spanning 2 cols
546
+ data.push([
547
+ { 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.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 },
548
+ null
549
+ ]);
550
+ // Row 3: "Total issues found:" with value
551
+ data.push([
552
+ { value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 },
553
+ { value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" },
554
+ ]);
555
+ // Row 4: "Number of issues" label
556
+ data.push([
557
+ { value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 },
558
+ { value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" },
559
+ ]);
560
+ data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues));
561
+ data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues));
562
+ data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues));
563
+ data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues));
564
+ return { data, sheet: "Issue summary", columns };
675
565
  }
676
- static createIssuesSheet(config, policyInfo, compressedScans, workbook) {
566
+ static createIssuesSheet(config, policyInfo, compressedScans) {
677
567
  const valueMap = {
678
568
  "VIOLATION": {
679
569
  "POTENTIAL": "Needs review",
@@ -694,17 +584,48 @@ class ACReporterXLSX {
694
584
  "MANUAL": "Recommendation"
695
585
  }
696
586
  };
697
- const worksheet = workbook.addWorksheet("Issues");
698
- // build rows
699
- let rowArray = [];
587
+ const columns = [
588
+ { width: 18.0 },
589
+ { width: 20.5 },
590
+ { width: 21.0 },
591
+ { width: 18.5 },
592
+ { width: 17.0 },
593
+ { width: 17.17 },
594
+ { width: 17.17 },
595
+ { width: 17.17 },
596
+ { width: 17.17 },
597
+ { width: 17.17 },
598
+ { width: 14.00 },
599
+ { width: 17.17 },
600
+ { width: 43.00 },
601
+ { width: 17.17 },
602
+ ];
603
+ // Header and data row colors are intentionally omitted — the Excel table
604
+ // (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring.
605
+ const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 };
606
+ const data = [];
607
+ // Header row
608
+ data.push([
609
+ Object.assign({ value: "Page title" }, hStyle),
610
+ Object.assign({ value: "Page URL" }, hStyle),
611
+ Object.assign({ value: "Scan label" }, hStyle),
612
+ Object.assign({ value: "Issue ID" }, hStyle),
613
+ Object.assign({ value: "Issue type" }, hStyle),
614
+ Object.assign({ value: "Toolkit level" }, hStyle),
615
+ Object.assign({ value: "Checkpoint" }, hStyle),
616
+ Object.assign({ value: "WCAG level" }, hStyle),
617
+ Object.assign({ value: "Rule" }, hStyle),
618
+ Object.assign({ value: "Issue" }, hStyle),
619
+ Object.assign({ value: "Element" }, hStyle),
620
+ Object.assign({ value: "Code" }, hStyle),
621
+ Object.assign({ value: "Xpath" }, hStyle),
622
+ Object.assign({ value: "Help" }, hStyle),
623
+ ]);
700
624
  for (const compressedScan of compressedScans) {
701
625
  let storedScan = ReporterManager_js_1.ReporterManager.uncompressReport(compressedScan);
702
626
  for (const item of storedScan.engineReport.results) {
703
627
  if (!(item.ruleId in policyInfo)) {
704
- policyInfo[item.ruleId] = {
705
- tkLevels: [],
706
- cps: []
707
- };
628
+ policyInfo[item.ruleId] = { tkLevels: [], cps: [] };
708
629
  }
709
630
  let polInfo = policyInfo[item.ruleId];
710
631
  let cps = polInfo.cps.filter(cp => {
@@ -715,195 +636,37 @@ class ACReporterXLSX {
715
636
  wcagLevels.sort();
716
637
  let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`));
717
638
  cpStrs.sort();
718
- let row = [
719
- storedScan.pageTitle,
720
- storedScan.engineReport.summary.URL,
721
- storedScan.label,
722
- this.stringHash(item.ruleId + item.path.dom),
723
- `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}`,
724
- polInfo.tkLevels.join(", "),
725
- cpStrs.join("; "),
726
- wcagLevels.join(", "),
727
- item.ruleId,
728
- item.message.substring(0, 32767), //max ength for MS Excel 32767 characters
729
- this.get_element(item.snippet),
730
- item.snippet.substring(0, 32767),
731
- item.path.dom,
732
- item.help,
733
- item.source
734
- // engine_end_point + '/tools/help/' + item.ruleId
735
- ];
736
- // let row = [myStoredData[i][0], myStoredData[i][1], storedScans[j].label,
737
- // myStoredData[i][3], myStoredData[i][4], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][5],
738
- // myStoredData[i][6], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][7], myStoredData[i][8],
739
- // myStoredData[i][9], myStoredData[i][10], myStoredData[i][11],
740
- // myStoredData[i][12], myStoredData[i][13]
741
- // ];
742
- rowArray.push(row);
639
+ const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 };
640
+ data.push([
641
+ Object.assign(Object.assign({ value: storedScan.pageTitle }, dStyle), { align: "left", alignVertical: "center" }),
642
+ Object.assign(Object.assign({ value: storedScan.engineReport.summary.URL }, dStyle), { align: "left", alignVertical: "center" }),
643
+ Object.assign(Object.assign({ value: storedScan.label }, dStyle), { align: "center", alignVertical: "center" }),
644
+ Object.assign(Object.assign({ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom) }, dStyle), { align: "left", alignVertical: "center" }),
645
+ Object.assign(Object.assign({ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}` }, dStyle), { align: "center", alignVertical: "center" }),
646
+ Object.assign(Object.assign({ value: polInfo.tkLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }),
647
+ Object.assign(Object.assign({ value: cpStrs.join("; ") }, dStyle), { align: "left", alignVertical: "center" }),
648
+ Object.assign(Object.assign({ value: wcagLevels.join(", ") }, dStyle), { align: "center", alignVertical: "center" }),
649
+ Object.assign(Object.assign({ value: item.ruleId }, dStyle), { align: "left", alignVertical: "center" }),
650
+ Object.assign(Object.assign({ value: item.message.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }),
651
+ Object.assign(Object.assign({ value: ACReporterXLSX.get_element(item.snippet) }, dStyle), { align: "center", alignVertical: "center" }),
652
+ Object.assign(Object.assign({ value: item.snippet.substring(0, 32767) }, dStyle), { align: "left", alignVertical: "center" }),
653
+ Object.assign(Object.assign({ value: item.path.dom }, dStyle), { align: "left", alignVertical: "center" }),
654
+ Object.assign(Object.assign({ value: item.help }, dStyle), { align: "left", alignVertical: "center" }),
655
+ ]);
743
656
  }
744
657
  }
745
- // column widths
746
- const colWidthData = [
747
- { col: 'A', width: 18.0, alignment: { vertical: "middle", horizontal: "left" } },
748
- { col: 'B', width: 20.5, alignment: { vertical: "middle", horizontal: "left" } },
749
- { col: 'C', width: 21.0, alignment: { vertical: "middle", horizontal: "center" } },
750
- { col: 'D', width: 18.5, alignment: { vertical: "middle", horizontal: "left" } },
751
- { col: 'E', width: 17.0, alignment: { vertical: "middle", horizontal: "center" } },
752
- { col: 'F', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } },
753
- { col: 'G', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
754
- { col: 'H', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } },
755
- { col: 'I', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
756
- { col: 'J', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
757
- { col: 'K', width: 14.00, alignment: { vertical: "middle", horizontal: "center" } },
758
- { col: 'L', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
759
- { col: 'M', width: 43.00, alignment: { vertical: "middle", horizontal: "left" } },
760
- { col: 'N', width: 17.17, alignment: { vertical: "middle", horizontal: "fill" } },
761
- ];
762
- for (let i = 0; i < 14; i++) {
763
- worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
764
- worksheet.getColumn(colWidthData[i].col).alignment = colWidthData[i].alignment;
765
- }
766
- // add table to a sheet
767
- let headRow = worksheet.addRow([
768
- "Page title",
769
- "Page URL",
770
- "Scan label",
771
- "Issue ID",
772
- "Issue type",
773
- "Toolkit level",
774
- "Checkpoint",
775
- "WCAG level",
776
- "Rule",
777
- "Issue",
778
- "Element",
779
- "Code",
780
- "Xpath",
781
- "Help",
782
- ""
783
- ]);
784
- // set font and alignment for the header cells
785
- for (let i = 1; i < 15; i++) {
786
- headRow.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true };
787
- headRow.getCell(i).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
788
- headRow.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
789
- headRow.getCell(i).border = {
790
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
791
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
792
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
793
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
794
- };
795
- }
796
- // height for header row
797
- headRow.height = 24;
798
- headRow.commit();
799
- for (const rowInfo of rowArray) {
800
- const row = worksheet.addRow(rowInfo);
801
- row.height = 14;
802
- for (let j = 1; j <= 14; j++) {
803
- row.getCell(j).border = {
804
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
805
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
806
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
807
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
808
- };
809
- }
810
- row.commit();
811
- }
812
- for (const key in worksheet) {
813
- if (typeof worksheet[key] === "function") {
814
- console.log(key);
815
- }
816
- }
817
- // worksheet.addTable({
818
- // name: 'MyTable',
819
- // ref: 'A1',
820
- // headerRow: true,
821
- // // totalsRow: true,
822
- // style: {
823
- // theme: 'TableStyleMedium2',
824
- // showRowStripes: true,
825
- // },
826
- // columns: [
827
- // { name: 'Page title', filterButton: true },
828
- // { name: 'Page URL', filterButton: true },
829
- // { name: 'Scan label', filterButton: true },
830
- // { name: 'Issue ID', filterButton: true },
831
- // { name: 'Issue type', filterButton: true },
832
- // { name: 'Toolkit level', filterButton: true },
833
- // { name: 'Checkpoint', filterButton: true },
834
- // { name: 'WCAG level', filterButton: true },
835
- // { name: 'Rule', filterButton: true },
836
- // { name: 'Issue', filterButton: true },
837
- // { name: 'Element', filterButton: true },
838
- // { name: 'Code', filterButton: true },
839
- // { name: 'Xpath', filterButton: true },
840
- // { name: 'Help', filterButton: true },
841
- // ],
842
- // rows: rowArray
843
- // });
844
- // for (let i = 2; i <= rowArray.length + 1; i++) {
845
- // worksheet.getRow(i).height = 14;
846
- // for (let j = 1; j <= 14; j++) {
847
- // worksheet.getRow(i).getCell(j).border = {
848
- // top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
849
- // left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
850
- // bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
851
- // right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
852
- // }
853
- // }
854
- // worksheet.getRow(i).commit();
855
- // }
856
- worksheet.commit();
658
+ return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length };
857
659
  }
858
- static createDefinitionsSheet(workbook) {
859
- const worksheet = workbook.addWorksheet("Definition of fields");
860
- // "Definition of fields" title
861
- worksheet.mergeCells('A1', "B1");
862
- const titleRow = worksheet.getRow(1);
863
- titleRow.height = 36; // actual is 48
864
- titleRow.getCell(1).value = "Definition of fields";
865
- titleRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
866
- titleRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: "20" };
867
- titleRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
868
- const colWidthData = [
869
- { col: 'A', width: '41.51' }, // note .84 added to actual width
870
- { col: 'B', width: '119.51' },
660
+ static createDefinitionsSheet() {
661
+ const columns = [
662
+ { width: 41.51 },
663
+ { width: 119.51 },
871
664
  ];
872
- for (let i = 0; i < 2; i++) {
873
- worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
874
- }
875
- // blank row
876
- worksheet.mergeCells('A2', "B2");
877
- const blankRow = worksheet.getRow(2);
878
- blankRow.height = 12; // actual is 16
879
- // "Scan summary and Issue summary" title
880
- worksheet.mergeCells('A3', "B3");
881
- const summaryRow = worksheet.getRow(3);
882
- summaryRow.height = 20; // actual is 26.75
883
- summaryRow.getCell(1).value = "Scan summary and Issue summary";
884
- summaryRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
885
- summaryRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
886
- summaryRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
887
- // row 4 Field / Definition
888
- const row4 = worksheet.getRow(4);
889
- row4.height = 16; // actual is
890
- row4.getCell(1).value = "Field";
891
- row4.getCell(2).value = "Definition";
892
- row4.getCell(1).alignment = row4.getCell(2).alignment = { vertical: "middle", horizontal: "left" };
893
- row4.getCell(1).font = row4.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 };
894
- row4.getCell(1).fill = row4.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } };
895
- row4.getCell(1).border = row4.getCell(2).border = {
896
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
897
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
898
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
899
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
900
- };
901
- // rows 5-13
902
- // set row height for rows 5-13
903
- for (let i = 5; i < 14; i++) {
904
- worksheet.getRow(i).height = 12; // results in a row height of 16
905
- }
906
- let rowData = [
665
+ const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" };
666
+ const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" };
667
+ const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" };
668
+ const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 };
669
+ const summaryRowData = [
907
670
  { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' },
908
671
  { 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.' },
909
672
  { key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' },
@@ -913,43 +676,7 @@ class ACReporterXLSX {
913
676
  { 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.' },
914
677
  { 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.' }
915
678
  ];
916
- for (let i = 5; i < rowData.length + 5; i++) {
917
- worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
918
- worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" };
919
- }
920
- for (let i = 5; i < rowData.length + 5; i++) {
921
- worksheet.getRow(i).getCell(1).value = rowData[i - 5].key1;
922
- worksheet.getRow(i).getCell(2).value = rowData[i - 5].key2;
923
- }
924
- // "Scan summary and Issue summary" title
925
- worksheet.mergeCells('A14', "B14");
926
- const issuesRow = worksheet.getRow(14);
927
- issuesRow.height = 20; // actual is 26.75
928
- issuesRow.getCell(1).value = "Issues";
929
- issuesRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
930
- issuesRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
931
- issuesRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
932
- // row 15 Field / Definition
933
- const row15 = worksheet.getRow(15);
934
- row15.height = 16; // actual is
935
- row15.getCell(1).value = "Field";
936
- row15.getCell(2).value = "Definition";
937
- row15.getCell(1).alignment = row15.getCell(2).alignment = { vertical: "middle", horizontal: "left" };
938
- row15.getCell(1).font = row15.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 };
939
- row15.getCell(1).fill = row15.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } };
940
- row15.getCell(1).border = row15.getCell(2).border = {
941
- top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
942
- left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
943
- bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
944
- right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
945
- };
946
- // rows 16-28
947
- // set row height for rows 16-28
948
- for (let i = 16; i < 29; i++) {
949
- worksheet.getRow(i).height = 12; // results in a row height of 16
950
- }
951
- rowData = [];
952
- rowData = [
679
+ const issuesRowData = [
953
680
  { key1: 'Page', key2: 'Identifies the page or html file that was scanned.' },
954
681
  { 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.' },
955
682
  { key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' },
@@ -964,19 +691,54 @@ class ACReporterXLSX {
964
691
  { key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' },
965
692
  { key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' },
966
693
  ];
967
- for (let i = 16; i < 29; i++) {
968
- worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
969
- worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" };
694
+ const data = [];
695
+ // Row 1: "Definition of fields" title spanning 2 cols
696
+ data.push([
697
+ Object.assign(Object.assign({ value: "Definition of fields" }, titleStyle), { height: 36, columnSpan: 2 }),
698
+ null
699
+ ]);
700
+ // Row 2: blank
701
+ data.push([{ value: null, height: 12, columnSpan: 2 }, null]);
702
+ // Row 3: "Scan summary and Issue summary" section header
703
+ data.push([
704
+ Object.assign(Object.assign({ value: "Scan summary and Issue summary" }, sectionStyle), { height: 20, columnSpan: 2 }),
705
+ null
706
+ ]);
707
+ // Row 4: "Field / Definition" subheader
708
+ data.push([
709
+ Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }),
710
+ Object.assign({ value: "Definition" }, subHeaderStyle),
711
+ ]);
712
+ // Rows 5–12: scan summary definitions
713
+ for (const row of summaryRowData) {
714
+ data.push([
715
+ Object.assign({ value: row.key1 }, dataStyle),
716
+ Object.assign({ value: row.key2 }, dataStyle),
717
+ ]);
970
718
  }
971
- for (let i = 16; i < 29; i++) {
972
- worksheet.getRow(i).getCell(1).value = rowData[i - 16].key1;
973
- worksheet.getRow(i).getCell(2).value = rowData[i - 16].key2;
719
+ // Row 13: blank (separator between sections) — kept simple
720
+ data.push([{ value: null, height: 12, columnSpan: 2 }, null]);
721
+ // Row 14: "Issues" section header
722
+ data.push([
723
+ Object.assign(Object.assign({ value: "Issues" }, sectionStyle), { height: 20, columnSpan: 2 }),
724
+ null
725
+ ]);
726
+ // Row 15: "Field / Definition" subheader
727
+ data.push([
728
+ Object.assign(Object.assign({ value: "Field" }, subHeaderStyle), { height: 16 }),
729
+ Object.assign({ value: "Definition" }, subHeaderStyle),
730
+ ]);
731
+ // Rows 16–28: issues definitions
732
+ for (const row of issuesRowData) {
733
+ data.push([
734
+ Object.assign({ value: row.key1 }, dataStyle),
735
+ Object.assign({ value: row.key2 }, dataStyle),
736
+ ]);
974
737
  }
975
- worksheet.commit();
738
+ return { data, sheet: "Definition of fields", columns };
976
739
  }
977
740
  static countDuplicatesInArray(array) {
978
741
  let count = {};
979
- // let result = [];
980
742
  array.forEach(item => {
981
743
  if (count[item]) {
982
744
  //@ts-ignore
@@ -1010,9 +772,6 @@ class ACReporterXLSX {
1010
772
  while (i) {
1011
773
  hash = (hash * 33) ^ str.charCodeAt(--i);
1012
774
  }
1013
- /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
1014
- * integers. Since we want the results to be always positive, convert the
1015
- * signed int to an unsigned by doing an unsigned bitshift. */
1016
775
  return hash >>> 0;
1017
776
  }
1018
777
  }