conformly 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Conformly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # conformly
2
+
3
+ [![npm version](https://img.shields.io/npm/v/conformly.svg)](https://www.npmjs.com/package/conformly)
4
+ [![license](https://img.shields.io/npm/l/conformly.svg)](./LICENSE)
5
+ [![node](https://img.shields.io/node/v/conformly.svg)](https://nodejs.org)
6
+
7
+ Free **RGAA / WCAG** web accessibility scanner for your **CLI & CI** — check any URL in one
8
+ command, no account required. Powered by the public [Conformly](https://conformly.online)
9
+ free-scan API (real-browser render, so React/Vue/Angular apps are analysed properly).
10
+
11
+ > Scanner d'accessibilité **RGAA / WCAG** en ligne de commande & CI, sans compte.
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ npx conformly scan https://your-site.com
17
+ # → Score RGAA : 96 % · 1 anomalie(s)
18
+ ```
19
+
20
+ ```bash
21
+ # Fail the build (exit 1) below a score threshold
22
+ npx conformly scan https://your-site.com --threshold 90
23
+
24
+ # Raw JSON output
25
+ npx conformly scan https://your-site.com --json
26
+ ```
27
+
28
+ ### In CI (GitHub Actions)
29
+
30
+ ```yaml
31
+ - name: Accessibility check
32
+ run: npx conformly scan https://your-site.com --threshold 90
33
+ ```
34
+
35
+ Exit code `1` when the score is below the threshold → your pipeline fails, just like a
36
+ broken test. Works the same in GitLab CI, CircleCI, etc.
37
+
38
+ ## Options
39
+
40
+ | Option | Effet |
41
+ |---|---|
42
+ | `--threshold N` | Sort en erreur (exit 1) si le score est sous `N` (0–100). |
43
+ | `--json` | Sortie JSON brute (`{ url, score, anomalies, threshold }`). |
44
+
45
+ ## Configuration
46
+
47
+ | Variable | Défaut | Rôle |
48
+ |---|---|---|
49
+ | `CONFORMLY_URL` | `https://conformly.online` | Base de l'API. |
50
+
51
+ ## What it checks — and what it doesn't
52
+
53
+ The scan combines **axe-core** with **expert tests** (page language, title, skip link,
54
+ visible focus, 200% zoom…) and maps findings to RGAA criteria.
55
+
56
+ **Honest scope:** automated testing only covers **part** of WCAG/RGAA. A full accessibility
57
+ declaration still requires human review of the non-automatable criteria. Treat the score as
58
+ a fast, reliable signal and a between-audits safety net — **not** a certification.
59
+
60
+ ## Continuous monitoring
61
+
62
+ A CI check is a floor. For drift over time — regression alerts on every deploy, per-page
63
+ history, timestamped evidence, per-framework fix guides — create a free account at
64
+ **[conformly.online](https://conformly.online)**.
65
+
66
+ ## License
67
+
68
+ [MIT](./LICENSE) — © Conformly · [conformly.online](https://conformly.online)
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ // Epic 15.4 — CLI de scan d'accessibilité RGAA. Utilise l'API publique du scan gratuit
3
+ // de Conformly (aucun token requis). Idéal en CI : `--threshold` fait échouer le build
4
+ // sous le score visé.
5
+ //
6
+ // Usage :
7
+ // npx conformly scan <url> [--threshold <0-100>] [--json]
8
+ //
9
+ // Variables : CONFORMLY_URL (défaut https://conformly.online).
10
+
11
+ const API = (process.env.CONFORMLY_URL || "https://conformly.online").replace(/\/$/, "");
12
+ const POLL_MS = 2500;
13
+ const MAX_POLLS = 60;
14
+
15
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
16
+
17
+ function usage(code) {
18
+ console.error(
19
+ [
20
+ "conformly — scan d'accessibilité RGAA",
21
+ "",
22
+ "Usage :",
23
+ " conformly scan <url> [--threshold <0-100>] [--json]",
24
+ "",
25
+ "Options :",
26
+ " --threshold N Échoue (exit 1) si le score est sous N.",
27
+ " --json Sortie JSON brute.",
28
+ ].join("\n"),
29
+ );
30
+ process.exit(code);
31
+ }
32
+
33
+ function parseArgs(argv) {
34
+ if (argv[0] !== "scan" || !argv[1] || argv[1].startsWith("-")) usage(2);
35
+ const url = argv[1];
36
+ let threshold = null;
37
+ let json = false;
38
+ for (let i = 2; i < argv.length; i++) {
39
+ if (argv[i] === "--threshold") threshold = Number(argv[++i]);
40
+ else if (argv[i] === "--json") json = true;
41
+ else usage(2);
42
+ }
43
+ if (threshold !== null && (Number.isNaN(threshold) || threshold < 0 || threshold > 100)) usage(2);
44
+ return { url, threshold, json };
45
+ }
46
+
47
+ function anomalyCount(violations) {
48
+ if (!Array.isArray(violations)) return 0;
49
+ let n = 0;
50
+ for (const v of violations) {
51
+ if (!v || typeof v.ruleId !== "string") continue;
52
+ n += Array.isArray(v.nodes) ? v.nodes.length : 1;
53
+ }
54
+ return n;
55
+ }
56
+
57
+ async function main() {
58
+ const { url, threshold, json } = parseArgs(process.argv.slice(2));
59
+
60
+ let started;
61
+ try {
62
+ const res = await fetch(`${API}/api/free-scan`, {
63
+ method: "POST",
64
+ headers: { "content-type": "application/json" },
65
+ body: JSON.stringify({ url }),
66
+ });
67
+ started = await res.json();
68
+ if (!res.ok || !started.id) {
69
+ console.error(`Erreur : ${started.error || res.status}`);
70
+ process.exit(1);
71
+ }
72
+ } catch (err) {
73
+ console.error(`Erreur réseau : ${err.message}`);
74
+ process.exit(1);
75
+ }
76
+
77
+ if (!json) process.stderr.write(`Scan de ${url} en cours…\n`);
78
+
79
+ let result = null;
80
+ for (let i = 0; i < MAX_POLLS; i++) {
81
+ await sleep(POLL_MS);
82
+ try {
83
+ const r = await fetch(`${API}/api/free-scan/${started.id}`);
84
+ const data = await r.json();
85
+ if (data.status === "done" || data.status === "error") {
86
+ result = data;
87
+ break;
88
+ }
89
+ } catch {
90
+ /* on retente */
91
+ }
92
+ }
93
+
94
+ if (!result) {
95
+ console.error("Délai dépassé.");
96
+ process.exit(1);
97
+ }
98
+ if (result.status === "error") {
99
+ console.error(`Analyse impossible : ${result.errorReason || "erreur inconnue"}`);
100
+ process.exit(1);
101
+ }
102
+
103
+ const score = result.score != null ? Math.round(result.score) : null;
104
+ const anomalies = anomalyCount(result.violations);
105
+
106
+ if (json) {
107
+ console.log(JSON.stringify({ url, score, anomalies, threshold }, null, 2));
108
+ } else {
109
+ console.log(`Score RGAA : ${score != null ? score + " %" : "—"} · ${anomalies} anomalie(s)`);
110
+ }
111
+
112
+ if (threshold !== null && score != null && score < threshold) {
113
+ console.error(`Score ${score}% sous le seuil ${threshold}%.`);
114
+ process.exit(1);
115
+ }
116
+ process.exit(0);
117
+ }
118
+
119
+ main();
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "conformly",
3
+ "version": "0.1.0",
4
+ "description": "CLI de scan d'accessibilité RGAA/WCAG — vérifiez une URL en ligne de commande, idéal en CI. Sans compte.",
5
+ "type": "module",
6
+ "bin": {
7
+ "conformly": "bin/conformly.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "keywords": [
18
+ "accessibility",
19
+ "accessibilité",
20
+ "rgaa",
21
+ "wcag",
22
+ "a11y",
23
+ "audit",
24
+ "ci",
25
+ "cli",
26
+ "conformly"
27
+ ],
28
+ "homepage": "https://conformly.online",
29
+ "bugs": {
30
+ "url": "https://conformly.online"
31
+ },
32
+ "author": "Conformly (https://conformly.online)",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/SeifBouarada/conformly-cli.git"
37
+ }
38
+ }