@holmdigital/engine 1.4.12 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +59 -59
- package/README.md +198 -158
- package/dist/{chunk-YWRTSIUX.mjs → chunk-32WU5BD6.mjs} +151 -7
- package/dist/{chunk-FFTRXRZU.mjs → chunk-ZO2XNHHT.mjs} +177 -4
- package/dist/cli/index.js +591 -45
- package/dist/cli/index.mjs +194 -56
- package/dist/github-actions-CGWJSLMB.mjs +24 -0
- package/dist/{i18n-WJLEZT5A.mjs → i18n-VBP5BVTT.mjs} +1 -1
- package/dist/index.d.mts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +339 -9
- package/dist/index.mjs +7 -3
- package/dist/junit-generator-FK3GE5E4.mjs +43 -0
- package/package.json +83 -79
package/dist/index.js
CHANGED
|
@@ -45,6 +45,8 @@ var init_en = __esm({
|
|
|
45
45
|
pdf_saved: "PDF Report saved to {path}",
|
|
46
46
|
scan_failed: "Scan failed",
|
|
47
47
|
critical_failure: "\nCI/CD Failure: Critical regulatory violations found.",
|
|
48
|
+
generating_statement: "Generating Accessibility Statement...",
|
|
49
|
+
statement_saved: "Accessibility Statement saved to {path}",
|
|
48
50
|
score: "\nCompliance Score: {score}/100",
|
|
49
51
|
status: "Compliance Status: {status}",
|
|
50
52
|
not_compliant: " (Not compliant with legal requirements)",
|
|
@@ -52,7 +54,8 @@ var init_en = __esm({
|
|
|
52
54
|
prescriptive_fix: "\n\u{1F4A1} Prescriptive Fix:",
|
|
53
55
|
use_component: "Use component: {component}",
|
|
54
56
|
pseudo_tests: "\n\u{1F9EC} Generating Pseudo-Automation Tests...\n",
|
|
55
|
-
test_for: "Test for {ruleId}:"
|
|
57
|
+
test_for: "Test for {ruleId}:",
|
|
58
|
+
junit_saved: "JUnit XML report saved to {path}"
|
|
56
59
|
},
|
|
57
60
|
report: {
|
|
58
61
|
title: "Accessibility Report - {url}",
|
|
@@ -87,6 +90,8 @@ var init_sv = __esm({
|
|
|
87
90
|
pdf_saved: "PDF-rapport sparad till {path}",
|
|
88
91
|
scan_failed: "Skanning misslyckades",
|
|
89
92
|
critical_failure: "\nCI/CD Fel: Kritiska regulatoriska brister hittades.",
|
|
93
|
+
generating_statement: "Genererar tillg\xE4nglighetsredog\xF6relse...",
|
|
94
|
+
statement_saved: "Tillg\xE4nglighetsredog\xF6relse sparad till {path}",
|
|
90
95
|
score: "\nEfterlevnadspo\xE4ng: {score}/100",
|
|
91
96
|
status: "Efterlevnadsstatus: {status}",
|
|
92
97
|
not_compliant: " (Uppfyller ej legala krav)",
|
|
@@ -94,7 +99,8 @@ var init_sv = __esm({
|
|
|
94
99
|
prescriptive_fix: "\n\u{1F4A1} Preskriptiv L\xF6sning:",
|
|
95
100
|
use_component: "Anv\xE4nd komponent: {component}",
|
|
96
101
|
pseudo_tests: "\n\u{1F9EC} Genererar Pseudo-automationstester...\n",
|
|
97
|
-
test_for: "Test f\xF6r {ruleId}:"
|
|
102
|
+
test_for: "Test f\xF6r {ruleId}:",
|
|
103
|
+
junit_saved: "JUnit XML-rapport sparad till {path}"
|
|
98
104
|
},
|
|
99
105
|
report: {
|
|
100
106
|
title: "Tillg\xE4nglighetsrapport - {url}",
|
|
@@ -129,6 +135,8 @@ var init_de = __esm({
|
|
|
129
135
|
pdf_saved: "PDF-Bericht gespeichert unter {path}",
|
|
130
136
|
scan_failed: "Scan fehlgeschlagen",
|
|
131
137
|
critical_failure: "\nCI/CD Fehler: Kritische regulatorische Verst\xF6\xDFe gefunden.",
|
|
138
|
+
generating_statement: "Generiere Barrierefreiheitserkl\xE4rung...",
|
|
139
|
+
statement_saved: "Barrierefreiheitserkl\xE4rung gespeichert unter {path}",
|
|
132
140
|
score: "\nKonformit\xE4tsbewertung: {score}/100",
|
|
133
141
|
status: "Konformit\xE4tsstatus: {status}",
|
|
134
142
|
not_compliant: " (Nicht konform mit gesetzlichen Anforderungen - BITV 2.0)",
|
|
@@ -136,7 +144,8 @@ var init_de = __esm({
|
|
|
136
144
|
prescriptive_fix: "\n\u{1F4A1} Vorschriftsm\xE4\xDFige L\xF6sung:",
|
|
137
145
|
use_component: "Verwenden Sie die Komponente: {component}",
|
|
138
146
|
pseudo_tests: "\n\u{1F9EC} Generiere Pseudo-Automatisierungstests...\n",
|
|
139
|
-
test_for: "Test f\xFCr {ruleId}:"
|
|
147
|
+
test_for: "Test f\xFCr {ruleId}:",
|
|
148
|
+
junit_saved: "JUnit XML-Bericht gespeichert unter {path}"
|
|
140
149
|
},
|
|
141
150
|
report: {
|
|
142
151
|
title: "Barrierefreiheitsbericht - {url}",
|
|
@@ -171,6 +180,8 @@ var init_fr = __esm({
|
|
|
171
180
|
pdf_saved: "Rapport PDF enregistr\xE9 sous {path}",
|
|
172
181
|
scan_failed: "\xC9chec du scan",
|
|
173
182
|
critical_failure: "\n\xC9chec CI/CD : Violations r\xE9glementaires critiques d\xE9tect\xE9es.",
|
|
183
|
+
generating_statement: "G\xE9n\xE9ration de la d\xE9claration d'accessibilit\xE9...",
|
|
184
|
+
statement_saved: "D\xE9claration d'accessibilit\xE9 enregistr\xE9e sous {path}",
|
|
174
185
|
score: "\nScore de Conformit\xE9 : {score}/100",
|
|
175
186
|
status: "Statut de Conformit\xE9 : {status}",
|
|
176
187
|
not_compliant: " (Non conforme aux exigences l\xE9gales - RGAA)",
|
|
@@ -178,7 +189,8 @@ var init_fr = __esm({
|
|
|
178
189
|
prescriptive_fix: "\n\u{1F4A1} Solution Prescriptive :",
|
|
179
190
|
use_component: "Utilisez le composant : {component}",
|
|
180
191
|
pseudo_tests: "\n\u{1F9EC} G\xE9n\xE9ration de tests de pseudo-automatisation...\n",
|
|
181
|
-
test_for: "Test pour {ruleId} :"
|
|
192
|
+
test_for: "Test pour {ruleId} :",
|
|
193
|
+
junit_saved: "Rapport XML JUnit enregistr\xE9 sous {path}"
|
|
182
194
|
},
|
|
183
195
|
report: {
|
|
184
196
|
title: "Rapport d'Accessibilit\xE9 - {url}",
|
|
@@ -213,6 +225,8 @@ var init_es = __esm({
|
|
|
213
225
|
pdf_saved: "Informe PDF guardado en {path}",
|
|
214
226
|
scan_failed: "Escaneo fallido",
|
|
215
227
|
critical_failure: "\nFallo de CI/CD: Se encontraron violaciones regulatorias cr\xEDticas.",
|
|
228
|
+
generating_statement: "Generando Declaraci\xF3n de Accesibilidad...",
|
|
229
|
+
statement_saved: "Declaraci\xF3n de Accesibilidad guardada en {path}",
|
|
216
230
|
score: "\nPuntuaci\xF3n de Cumplimiento: {score}/100",
|
|
217
231
|
status: "Estado de Cumplimiento: {status}",
|
|
218
232
|
not_compliant: " (No cumple con los requisitos legales - UNE 139803)",
|
|
@@ -220,7 +234,8 @@ var init_es = __esm({
|
|
|
220
234
|
prescriptive_fix: "\n\u{1F4A1} Soluci\xF3n Prescriptiva:",
|
|
221
235
|
use_component: "Use el componente: {component}",
|
|
222
236
|
pseudo_tests: "\n\u{1F9EC} Generando pruebas de pseudo-automatizaci\xF3n...\n",
|
|
223
|
-
test_for: "Prueba para {ruleId}:"
|
|
237
|
+
test_for: "Prueba para {ruleId}:",
|
|
238
|
+
junit_saved: "Informe JUnit XML guardado en {path}"
|
|
224
239
|
},
|
|
225
240
|
report: {
|
|
226
241
|
title: "Informe de Accesibilidad - {url}",
|
|
@@ -240,6 +255,141 @@ var init_es = __esm({
|
|
|
240
255
|
}
|
|
241
256
|
});
|
|
242
257
|
|
|
258
|
+
// src/locales/fi.json
|
|
259
|
+
var fi_default;
|
|
260
|
+
var init_fi = __esm({
|
|
261
|
+
"src/locales/fi.json"() {
|
|
262
|
+
fi_default = {
|
|
263
|
+
cli: {
|
|
264
|
+
title: "\n\u{1F310} HolmDigital S\xE4\xE4ntelyskanneri\n",
|
|
265
|
+
scanning: "Skannataan {url}...\n",
|
|
266
|
+
initializing: "Alustetaan skanneria...",
|
|
267
|
+
analyzing: "Analysoidaan DOM & Shadow DOM...",
|
|
268
|
+
complete: "Skannaus valmis!",
|
|
269
|
+
generating_pdf: "Luodaan PDF-raporttia...",
|
|
270
|
+
pdf_saved: "PDF-raportti tallennettu kohteeseen {path}",
|
|
271
|
+
scan_failed: "Skannaus ep\xE4onnistui",
|
|
272
|
+
critical_failure: "\nCI/CD Virhe: Kriittisi\xE4 s\xE4\xE4ntelyrikkomuksia havaittu.",
|
|
273
|
+
generating_statement: "Luodaan saavutettavuusselostetta...",
|
|
274
|
+
statement_saved: "Saavutettavuusseloste tallennettu kohteeseen {path}",
|
|
275
|
+
score: "\nVaatimustenmukaisuus: {score}/100",
|
|
276
|
+
status: "Tila: {status}",
|
|
277
|
+
not_compliant: " (Ei t\xE4yt\xE4 lakis\xE4\xE4teisi\xE4 vaatimuksia - Laki digitaalisten palvelujen tarjoamisesta)",
|
|
278
|
+
viewport: "N\xE4kym\xE4: {width}x{height}",
|
|
279
|
+
prescriptive_fix: "\n\u{1F4A1} Ehdotettu korjaus:",
|
|
280
|
+
use_component: "K\xE4yt\xE4 komponenttia: {component}",
|
|
281
|
+
pseudo_tests: "\n\u{1F9EC} Luodaan Pseudo-automaatiotestej\xE4...\n",
|
|
282
|
+
test_for: "Testi {ruleId}:lle:",
|
|
283
|
+
junit_saved: "JUnit XML -raportti tallennettu kohteeseen {path}"
|
|
284
|
+
},
|
|
285
|
+
report: {
|
|
286
|
+
title: "Saavutettavuusraportti - {url}",
|
|
287
|
+
generated: "Luotu: {date}",
|
|
288
|
+
scan_target: "Skannauksen kohde: {url}",
|
|
289
|
+
overall_score: "Kokonaispisteet",
|
|
290
|
+
critical_issues: "Kriittiset ongelmat",
|
|
291
|
+
high_issues: "Vakavat ongelmat",
|
|
292
|
+
total_issues: "Ongelmat yhteens\xE4",
|
|
293
|
+
html_errors: "HTML-virheet",
|
|
294
|
+
detailed_violations: "Yksityiskohtaiset rikkomukset",
|
|
295
|
+
prescriptive_fix: "\u{1F4A1} Ehdotettu korjaus",
|
|
296
|
+
use: "K\xE4yt\xE4",
|
|
297
|
+
footer: "Luonut @holmdigital/engine v0.1.0 \u2022 Standardit: WCAG 2.1 AA, EN 301 549, Digipalvelulaki"
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// src/locales/dk.json
|
|
304
|
+
var dk_default;
|
|
305
|
+
var init_dk = __esm({
|
|
306
|
+
"src/locales/dk.json"() {
|
|
307
|
+
dk_default = {
|
|
308
|
+
cli: {
|
|
309
|
+
title: "\n\u{1F310} HolmDigital Regulatorisk Scanner\n",
|
|
310
|
+
scanning: "Scanner {url}...\n",
|
|
311
|
+
initializing: "Initialiserer scanner...",
|
|
312
|
+
analyzing: "Analyserer DOM & Shadow DOM...",
|
|
313
|
+
complete: "Scanning f\xE6rdig!",
|
|
314
|
+
generating_pdf: "Genererer PDF-rapport...",
|
|
315
|
+
pdf_saved: "PDF-rapport gemt i {path}",
|
|
316
|
+
scan_failed: "Scanning mislykkedes",
|
|
317
|
+
critical_failure: "\nCI/CD Fejl: Kritiske regulatoriske overtr\xE6delser fundet.",
|
|
318
|
+
generating_statement: "Genererer tilg\xE6ngelighedserkl\xE6ring...",
|
|
319
|
+
statement_saved: "Tilg\xE6ngelighedserkl\xE6ring gemt i {path}",
|
|
320
|
+
score: "\nOverholdelsesscore: {score}/100",
|
|
321
|
+
status: "Overholdelsesstatus: {status}",
|
|
322
|
+
not_compliant: " (Opfylder ikke lovkrav - Lov om tilg\xE6ngelighed)",
|
|
323
|
+
viewport: "Viewport: {width}x{height}",
|
|
324
|
+
prescriptive_fix: "\n\u{1F4A1} Foresl\xE5et l\xF8sning:",
|
|
325
|
+
use_component: "Brug komponent: {component}",
|
|
326
|
+
pseudo_tests: "\n\u{1F9EC} Genererer Pseudo-automatiseringstests...\n",
|
|
327
|
+
test_for: "Test for {ruleId}:",
|
|
328
|
+
junit_saved: "JUnit XML-rapport gemt i {path}"
|
|
329
|
+
},
|
|
330
|
+
report: {
|
|
331
|
+
title: "Tilg\xE6ngelighedsrapport - {url}",
|
|
332
|
+
generated: "Genereret: {date}",
|
|
333
|
+
scan_target: "Scanningsm\xE5l: {url}",
|
|
334
|
+
overall_score: "Samlet Score",
|
|
335
|
+
critical_issues: "Kritiske Fejl",
|
|
336
|
+
high_issues: "Alvorlige Fejl",
|
|
337
|
+
total_issues: "Totale Fejl",
|
|
338
|
+
html_errors: "HTML Fejl",
|
|
339
|
+
detailed_violations: "Detaljerede Overtr\xE6delser",
|
|
340
|
+
prescriptive_fix: "\u{1F4A1} Foresl\xE5et L\xF8sning",
|
|
341
|
+
use: "Brug",
|
|
342
|
+
footer: "Genereret af @holmdigital/engine v0.1.0 \u2022 Standarder: WCAG 2.1 AA, EN 301 549, Lov om tilg\xE6ngelighed"
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// src/locales/no.json
|
|
349
|
+
var no_default;
|
|
350
|
+
var init_no = __esm({
|
|
351
|
+
"src/locales/no.json"() {
|
|
352
|
+
no_default = {
|
|
353
|
+
cli: {
|
|
354
|
+
title: "\n\u{1F310} HolmDigital Regulatorisk Skanner\n",
|
|
355
|
+
scanning: "Skanner {url}...\n",
|
|
356
|
+
initializing: "Initialiserer skanner...",
|
|
357
|
+
analyzing: "Analyserer DOM & Shadow DOM...",
|
|
358
|
+
complete: "Skanning ferdig!",
|
|
359
|
+
generating_pdf: "Genererer PDF-rapport...",
|
|
360
|
+
pdf_saved: "PDF-rapport lagret i {path}",
|
|
361
|
+
scan_failed: "Skanning mislyktes",
|
|
362
|
+
critical_failure: "\nCI/CD Feil: Kritiske regulatoriske brudd funnet.",
|
|
363
|
+
generating_statement: "Genererer tilgjengelighetserkl\xE6ring...",
|
|
364
|
+
statement_saved: "Tilgjengelighetserkl\xE6ring lagret i {path}",
|
|
365
|
+
score: "\nEtterlevelsespoeng: {score}/100",
|
|
366
|
+
status: "Etterlevelsesstatus: {status}",
|
|
367
|
+
not_compliant: " (Oppfyller ikke lovkrav - Diskriminerings- og tilgjengelighetsloven)",
|
|
368
|
+
viewport: "Visningsomr\xE5de: {width}x{height}",
|
|
369
|
+
prescriptive_fix: "\n\u{1F4A1} Foresl\xE5tt l\xF8sning:",
|
|
370
|
+
use_component: "Bruk komponent: {component}",
|
|
371
|
+
pseudo_tests: "\n\u{1F9EC} Genererer Pseudo-automatiseringstester...\n",
|
|
372
|
+
test_for: "Test for {ruleId}:",
|
|
373
|
+
junit_saved: "JUnit XML-rapport lagret i {path}"
|
|
374
|
+
},
|
|
375
|
+
report: {
|
|
376
|
+
title: "Tilgjengelighetsrapport - {url}",
|
|
377
|
+
generated: "Generert: {date}",
|
|
378
|
+
scan_target: "Skannet m\xE5l: {url}",
|
|
379
|
+
overall_score: "Total Score",
|
|
380
|
+
critical_issues: "Kritiske Feil",
|
|
381
|
+
high_issues: "Alvorlige Feil",
|
|
382
|
+
total_issues: "Totale Feil",
|
|
383
|
+
html_errors: "HTML Feil",
|
|
384
|
+
detailed_violations: "Detaljerte Brudd",
|
|
385
|
+
prescriptive_fix: "\u{1F4A1} Foresl\xE5tt L\xF8sning",
|
|
386
|
+
use: "Bruk",
|
|
387
|
+
footer: "Generert av @holmdigital/engine v0.1.0 \u2022 Standarder: WCAG 2.1 AA, EN 301 549, Uu-tilsynet"
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
243
393
|
// src/locales/nl.json
|
|
244
394
|
var nl_default;
|
|
245
395
|
var init_nl = __esm({
|
|
@@ -255,6 +405,8 @@ var init_nl = __esm({
|
|
|
255
405
|
pdf_saved: "PDF-rapport opgeslagen op {path}",
|
|
256
406
|
scan_failed: "Scan mislukt",
|
|
257
407
|
critical_failure: "\nCI/CD Fout: Kritieke wettelijke overtredingen gevonden.",
|
|
408
|
+
generating_statement: "Toegankelijkheidsverklaring genereren...",
|
|
409
|
+
statement_saved: "Toegankelijkheidsverklaring opgeslagen op {path}",
|
|
258
410
|
score: "\nNalevingsscore: {score}/100",
|
|
259
411
|
status: "Nalevingsstatus: {status}",
|
|
260
412
|
not_compliant: " (Niet in overeenstemming met wettelijke vereisten)",
|
|
@@ -262,7 +414,8 @@ var init_nl = __esm({
|
|
|
262
414
|
prescriptive_fix: "\n\u{1F4A1} Voorgeschreven oplossing:",
|
|
263
415
|
use_component: "Gebruik component: {component}",
|
|
264
416
|
pseudo_tests: "\n\u{1F9EC} Pseudo-automatiseringstests genereren...\n",
|
|
265
|
-
test_for: "Test voor {ruleId}:"
|
|
417
|
+
test_for: "Test voor {ruleId}:",
|
|
418
|
+
junit_saved: "JUnit XML-rapport opgeslagen op {path}"
|
|
266
419
|
},
|
|
267
420
|
report: {
|
|
268
421
|
title: "Toegankelijkheidsrapport - {url}",
|
|
@@ -336,6 +489,9 @@ var init_i18n = __esm({
|
|
|
336
489
|
init_de();
|
|
337
490
|
init_fr();
|
|
338
491
|
init_es();
|
|
492
|
+
init_fi();
|
|
493
|
+
init_dk();
|
|
494
|
+
init_no();
|
|
339
495
|
init_nl();
|
|
340
496
|
locales = {
|
|
341
497
|
en: en_default,
|
|
@@ -344,9 +500,15 @@ var init_i18n = __esm({
|
|
|
344
500
|
fr: fr_default,
|
|
345
501
|
es: es_default,
|
|
346
502
|
nl: nl_default,
|
|
503
|
+
fi: fi_default,
|
|
504
|
+
dk: dk_default,
|
|
505
|
+
no: no_default,
|
|
347
506
|
"en-gb": en_default,
|
|
348
507
|
"en-us": en_default,
|
|
349
|
-
"en-ca": en_default
|
|
508
|
+
"en-ca": en_default,
|
|
509
|
+
"da": dk_default,
|
|
510
|
+
"nb": no_default
|
|
511
|
+
// Norwegian Bokmål alias
|
|
350
512
|
};
|
|
351
513
|
currentLang = "en";
|
|
352
514
|
}
|
|
@@ -358,6 +520,8 @@ __export(index_exports, {
|
|
|
358
520
|
PseudoAutomationEngine: () => PseudoAutomationEngine,
|
|
359
521
|
RegulatoryScanner: () => RegulatoryScanner,
|
|
360
522
|
VirtualDOMBuilder: () => VirtualDOMBuilder,
|
|
523
|
+
generateStatement: () => generateStatement,
|
|
524
|
+
generateStatementContent: () => generateStatementContent,
|
|
361
525
|
getCurrentLang: () => getCurrentLang,
|
|
362
526
|
setLanguage: () => setLanguage,
|
|
363
527
|
t: () => t
|
|
@@ -618,7 +782,7 @@ var RegulatoryScanner = class {
|
|
|
618
782
|
}
|
|
619
783
|
async enrichResults(axeResults) {
|
|
620
784
|
const reports = [];
|
|
621
|
-
const { searchRulesByTags, generateRegulatoryReport } = await import("@holmdigital/standards");
|
|
785
|
+
const { searchRulesByTags, generateRegulatoryReport, getConvergenceRule } = await import("@holmdigital/standards");
|
|
622
786
|
const { getCurrentLang: getCurrentLang2 } = await Promise.resolve().then(() => (init_i18n(), i18n_exports));
|
|
623
787
|
const lang = getCurrentLang2();
|
|
624
788
|
for (const violation of axeResults.violations) {
|
|
@@ -630,6 +794,7 @@ var RegulatoryScanner = class {
|
|
|
630
794
|
}
|
|
631
795
|
}
|
|
632
796
|
if (report) {
|
|
797
|
+
const fullRule = getConvergenceRule(report.ruleId, lang);
|
|
633
798
|
reports.push({
|
|
634
799
|
...report,
|
|
635
800
|
holmdigitalInsight: {
|
|
@@ -637,6 +802,8 @@ var RegulatoryScanner = class {
|
|
|
637
802
|
reasoning: violation.help
|
|
638
803
|
// Använd Axe's hjälptext som specifik anledning
|
|
639
804
|
},
|
|
805
|
+
// Include legal context from the full rule
|
|
806
|
+
legalContext: fullRule?.legalContext,
|
|
640
807
|
// Attach extra debug info for the CLI
|
|
641
808
|
failingNodes: violation.nodes.map((node) => ({
|
|
642
809
|
html: node.html,
|
|
@@ -713,6 +880,18 @@ var RegulatoryScanner = class {
|
|
|
713
880
|
pageTitle,
|
|
714
881
|
pageLanguage
|
|
715
882
|
};
|
|
883
|
+
const reportsWithContext = reports.filter((r) => r.legalContext);
|
|
884
|
+
const legalSummary = {
|
|
885
|
+
wadApplicable: reportsWithContext.filter(
|
|
886
|
+
(r) => r.legalContext?.appliesTo?.includes("WAD")
|
|
887
|
+
).length,
|
|
888
|
+
eaaApplicable: reportsWithContext.filter(
|
|
889
|
+
(r) => r.legalContext?.appliesTo?.includes("EAA")
|
|
890
|
+
).length,
|
|
891
|
+
eaaDeadlineViolations: reportsWithContext.filter(
|
|
892
|
+
(r) => r.legalContext?.eaaDeadline
|
|
893
|
+
).length
|
|
894
|
+
};
|
|
716
895
|
return {
|
|
717
896
|
url: this.options.url,
|
|
718
897
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -720,7 +899,8 @@ var RegulatoryScanner = class {
|
|
|
720
899
|
reports,
|
|
721
900
|
stats,
|
|
722
901
|
score,
|
|
723
|
-
complianceStatus
|
|
902
|
+
complianceStatus,
|
|
903
|
+
legalSummary
|
|
724
904
|
};
|
|
725
905
|
}
|
|
726
906
|
/**
|
|
@@ -804,11 +984,161 @@ test('${testName}', async ({ page }) => {
|
|
|
804
984
|
|
|
805
985
|
// src/index.ts
|
|
806
986
|
init_i18n();
|
|
987
|
+
|
|
988
|
+
// src/reporting/statement-generator.ts
|
|
989
|
+
var import_react = __toESM(require("react"));
|
|
990
|
+
var import_server = require("react-dom/server");
|
|
991
|
+
var import_components = require("@holmdigital/components");
|
|
992
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
993
|
+
var import_path = __toESM(require("path"));
|
|
994
|
+
|
|
995
|
+
// src/reporting/badge-generator.ts
|
|
996
|
+
var BADGE_COLOR = "00703C";
|
|
997
|
+
var BADGE_BASE_URL = "https://img.shields.io/badge/HolmDigital_Engine";
|
|
998
|
+
function generateBadgeUrl(score) {
|
|
999
|
+
if (score !== 100) {
|
|
1000
|
+
return null;
|
|
1001
|
+
}
|
|
1002
|
+
return `${BADGE_BASE_URL}-100%25-${BADGE_COLOR}?style=flat-square`;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// src/reporting/statement-generator.ts
|
|
1006
|
+
async function generateStatementContent(result, lang = "en", format = "html", metadata) {
|
|
1007
|
+
let complianceLevel = "full";
|
|
1008
|
+
if (result.stats.critical > 0 || result.legalSummary && result.legalSummary.eaaDeadlineViolations > 0) {
|
|
1009
|
+
complianceLevel = "non-compliant";
|
|
1010
|
+
} else if (result.score < 100) {
|
|
1011
|
+
complianceLevel = "partial";
|
|
1012
|
+
}
|
|
1013
|
+
const issuesMap = /* @__PURE__ */ new Map();
|
|
1014
|
+
result.reports.forEach((report) => {
|
|
1015
|
+
if (!issuesMap.has(report.ruleId)) {
|
|
1016
|
+
const issueText = `${report.ruleId} (${report.wcagCriteria})`;
|
|
1017
|
+
issuesMap.set(report.ruleId, issueText);
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
const nonComplianceItems = Array.from(issuesMap.values());
|
|
1021
|
+
let country = metadata?.country || "SE";
|
|
1022
|
+
if (!metadata?.country) {
|
|
1023
|
+
if (result.url.endsWith(".no")) country = "NO";
|
|
1024
|
+
if (result.url.endsWith(".dk")) country = "DK";
|
|
1025
|
+
if (result.url.endsWith(".fi")) country = "FI";
|
|
1026
|
+
if (result.url.endsWith(".de")) country = "DE";
|
|
1027
|
+
}
|
|
1028
|
+
const sector = "public";
|
|
1029
|
+
let logoUrl;
|
|
1030
|
+
try {
|
|
1031
|
+
const possiblePaths = [
|
|
1032
|
+
import_path.default.join(process.cwd(), "src/assets/logo.jpg"),
|
|
1033
|
+
// run from package root
|
|
1034
|
+
import_path.default.join(process.cwd(), "packages/engine/src/assets/logo.jpg")
|
|
1035
|
+
// run from monorepo root
|
|
1036
|
+
];
|
|
1037
|
+
for (const p of possiblePaths) {
|
|
1038
|
+
try {
|
|
1039
|
+
const logoBuffer = await import_promises.default.readFile(p);
|
|
1040
|
+
logoUrl = `data:image/jpeg;base64,${logoBuffer.toString("base64")}`;
|
|
1041
|
+
break;
|
|
1042
|
+
} catch (e) {
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
} catch (e) {
|
|
1046
|
+
console.warn("Could not load logo.jpg", e);
|
|
1047
|
+
}
|
|
1048
|
+
const props = {
|
|
1049
|
+
country,
|
|
1050
|
+
sector,
|
|
1051
|
+
organizationName: metadata?.organizationName || new URL(result.url).hostname.replace(/^www\./, ""),
|
|
1052
|
+
websiteUrl: result.url,
|
|
1053
|
+
complianceLevel,
|
|
1054
|
+
lastReviewDate: /* @__PURE__ */ new Date(),
|
|
1055
|
+
assessmentDate: /* @__PURE__ */ new Date(),
|
|
1056
|
+
evaluationMethod: lang === "sv" ? "Automatiserad granskning via @holmdigital/engine" : "Automated Scan via @holmdigital/engine",
|
|
1057
|
+
generatorTool: {
|
|
1058
|
+
name: "HolmDigital Regulatory Engine",
|
|
1059
|
+
url: "https://holmdigital.se"
|
|
1060
|
+
},
|
|
1061
|
+
logoUrl,
|
|
1062
|
+
contactEmail: metadata?.contactEmail || "hej@holmdigital.se",
|
|
1063
|
+
phoneNumber: metadata?.phoneNumber || "070-123 45 67",
|
|
1064
|
+
responseTime: metadata?.responseTime || (lang === "sv" ? "2 dagar" : "2 days"),
|
|
1065
|
+
nonComplianceItems,
|
|
1066
|
+
locale: lang,
|
|
1067
|
+
badgeUrl: generateBadgeUrl(result.score) || void 0,
|
|
1068
|
+
publishDate: metadata?.publishDate ? new Date(metadata.publishDate) : void 0
|
|
1069
|
+
};
|
|
1070
|
+
let content = "";
|
|
1071
|
+
if (format === "html") {
|
|
1072
|
+
const element = import_react.default.createElement(import_components.AccessibilityStatement, props);
|
|
1073
|
+
const markup = (0, import_server.renderToStaticMarkup)(element);
|
|
1074
|
+
content = `<!DOCTYPE html>
|
|
1075
|
+
<html lang="${lang}">
|
|
1076
|
+
<head>
|
|
1077
|
+
<meta charset="UTF-8">
|
|
1078
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1079
|
+
<title>Accessibility Statement - ${props.organizationName}</title>
|
|
1080
|
+
<style>
|
|
1081
|
+
body { font-family: system-ui, -apple-system, sans-serif; background: #f8f9fa; padding: 2rem; margin: 0; }
|
|
1082
|
+
</style>
|
|
1083
|
+
</head>
|
|
1084
|
+
<body>
|
|
1085
|
+
${markup}
|
|
1086
|
+
</body>
|
|
1087
|
+
</html>`;
|
|
1088
|
+
} else {
|
|
1089
|
+
const dateStr = props.lastReviewDate.toISOString().split("T")[0];
|
|
1090
|
+
const statusMap = {
|
|
1091
|
+
"full": "Full",
|
|
1092
|
+
"partial": "Partial",
|
|
1093
|
+
"non-compliant": "Non-Compliant"
|
|
1094
|
+
};
|
|
1095
|
+
content = `# Accessibility Statement for ${props.organizationName}
|
|
1096
|
+
|
|
1097
|
+
This accessibility statement applies to [${props.websiteUrl}](${props.websiteUrl}).
|
|
1098
|
+
|
|
1099
|
+
## Compliance Status
|
|
1100
|
+
|
|
1101
|
+
**Status:** ${statusMap[complianceLevel] || complianceLevel}
|
|
1102
|
+
|
|
1103
|
+
This website is ${complianceLevel} compliant with ${sector === "public" ? "EN 301 549 (WAD)" : "EAA"}.
|
|
1104
|
+
|
|
1105
|
+
## Non-accessible Content
|
|
1106
|
+
|
|
1107
|
+
The following content is non-accessible for the following reasons:
|
|
1108
|
+
|
|
1109
|
+
${nonComplianceItems.length > 0 ? nonComplianceItems.map((item) => `- ${item}`).join("\n") : "_No known issues._"}
|
|
1110
|
+
|
|
1111
|
+
## Preparation of this statement
|
|
1112
|
+
|
|
1113
|
+
This statement was prepared on ${dateStr}.
|
|
1114
|
+
Method used: **Automated Scan** via @holmdigital/engine.
|
|
1115
|
+
|
|
1116
|
+
## Feedback and contact information
|
|
1117
|
+
|
|
1118
|
+
If you need information on this website in a different format like accessible PDF, large print, easy-to-read, audio recording or braille:
|
|
1119
|
+
|
|
1120
|
+
- email: [${props.contactEmail}](mailto:${props.contactEmail})
|
|
1121
|
+
|
|
1122
|
+
## Enforcement procedure
|
|
1123
|
+
|
|
1124
|
+
The enforcement body for ${country} is responsible for enforcing these regulations.
|
|
1125
|
+
`;
|
|
1126
|
+
}
|
|
1127
|
+
return content;
|
|
1128
|
+
}
|
|
1129
|
+
async function generateStatement(result, outputPath, lang = "en", format = "html", metadata) {
|
|
1130
|
+
const content = await generateStatementContent(result, lang, format, metadata);
|
|
1131
|
+
const dir = import_path.default.dirname(outputPath);
|
|
1132
|
+
await import_promises.default.mkdir(dir, { recursive: true });
|
|
1133
|
+
await import_promises.default.writeFile(outputPath, content, "utf-8");
|
|
1134
|
+
}
|
|
807
1135
|
// Annotate the CommonJS export names for ESM import in node:
|
|
808
1136
|
0 && (module.exports = {
|
|
809
1137
|
PseudoAutomationEngine,
|
|
810
1138
|
RegulatoryScanner,
|
|
811
1139
|
VirtualDOMBuilder,
|
|
1140
|
+
generateStatement,
|
|
1141
|
+
generateStatementContent,
|
|
812
1142
|
getCurrentLang,
|
|
813
1143
|
setLanguage,
|
|
814
1144
|
t
|
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PseudoAutomationEngine,
|
|
3
3
|
RegulatoryScanner,
|
|
4
|
-
VirtualDOMBuilder
|
|
5
|
-
|
|
4
|
+
VirtualDOMBuilder,
|
|
5
|
+
generateStatement,
|
|
6
|
+
generateStatementContent
|
|
7
|
+
} from "./chunk-ZO2XNHHT.mjs";
|
|
6
8
|
import {
|
|
7
9
|
getCurrentLang,
|
|
8
10
|
setLanguage,
|
|
9
11
|
t
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-32WU5BD6.mjs";
|
|
11
13
|
export {
|
|
12
14
|
PseudoAutomationEngine,
|
|
13
15
|
RegulatoryScanner,
|
|
14
16
|
VirtualDOMBuilder,
|
|
17
|
+
generateStatement,
|
|
18
|
+
generateStatementContent,
|
|
15
19
|
getCurrentLang,
|
|
16
20
|
setLanguage,
|
|
17
21
|
t
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/reporting/junit-generator.ts
|
|
2
|
+
function generateJUnitXML(reports, url, duration) {
|
|
3
|
+
const failures = reports.length;
|
|
4
|
+
const testSuites = [
|
|
5
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
6
|
+
`<testsuites name="HolmDigital Accessibility Scan" time="${duration / 1e3}">`,
|
|
7
|
+
` <testsuite name="${url}" tests="${failures}" failures="${failures}" errors="0" time="${duration / 1e3}">`
|
|
8
|
+
];
|
|
9
|
+
reports.forEach((report) => {
|
|
10
|
+
const severity = report.holmdigitalInsight.diggRisk;
|
|
11
|
+
const message = escapeXML(report.holmdigitalInsight.reasoning);
|
|
12
|
+
const criteria = escapeXML(`WCAG ${report.wcagCriteria} | EN 301 549 ${report.en301549Criteria}`);
|
|
13
|
+
const help = escapeXML(`Ref: ${report.dosLagenReference}. Remediation: ${report.remediation.component || "Manual"}`);
|
|
14
|
+
testSuites.push(` <testcase name="[${severity.toUpperCase()}] ${report.ruleId}" classname="${report.wcagCriteria}" time="0">`);
|
|
15
|
+
testSuites.push(` <failure message="${message}" type="${severity}">${criteria}
|
|
16
|
+
${help}</failure>`);
|
|
17
|
+
testSuites.push(` </testcase>`);
|
|
18
|
+
});
|
|
19
|
+
testSuites.push(` </testsuite>`);
|
|
20
|
+
testSuites.push(`</testsuites>`);
|
|
21
|
+
return testSuites.join("\n");
|
|
22
|
+
}
|
|
23
|
+
function escapeXML(unsafe) {
|
|
24
|
+
return unsafe.replace(/[<>&'"]/g, (c) => {
|
|
25
|
+
switch (c) {
|
|
26
|
+
case "<":
|
|
27
|
+
return "<";
|
|
28
|
+
case ">":
|
|
29
|
+
return ">";
|
|
30
|
+
case "&":
|
|
31
|
+
return "&";
|
|
32
|
+
case "'":
|
|
33
|
+
return "'";
|
|
34
|
+
case '"':
|
|
35
|
+
return """;
|
|
36
|
+
default:
|
|
37
|
+
return c;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
generateJUnitXML
|
|
43
|
+
};
|