privalint 0.1.1 → 0.2.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/README.de.md +89 -0
- package/README.md +29 -1
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/i18n.d.ts +5 -0
- package/dist/i18n.js +3 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/legal.d.ts +10 -0
- package/dist/legal.js +99 -0
- package/dist/legal.js.map +1 -0
- package/dist/reporters/markdown.js +14 -12
- package/dist/reporters/markdown.js.map +1 -1
- package/dist/reporters/messages.d.ts +21 -0
- package/dist/reporters/messages.js +62 -0
- package/dist/reporters/messages.js.map +1 -0
- package/dist/reporters/sarif.js +7 -1
- package/dist/reporters/sarif.js.map +1 -1
- package/dist/reporters/shared.d.ts +1 -3
- package/dist/reporters/shared.js +0 -17
- package/dist/reporters/shared.js.map +1 -1
- package/dist/reporters/text.js +17 -13
- package/dist/reporters/text.js.map +1 -1
- package/dist/rules/google-fonts.js +26 -9
- package/dist/rules/google-fonts.js.map +1 -1
- package/dist/rules/impressum-link.js +21 -8
- package/dist/rules/impressum-link.js.map +1 -1
- package/dist/rules/links.d.ts +2 -0
- package/dist/rules/links.js +2 -0
- package/dist/rules/links.js.map +1 -1
- package/dist/rules/pre-consent-trackers.js +20 -7
- package/dist/rules/pre-consent-trackers.js.map +1 -1
- package/dist/rules/privacy-policy-link.js +12 -5
- package/dist/rules/privacy-policy-link.js.map +1 -1
- package/dist/rules/reject-option.js +27 -7
- package/dist/rules/reject-option.js.map +1 -1
- package/dist/rules/third-party-cdns.js +10 -3
- package/dist/rules/third-party-cdns.js.map +1 -1
- package/dist/rules/third-party-embeds.js +10 -3
- package/dist/rules/third-party-embeds.js.map +1 -1
- package/dist/rules/tracker-hits.d.ts +4 -2
- package/dist/rules/tracker-hits.js +14 -3
- package/dist/rules/tracker-hits.js.map +1 -1
- package/dist/rules/trackers-after-reject.js +24 -12
- package/dist/rules/trackers-after-reject.js.map +1 -1
- package/dist/scanner.d.ts +6 -0
- package/dist/scanner.js +10 -2
- package/dist/scanner.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/package.json +11 -6
package/README.de.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# privalint
|
|
2
|
+
|
|
3
|
+
**English:** [README.md](README.md)
|
|
4
|
+
|
|
5
|
+
privalint prüft Websites auf die Datenschutzfehler, für die es Abmahnungen gibt: Tracker, die vor
|
|
6
|
+
der Einwilligung laden oder nach „Ablehnen“ weiterlaufen, Google Fonts vom Google-Server,
|
|
7
|
+
eingebundene Inhalte wie YouTube oder Google Maps und ein fehlendes Impressum.
|
|
8
|
+
|
|
9
|
+
privalint öffnet die Seite in einem echten Chromium-Browser ohne Cookies, wie beim ersten Besuch.
|
|
10
|
+
Es zeichnet auf, was geladen wird, bevor jemand das Cookie-Banner bedient, klickt dann auf
|
|
11
|
+
„Ablehnen“ und prüft, was trotzdem noch lädt. Es läuft im Terminal oder als GitHub Action bei
|
|
12
|
+
jedem Pull Request.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx privalint https://ihre-seite.de --lang de
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
> [!IMPORTANT]
|
|
19
|
+
> privalint führt automatisierte Prüfungen durch. Ein sauberes Ergebnis bedeutet, dass keines der
|
|
20
|
+
> geprüften Probleme gefunden wurde. Es macht eine Website nicht DSGVO-konform und ist keine
|
|
21
|
+
> Rechtsberatung.
|
|
22
|
+
|
|
23
|
+
## Deutschland, Österreich, Schweiz
|
|
24
|
+
|
|
25
|
+
Mit `--region` wählen Sie, nach welchem Recht privalint die Befunde einordnet. Jeder Befund nennt
|
|
26
|
+
die Rechtsgrundlage des gewählten Landes.
|
|
27
|
+
|
|
28
|
+
| Region | Cookies und Tracking | Impressum | Besonderheit |
|
|
29
|
+
| --------------- | ----------------------------------------- | ----------------------------------------------- | ----------------------------------------------------- |
|
|
30
|
+
| `de` (Standard) | Opt-in, § 25 TDDDG | § 5 DDG | – |
|
|
31
|
+
| `at` | Opt-in, § 165 Abs. 3 TKG 2021 | § 5 ECG, § 25 MedienG | – |
|
|
32
|
+
| `ch` | Opt-out, Art. 45c FMG | Art. 3 Abs. 1 lit. s UWG (bei Online-Angeboten) | Tracker, Einbindungen und Impressum eine Stufe milder |
|
|
33
|
+
| `eu` | Opt-in, Art. 5 Abs. 3 ePrivacy-Richtlinie | Art. 5 E-Commerce-Richtlinie | – |
|
|
34
|
+
|
|
35
|
+
Tracker, die nach einem ausdrücklichen „Ablehnen“ weiterlaufen, bleiben überall ein Fehler, auch in
|
|
36
|
+
der Schweiz (Art. 30 Abs. 2 lit. b DSG). Richtet sich eine Schweizer Website auch an Besucher aus
|
|
37
|
+
der EU, prüfen Sie sie zusätzlich mit `--region eu`.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx privalint https://ihre-seite.at --region at --lang de --max-pages 20
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Was geprüft wird
|
|
44
|
+
|
|
45
|
+
| Regel | Was sie findet |
|
|
46
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| `pre-consent-trackers` | Analyse-, Werbe- und Session-Replay-Tools, die vor der Einwilligung Anfragen senden oder Cookies setzen |
|
|
48
|
+
| `trackers-after-reject` | Tracker, die nach Klick auf „Ablehnen“ und Neuladen weiterlaufen |
|
|
49
|
+
| `reject-option` | Cookie-Banner mit „Zustimmen“, aber ohne „Ablehnen“ auf der ersten Ebene; Pur-Abo-Modelle als Hinweis |
|
|
50
|
+
| `google-fonts` | Schriften von `fonts.googleapis.com` / `fonts.gstatic.com` |
|
|
51
|
+
| `third-party-embeds` | YouTube, Vimeo, Google Maps, reCAPTCHA, Gravatar und Social-Media-Einbindungen vor der Einwilligung |
|
|
52
|
+
| `third-party-cdns` | Skripte und Styles von jsDelivr, unpkg, cdnjs und anderen öffentlichen CDNs (Hinweis) |
|
|
53
|
+
| `impressum-link` | Seiten ohne Link zum Impressum |
|
|
54
|
+
| `privacy-policy-link` | Seiten ohne Link zur Datenschutzerklärung |
|
|
55
|
+
|
|
56
|
+
Details, Hintergründe und Lösungen stehen auf Englisch in [`docs/rules`](docs/rules).
|
|
57
|
+
|
|
58
|
+
## GitHub Action
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
- uses: jexcellence/privalint@v0
|
|
62
|
+
with:
|
|
63
|
+
url: https://ihre-seite.de
|
|
64
|
+
max-pages: 20
|
|
65
|
+
lang: de
|
|
66
|
+
region: de
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Der Bericht erscheint auf Deutsch in der Zusammenfassung des Workflow-Laufs. Alle Eingaben und
|
|
70
|
+
die Anbindung an GitHub Code Scanning beschreibt die [englische README](README.md#github-action).
|
|
71
|
+
|
|
72
|
+
## Grenzen
|
|
73
|
+
|
|
74
|
+
- Manche Seiten zeigen ihr Cookie-Banner Headless-Browsern nicht. Dann meldet privalint „kein
|
|
75
|
+
Banner gefunden“. Lokal hilft `--headed --channel msedge` (oder `chrome`).
|
|
76
|
+
- Viele Consent-Tools entscheiden anhand der IP-Adresse, ob sie ein Banner zeigen. GitHub-Runner
|
|
77
|
+
haben US-Adressen und sehen deshalb unter Umständen etwas anderes als Besucher aus der EU.
|
|
78
|
+
- Serverseitiges Tracking ist im Browser nicht sichtbar.
|
|
79
|
+
|
|
80
|
+
## Mitmachen
|
|
81
|
+
|
|
82
|
+
Fehlalarme, fehlende Tracker, Consent-Tools und neue Regeln sind sehr willkommen. Gerade
|
|
83
|
+
Anbieter aus dem deutschsprachigen Raum fehlen noch. Der Einstieg steht in
|
|
84
|
+
[CONTRIBUTING.md](CONTRIBUTING.md), passende Aufgaben tragen das Label
|
|
85
|
+
[`good first issue`](https://github.com/jexcellence/privalint/labels/good%20first%20issue).
|
|
86
|
+
|
|
87
|
+
## Lizenz
|
|
88
|
+
|
|
89
|
+
[MIT](LICENSE)
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/privalint)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
+
**Deutsch:** [README.de.md](README.de.md)
|
|
8
|
+
|
|
7
9
|
Lint your website for the GDPR mistakes that get people warning letters: trackers that fire before
|
|
8
10
|
consent or keep running after "reject", Google Fonts loaded from Google, embeds and a missing
|
|
9
11
|
Impressum.
|
|
@@ -84,6 +86,8 @@ preview URL from your hosting provider's deployment event or action output as `u
|
|
|
84
86
|
| `max-pages` | `1` | How many pages of the same site to crawl. |
|
|
85
87
|
| `fail-on` | `error` | `error`, `warning` or `never`. |
|
|
86
88
|
| `disable` | | Comma-separated rule ids to skip. |
|
|
89
|
+
| `lang` | `en` | Language of the report: `en` or `de`. |
|
|
90
|
+
| `region` | `de` | Whose law to cite: `de`, `at`, `ch`, `eu`. |
|
|
87
91
|
| `sarif-file` | `privalint.sarif` | Where to write SARIF. Empty to skip. |
|
|
88
92
|
| `job-summary` | `true` | Add the Markdown report to the job summary. |
|
|
89
93
|
|
|
@@ -113,6 +117,8 @@ privalint <url> [options]
|
|
|
113
117
|
--settle <ms> Wait this long after load for late tags (default 2000)
|
|
114
118
|
--timeout <ms> Navigation timeout per page (default 30000)
|
|
115
119
|
--locale <locale> Browser locale (default de-DE)
|
|
120
|
+
--lang <lang> Language of the report: en | de (default en)
|
|
121
|
+
--region <region> Whose law to cite: de | at | ch | eu (default de)
|
|
116
122
|
--skip-consent Don't click "reject" on the consent banner
|
|
117
123
|
--headed Open a visible browser window instead of running headless
|
|
118
124
|
--channel <name> Use an installed browser: chrome or msedge
|
|
@@ -127,12 +133,34 @@ The first run needs a browser. If Playwright hasn't installed one yet:
|
|
|
127
133
|
npx playwright install chromium
|
|
128
134
|
```
|
|
129
135
|
|
|
136
|
+
## Countries and languages
|
|
137
|
+
|
|
138
|
+
The same finding can be a clear violation in one country and a hint in another. `--region` picks
|
|
139
|
+
whose law privalint cites and how strictly it judges:
|
|
140
|
+
|
|
141
|
+
| Region | Cookies and tracking | Imprint | Changes |
|
|
142
|
+
| -------------- | ------------------------------------ | ------------------------------------- | -------------------------------------------------------------------------------- |
|
|
143
|
+
| `de` (default) | Opt-in, § 25 TDDDG | § 5 DDG | none |
|
|
144
|
+
| `at` | Opt-in, § 165 Abs. 3 TKG 2021 | § 5 ECG, § 25 MedienG | none |
|
|
145
|
+
| `ch` | Opt-out, Art. 45c FMG | Art. 3 Abs. 1 lit. s UWG (e-commerce) | `pre-consent-trackers`, `third-party-embeds` and `impressum-link` drop one level |
|
|
146
|
+
| `eu` | Opt-in, Art. 5(3) ePrivacy Directive | Art. 5 Directive 2000/31/EC | none |
|
|
147
|
+
|
|
148
|
+
Every finding lists its legal basis for the chosen country. Trackers that run after an explicit
|
|
149
|
+
"reject" stay an error everywhere, Switzerland included (Art. 30 Abs. 2 lit. b DSG). If a Swiss
|
|
150
|
+
site also targets visitors in the EU, scan it with `--region eu` as well.
|
|
151
|
+
|
|
152
|
+
`--lang de` writes findings, fixes and the report in German:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npx privalint https://ihre-seite.ch --region ch --lang de
|
|
156
|
+
```
|
|
157
|
+
|
|
130
158
|
## Use it from code
|
|
131
159
|
|
|
132
160
|
```ts
|
|
133
161
|
import { scan } from 'privalint';
|
|
134
162
|
|
|
135
|
-
const result = await scan('https://your-site.de', { maxPages: 10 });
|
|
163
|
+
const result = await scan('https://your-site.de', { maxPages: 10, region: 'at', lang: 'de' });
|
|
136
164
|
for (const finding of result.findings) {
|
|
137
165
|
console.log(finding.severity, finding.ruleId, finding.pageUrl);
|
|
138
166
|
}
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { writeFile } from 'node:fs/promises';
|
|
3
3
|
import { extname } from 'node:path';
|
|
4
4
|
import { parseArgs } from 'node:util';
|
|
5
|
+
import { LANGS } from './i18n.js';
|
|
6
|
+
import { REGIONS } from './legal.js';
|
|
5
7
|
import { VERSION } from './meta.js';
|
|
6
8
|
import { FORMATS, format, formatText } from './reporters/index.js';
|
|
7
9
|
import { defaultRules } from './rules/index.js';
|
|
@@ -29,6 +31,8 @@ Options
|
|
|
29
31
|
--settle <ms> Wait this long after load for late tags (default 2000)
|
|
30
32
|
--timeout <ms> Navigation timeout per page (default 30000)
|
|
31
33
|
--locale <locale> Browser locale (default de-DE)
|
|
34
|
+
--lang <lang> Language of the report: en | de (default en)
|
|
35
|
+
--region <region> Whose law to cite: de | at | ch | eu (default de)
|
|
32
36
|
--skip-consent Don't click "reject" on the consent banner
|
|
33
37
|
--headed Open a visible browser window instead of running headless
|
|
34
38
|
--channel <name> Use an installed browser: chrome or msedge
|
|
@@ -59,6 +63,8 @@ async function main(argv) {
|
|
|
59
63
|
settle: { type: 'string' },
|
|
60
64
|
timeout: { type: 'string' },
|
|
61
65
|
locale: { type: 'string' },
|
|
66
|
+
lang: { type: 'string', default: 'en' },
|
|
67
|
+
region: { type: 'string', default: 'de' },
|
|
62
68
|
'skip-consent': { type: 'boolean' },
|
|
63
69
|
headed: { type: 'boolean' },
|
|
64
70
|
channel: { type: 'string' },
|
|
@@ -91,6 +97,8 @@ async function main(argv) {
|
|
|
91
97
|
settleMs: wholeNumber(values.settle, '--settle', 0),
|
|
92
98
|
timeoutMs: wholeNumber(values.timeout, '--timeout', 1),
|
|
93
99
|
locale: values.locale,
|
|
100
|
+
lang: oneOf(values.lang, LANGS, '--lang'),
|
|
101
|
+
region: oneOf(values.region, REGIONS, '--region'),
|
|
94
102
|
consentCheck: values['skip-consent'] !== true,
|
|
95
103
|
headed: values.headed === true,
|
|
96
104
|
channel: values.channel === undefined ? undefined : oneOf(values.channel, CHANNELS, '--channel'),
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAe,MAAM,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAGpC,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAU,CAAC;AAC3D,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAG/C,MAAM,OAAO,GAAG,CAAC,CAAC;AAClB,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,MAAM,IAAI,GAAG,aAAa,OAAO;;;;;;;;;4BASL,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const LANGS: readonly ['en', 'de'];
|
|
2
|
+
export type Lang = (typeof LANGS)[number];
|
|
3
|
+
/** One string per language. Adding a language makes every missing translation a type error. */
|
|
4
|
+
export type Text = Record<Lang, string>;
|
|
5
|
+
export declare const say: (lang: Lang, text: Text) => string;
|
package/dist/i18n.js
ADDED
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,CAAU,CAAC;AAM3C,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,IAAU,EAAE,IAAU,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { type Tracker, type TrackerCategory, trackers } from './data/trackers.js';
|
|
2
|
+
export { LANGS, type Lang, type Text } from './i18n.js';
|
|
3
|
+
export { legalReferences, REGIONS, type Region } from './legal.js';
|
|
2
4
|
export { defaultRules, googleFonts, impressumLink, preConsentTrackers, privacyPolicyLink, rejectOption, thirdPartyCdns, thirdPartyEmbeds, trackersAfterReject, } from './rules/index.js';
|
|
3
5
|
export { type ScanOptions, scan } from './scanner.js';
|
|
4
6
|
export type * from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { trackers } from './data/trackers.js';
|
|
2
|
+
export { LANGS } from './i18n.js';
|
|
3
|
+
export { legalReferences, REGIONS } from './legal.js';
|
|
2
4
|
export { defaultRules, googleFonts, impressumLink, preConsentTrackers, privacyPolicyLink, rejectOption, thirdPartyCdns, thirdPartyEmbeds, trackersAfterReject, } from './rules/index.js';
|
|
3
5
|
export { scan } from './scanner.js';
|
|
4
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAoB,IAAI,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,KAAK,EAAwB,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,OAAO,EAAe,MAAM,YAAY,CAAC;AACnE,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAoB,IAAI,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/legal.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Finding } from './types.js';
|
|
2
|
+
export declare const REGIONS: readonly ['de', 'at', 'ch', 'eu'];
|
|
3
|
+
export type Region = (typeof REGIONS)[number];
|
|
4
|
+
export declare const legalReferences: (ruleId: string, region: Region) => string[] | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Attaches the legal basis of the chosen country to each finding and adjusts
|
|
7
|
+
* its severity where that country's law is softer or stricter. Findings of
|
|
8
|
+
* custom rules without an entry above are left as they are.
|
|
9
|
+
*/
|
|
10
|
+
export declare function applyRegion(findings: readonly Finding[], region: Region): Finding[];
|
package/dist/legal.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export const REGIONS = ['de', 'at', 'ch', 'eu'];
|
|
2
|
+
/**
|
|
3
|
+
* Legal basis per rule and country, cited the way lawyers in that country
|
|
4
|
+
* would cite it. `eu` is for sites outside Germany, Austria and Switzerland
|
|
5
|
+
* and refers to the EU instruments directly.
|
|
6
|
+
*/
|
|
7
|
+
const LEGAL = {
|
|
8
|
+
'pre-consent-trackers': {
|
|
9
|
+
de: ['§ 25 Abs. 1 TDDDG', 'Art. 6 Abs. 1 lit. a DSGVO', 'EuGH C-673/17 (Planet49)'],
|
|
10
|
+
at: ['§ 165 Abs. 3 TKG 2021', 'Art. 6 Abs. 1 lit. a DSGVO', 'EuGH C-673/17 (Planet49)'],
|
|
11
|
+
ch: ['Art. 45c FMG', 'Art. 6 DSG'],
|
|
12
|
+
eu: ['Art. 5(3) ePrivacy Directive', 'Art. 6(1)(a) GDPR', 'CJEU C-673/17 (Planet49)'],
|
|
13
|
+
},
|
|
14
|
+
'trackers-after-reject': {
|
|
15
|
+
de: ['§ 25 Abs. 1 TDDDG', 'Art. 7 Abs. 3 DSGVO'],
|
|
16
|
+
at: ['§ 165 Abs. 3 TKG 2021', 'Art. 7 Abs. 3 DSGVO'],
|
|
17
|
+
ch: ['Art. 45c FMG', 'Art. 30 Abs. 2 lit. b DSG'],
|
|
18
|
+
eu: ['Art. 5(3) ePrivacy Directive', 'Art. 7(3) GDPR'],
|
|
19
|
+
},
|
|
20
|
+
'reject-option': {
|
|
21
|
+
de: [
|
|
22
|
+
'§ 25 Abs. 1 TDDDG',
|
|
23
|
+
'Art. 4 Nr. 11 DSGVO',
|
|
24
|
+
'EDSA Cookie-Banner-Taskforce, 17.01.2023',
|
|
25
|
+
'DSK-Beschluss, 22.03.2023 (Pur-Abo-Modelle)',
|
|
26
|
+
],
|
|
27
|
+
at: [
|
|
28
|
+
'§ 165 Abs. 3 TKG 2021',
|
|
29
|
+
'Art. 4 Nr. 11 DSGVO',
|
|
30
|
+
'EDSA Cookie-Banner-Taskforce, 17.01.2023',
|
|
31
|
+
],
|
|
32
|
+
ch: ['Art. 45c FMG', 'EDÖB, Leitfaden zu Cookies (2025)'],
|
|
33
|
+
eu: ['Art. 4(11) GDPR', 'Art. 7(3) GDPR', 'EDPB Cookie Banner Taskforce report, 17.01.2023'],
|
|
34
|
+
},
|
|
35
|
+
'google-fonts': {
|
|
36
|
+
de: ['Art. 6 Abs. 1 DSGVO', 'LG München I, 20.01.2022, Az. 3 O 17493/20'],
|
|
37
|
+
at: ['Art. 6 Abs. 1 DSGVO'],
|
|
38
|
+
ch: ['Art. 6 DSG'],
|
|
39
|
+
eu: ['Art. 6(1) GDPR'],
|
|
40
|
+
},
|
|
41
|
+
'third-party-embeds': {
|
|
42
|
+
de: ['Art. 6 Abs. 1 DSGVO', '§ 25 Abs. 1 TDDDG'],
|
|
43
|
+
at: ['Art. 6 Abs. 1 DSGVO', '§ 165 Abs. 3 TKG 2021'],
|
|
44
|
+
ch: ['Art. 6 DSG', 'Art. 45c FMG'],
|
|
45
|
+
eu: ['Art. 6(1) GDPR', 'Art. 5(3) ePrivacy Directive'],
|
|
46
|
+
},
|
|
47
|
+
'third-party-cdns': {
|
|
48
|
+
de: ['Art. 6 Abs. 1 DSGVO'],
|
|
49
|
+
at: ['Art. 6 Abs. 1 DSGVO'],
|
|
50
|
+
ch: ['Art. 6 DSG'],
|
|
51
|
+
eu: ['Art. 6(1) GDPR'],
|
|
52
|
+
},
|
|
53
|
+
'impressum-link': {
|
|
54
|
+
de: ['§ 5 DDG', 'BGH, 20.07.2006, Az. I ZR 228/03'],
|
|
55
|
+
at: ['§ 5 ECG', '§ 25 MedienG'],
|
|
56
|
+
ch: ['Art. 3 Abs. 1 lit. s UWG'],
|
|
57
|
+
eu: ['Art. 5 Directive 2000/31/EC (e-commerce)'],
|
|
58
|
+
},
|
|
59
|
+
'privacy-policy-link': {
|
|
60
|
+
de: ['Art. 12 DSGVO', 'Art. 13 DSGVO'],
|
|
61
|
+
at: ['Art. 12 DSGVO', 'Art. 13 DSGVO'],
|
|
62
|
+
ch: ['Art. 19 DSG'],
|
|
63
|
+
eu: ['Art. 12 GDPR', 'Art. 13 GDPR'],
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
export const legalReferences = (ruleId, region) => LEGAL[ruleId]?.[region];
|
|
67
|
+
/**
|
|
68
|
+
* Attaches the legal basis of the chosen country to each finding and adjusts
|
|
69
|
+
* its severity where that country's law is softer or stricter. Findings of
|
|
70
|
+
* custom rules without an entry above are left as they are.
|
|
71
|
+
*/
|
|
72
|
+
export function applyRegion(findings, region) {
|
|
73
|
+
return findings.map((finding) => {
|
|
74
|
+
const references = legalReferences(finding.ruleId, region);
|
|
75
|
+
return {
|
|
76
|
+
...finding,
|
|
77
|
+
severity: severityFor(finding, region),
|
|
78
|
+
...(references === undefined ? {} : { references }),
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Switzerland uses an opt-out model for cookies and tracking (Art. 45c FMG) and
|
|
84
|
+
* requires an imprint only for offers in electronic commerce, so those findings
|
|
85
|
+
* drop one level there. Ignoring an explicit refusal stays as serious as anywhere.
|
|
86
|
+
*/
|
|
87
|
+
const SOFTER_IN_SWITZERLAND = new Set([
|
|
88
|
+
'pre-consent-trackers',
|
|
89
|
+
'third-party-embeds',
|
|
90
|
+
'impressum-link',
|
|
91
|
+
]);
|
|
92
|
+
function severityFor(finding, region) {
|
|
93
|
+
if (region === 'ch' && SOFTER_IN_SWITZERLAND.has(finding.ruleId)) {
|
|
94
|
+
return lower(finding.severity);
|
|
95
|
+
}
|
|
96
|
+
return finding.severity;
|
|
97
|
+
}
|
|
98
|
+
const lower = (severity) => (severity === 'error' ? 'warning' : 'info');
|
|
99
|
+
//# sourceMappingURL=legal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legal.js","sourceRoot":"","sources":["../src/legal.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { messagesFor } from './messages.js';
|
|
2
|
+
import { countBySeverity, groupByPage } from './shared.js';
|
|
2
3
|
const ICONS = { error: '🔴', warning: '🟡', info: '🔵' };
|
|
3
4
|
/**
|
|
4
5
|
* Compact report for GitHub job summaries and PR comments.
|
|
@@ -8,38 +9,39 @@ const ICONS = { error: '🔴', warning: '🟡', info: '🔵' };
|
|
|
8
9
|
* rendered inside code spans.
|
|
9
10
|
*/
|
|
10
11
|
export function formatMarkdown(result) {
|
|
12
|
+
const m = messagesFor(result.lang);
|
|
11
13
|
const counts = countBySeverity(result.findings);
|
|
12
14
|
const lines = [
|
|
13
15
|
`### privalint: ${code(result.siteUrl)}`,
|
|
14
16
|
'',
|
|
15
|
-
`${
|
|
17
|
+
`${m.errors(counts.error)} · ${m.warnings(counts.warning)} · ${m.scanned(m.pages(result.pages.length))}`,
|
|
16
18
|
];
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
lines.push('', escapeText(consent));
|
|
19
|
+
if (result.consent !== undefined) {
|
|
20
|
+
lines.push('', escapeText(m.consent(result.consent)));
|
|
20
21
|
}
|
|
21
22
|
for (const [pageUrl, findings] of groupByPage(result.findings)) {
|
|
22
|
-
lines.push('', `#### ${code(pageUrl)}`, '',
|
|
23
|
+
lines.push('', `#### ${code(pageUrl)}`, '', `| | ${m.rule} | ${m.finding} |`, '|---|---|---|');
|
|
23
24
|
for (const finding of findings) {
|
|
24
25
|
lines.push(`| ${ICONS[finding.severity]} | \`${finding.ruleId}\` | ${escapeText(finding.message)} |`);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
const failed = result.pages.filter((page) => page.error !== undefined);
|
|
28
29
|
if (failed.length > 0) {
|
|
29
|
-
lines.push('',
|
|
30
|
+
lines.push('', m.couldNotScan(failed.length), '');
|
|
30
31
|
for (const page of failed) {
|
|
31
32
|
lines.push(`- ${code(page.url)}: ${escapeText(page.error ?? '')}`);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
const fixes = new Map(result.findings.filter((f) => f.fix !== undefined).map((f) => [f.ruleId, f
|
|
35
|
+
const fixes = new Map(result.findings.filter((f) => f.fix !== undefined).map((f) => [f.ruleId, f]));
|
|
35
36
|
if (fixes.size > 0) {
|
|
36
|
-
lines.push('',
|
|
37
|
-
for (const [ruleId, fix] of fixes) {
|
|
38
|
-
|
|
37
|
+
lines.push('', `<details><summary>${m.howToFix}</summary>`, '');
|
|
38
|
+
for (const [ruleId, { fix, references }] of fixes) {
|
|
39
|
+
const legal = references?.length ? ` (${m.legalBasis} ${references.join('; ')})` : '';
|
|
40
|
+
lines.push(`- **${ruleId}**: ${escapeText(`${fix ?? ''}${legal}`)}`);
|
|
39
41
|
}
|
|
40
42
|
lines.push('', '</details>');
|
|
41
43
|
}
|
|
42
|
-
lines.push('',
|
|
44
|
+
lines.push('', `<sub>${m.disclaimer}</sub>`);
|
|
43
45
|
return `${lines.join('\n')}\n`;
|
|
44
46
|
}
|
|
45
47
|
const code = (text) => `\`${text.replaceAll('`', '%60').replaceAll('\n', ' ')}\``;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/reporters/markdown.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/reporters/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Lang } from '../i18n.js';
|
|
2
|
+
import type { ConsentSummary } from '../types.js';
|
|
3
|
+
/** Fixed wording of the text and Markdown reports. */
|
|
4
|
+
export interface ReportMessages {
|
|
5
|
+
errors(count: number): string;
|
|
6
|
+
warnings(count: number): string;
|
|
7
|
+
pages(count: number): string;
|
|
8
|
+
duration(ms: number): string;
|
|
9
|
+
noProblems(pages: string, duration: string): string;
|
|
10
|
+
on: string;
|
|
11
|
+
scanned(pages: string): string;
|
|
12
|
+
couldNotScan(count: number): string;
|
|
13
|
+
fix: string;
|
|
14
|
+
legalBasis: string;
|
|
15
|
+
rule: string;
|
|
16
|
+
finding: string;
|
|
17
|
+
howToFix: string;
|
|
18
|
+
disclaimer: string;
|
|
19
|
+
consent(consent: ConsentSummary): string;
|
|
20
|
+
}
|
|
21
|
+
export declare const messagesFor: (lang: Lang) => ReportMessages;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const count = (n, one, many) => `${n} ${n === 1 ? one : many}`;
|
|
2
|
+
const en = {
|
|
3
|
+
errors: (n) => count(n, 'error', 'errors'),
|
|
4
|
+
warnings: (n) => count(n, 'warning', 'warnings'),
|
|
5
|
+
pages: (n) => count(n, 'page', 'pages'),
|
|
6
|
+
duration: (ms) => `${(ms / 1000).toFixed(1)}s`,
|
|
7
|
+
noProblems: (pages, duration) => `No problems found on ${pages} (${duration}).`,
|
|
8
|
+
on: 'on',
|
|
9
|
+
scanned: (pages) => `${pages} scanned`,
|
|
10
|
+
couldNotScan: (n) => `Could not scan ${count(n, 'page', 'pages')}:`,
|
|
11
|
+
fix: 'fix:',
|
|
12
|
+
legalBasis: 'legal basis:',
|
|
13
|
+
rule: 'Rule',
|
|
14
|
+
finding: 'Finding',
|
|
15
|
+
howToFix: 'How to fix',
|
|
16
|
+
disclaimer: 'Automated checks only. A clean result is not proof of GDPR compliance.',
|
|
17
|
+
consent(consent) {
|
|
18
|
+
if (!consent.bannerFound) {
|
|
19
|
+
return 'Consent banner: none found';
|
|
20
|
+
}
|
|
21
|
+
const vendor = consent.cmp === undefined ? '' : ` (${consent.cmp})`;
|
|
22
|
+
if (consent.error !== undefined) {
|
|
23
|
+
return `Consent banner${vendor}: found, but rejecting failed: ${consent.error}`;
|
|
24
|
+
}
|
|
25
|
+
if (consent.rejected) {
|
|
26
|
+
return `Consent banner${vendor}: clicked "${consent.rejectLabel}" and reloaded`;
|
|
27
|
+
}
|
|
28
|
+
return `Consent banner${vendor}: found, no reject button`;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const de = {
|
|
32
|
+
errors: (n) => count(n, 'Fehler', 'Fehler'),
|
|
33
|
+
warnings: (n) => count(n, 'Warnung', 'Warnungen'),
|
|
34
|
+
pages: (n) => count(n, 'Seite', 'Seiten'),
|
|
35
|
+
duration: (ms) => `${(ms / 1000).toFixed(1).replace('.', ',')} s`,
|
|
36
|
+
noProblems: (pages, duration) => `Keine Probleme auf ${pages} gefunden (${duration}).`,
|
|
37
|
+
on: 'auf',
|
|
38
|
+
scanned: (pages) => `${pages} geprüft`,
|
|
39
|
+
couldNotScan: (n) => `${count(n, 'Seite', 'Seiten')} ${n === 1 ? 'konnte' : 'konnten'} nicht geprüft werden:`,
|
|
40
|
+
fix: 'Lösung:',
|
|
41
|
+
legalBasis: 'Rechtsgrundlage:',
|
|
42
|
+
rule: 'Regel',
|
|
43
|
+
finding: 'Befund',
|
|
44
|
+
howToFix: 'So beheben Sie es',
|
|
45
|
+
disclaimer: 'Nur automatisierte Prüfungen. Ein sauberes Ergebnis ist kein Nachweis der DSGVO-Konformität.',
|
|
46
|
+
consent(consent) {
|
|
47
|
+
if (!consent.bannerFound) {
|
|
48
|
+
return 'Cookie-Banner: keines gefunden';
|
|
49
|
+
}
|
|
50
|
+
const vendor = consent.cmp === undefined ? '' : ` (${consent.cmp})`;
|
|
51
|
+
if (consent.error !== undefined) {
|
|
52
|
+
return `Cookie-Banner${vendor}: gefunden, aber Ablehnen ist fehlgeschlagen: ${consent.error}`;
|
|
53
|
+
}
|
|
54
|
+
if (consent.rejected) {
|
|
55
|
+
return `Cookie-Banner${vendor}: „${consent.rejectLabel}“ geklickt und neu geladen`;
|
|
56
|
+
}
|
|
57
|
+
return `Cookie-Banner${vendor}: gefunden, kein Ablehnen-Button`;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
const MESSAGES = { en, de };
|
|
61
|
+
export const messagesFor = (lang) => MESSAGES[lang];
|
|
62
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/reporters/messages.ts"],"names":[],"mappings":"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"}
|
package/dist/reporters/sarif.js
CHANGED
|
@@ -50,7 +50,13 @@ function toResult(finding) {
|
|
|
50
50
|
ruleId: finding.ruleId,
|
|
51
51
|
level: LEVELS[finding.severity],
|
|
52
52
|
message: {
|
|
53
|
-
text: [
|
|
53
|
+
text: [
|
|
54
|
+
finding.message,
|
|
55
|
+
`Page: ${finding.pageUrl}`,
|
|
56
|
+
evidence,
|
|
57
|
+
finding.fix,
|
|
58
|
+
finding.references?.join('; '),
|
|
59
|
+
]
|
|
54
60
|
.filter(Boolean)
|
|
55
61
|
.join('\n\n'),
|
|
56
62
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGlE,MAAM,MAAM,GAAmD;IAC7D,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,MAAM,KAAK,GAAG;QACZ,OAAO,EAAE,+CAA+C;QACxD,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,WAAW;wBACjB,eAAe,EAAE,OAAO;wBACxB,cAAc,EAAE,cAAc;wBAC9B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;4BACjC,EAAE,EAAE,IAAI,CAAC,EAAE;4BACX,IAAI,EAAE,IAAI,CAAC,EAAE;4BACb,gBAAgB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;4BACtC,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE;4BAC3C,IAAI,EAAE;gCACJ,IAAI,EAAE,GAAG,IAAI,CAAC,WAAW,mBAAmB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gCACxE,QAAQ,EAAE,GAAG,IAAI,CAAC,WAAW,uBAAuB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;6BACjF;4BACD,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;4BAC7B,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE;yBAC7D,CAAC,CAAC;qBACJ;iBACF;gBACD,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;aACvC;SACF;KACF,CAAC;IACF,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED,SAAS,QAAQ,CAAC,OAAgB;IAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC/B,OAAO,EAAE;YACP,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Finding, Severity } from '../types.js';
|
|
2
2
|
export declare function groupByPage(findings: readonly Finding[]): Map<string, Finding[]>;
|
|
3
3
|
export declare function countBySeverity(findings: readonly Finding[]): Record<Severity, number>;
|
|
4
|
-
export declare function describeConsent(consent: ConsentSummary | undefined): string | undefined;
|
|
5
|
-
export declare const plural: (count: number, word: string) => string;
|
package/dist/reporters/shared.js
CHANGED
|
@@ -14,21 +14,4 @@ export function countBySeverity(findings) {
|
|
|
14
14
|
}
|
|
15
15
|
return counts;
|
|
16
16
|
}
|
|
17
|
-
export function describeConsent(consent) {
|
|
18
|
-
if (consent === undefined) {
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
if (!consent.bannerFound) {
|
|
22
|
-
return 'Consent banner: none found';
|
|
23
|
-
}
|
|
24
|
-
const vendor = consent.cmp === undefined ? '' : ` (${consent.cmp})`;
|
|
25
|
-
if (consent.error !== undefined) {
|
|
26
|
-
return `Consent banner${vendor}: found, but rejecting failed: ${consent.error}`;
|
|
27
|
-
}
|
|
28
|
-
if (consent.rejected) {
|
|
29
|
-
return `Consent banner${vendor}: clicked "${consent.rejectLabel}" and reloaded`;
|
|
30
|
-
}
|
|
31
|
-
return `Consent banner${vendor}: found, no reject button`;
|
|
32
|
-
}
|
|
33
|
-
export const plural = (count, word) => `${count} ${word}${count === 1 ? '' : 's'}`;
|
|
34
17
|
//# sourceMappingURL=shared.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/reporters/shared.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,QAA4B;IACtD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC3C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnB,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAA4B;IAC1D,MAAM,MAAM,GAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAC3E,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/reporters/shared.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,QAA4B;IACtD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC3C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnB,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAA4B;IAC1D,MAAM,MAAM,GAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAC3E,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|