eaa-kit 0.1.0 → 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.
@@ -0,0 +1,192 @@
1
+ //#region src/schema.ts
2
+ function safeParse(schema, value) {
3
+ const issues = [];
4
+ const data = schema.read(value, [], issues);
5
+ if (issues.length > 0) return {
6
+ success: false,
7
+ error: { issues }
8
+ };
9
+ return {
10
+ success: true,
11
+ data
12
+ };
13
+ }
14
+ function fail(issues, path, message) {
15
+ issues.push({
16
+ path,
17
+ message
18
+ });
19
+ }
20
+ /** Marks a schema as allowed to be absent. */
21
+ function optional(inner) {
22
+ return {
23
+ isOptional: true,
24
+ read: (value, path, issues) => value === void 0 ? void 0 : inner.read(value, path, issues)
25
+ };
26
+ }
27
+ /** Supplies a value when the field is absent. Never when it is present and wrong. */
28
+ function withDefault(inner, fallback) {
29
+ return {
30
+ isOptional: true,
31
+ fallback,
32
+ read: (value, path, issues) => value === void 0 ? fallback() : inner.read(value, path, issues)
33
+ };
34
+ }
35
+ /** Reads with `inner`, then reshapes what came back. */
36
+ function transform(inner, map) {
37
+ return { read: (value, path, issues) => {
38
+ const before = issues.length;
39
+ const parsed = inner.read(value, path, issues);
40
+ return issues.length === before ? map(parsed) : void 0;
41
+ } };
42
+ }
43
+ /**
44
+ * Reads with `first`, then reads that result with `second`.
45
+ *
46
+ * Lets a shorthand form be widened into the full one and validated by the same
47
+ * schema, so both branches of a union produce one type rather than a union the
48
+ * callers have to narrow.
49
+ */
50
+ function pipe(first, second) {
51
+ return { read: (value, path, issues) => {
52
+ const before = issues.length;
53
+ const parsed = first.read(value, path, issues);
54
+ return issues.length === before ? second.read(parsed, path, issues) : void 0;
55
+ } };
56
+ }
57
+ function nullable(inner) {
58
+ return { read: (value, path, issues) => value === null ? null : inner.read(value, path, issues) };
59
+ }
60
+ function string(options = {}) {
61
+ return { read: (value, path, issues) => {
62
+ if (typeof value !== "string") return fail(issues, path, "expected a string");
63
+ if (options.min !== void 0 && value.length < options.min) return fail(issues, path, options.min === 1 ? "must not be empty" : `must be at least ${options.min} characters`);
64
+ return value;
65
+ } };
66
+ }
67
+ function number() {
68
+ return { read: (value, path, issues) => typeof value === "number" && Number.isFinite(value) ? value : fail(issues, path, "expected a number") };
69
+ }
70
+ /** One of a fixed set. The message lists them, since that is the useful part. */
71
+ function enumeration(values) {
72
+ return { read: (value, path, issues) => typeof value === "string" && values.includes(value) ? value : fail(issues, path, `expected one of ${values.join(", ")}`) };
73
+ }
74
+ function array(item) {
75
+ return { read: (value, path, issues) => {
76
+ if (!Array.isArray(value)) return fail(issues, path, "expected an array");
77
+ const out = [];
78
+ for (const [index, element] of value.entries()) {
79
+ const before = issues.length;
80
+ const parsed = item.read(element, [...path, index], issues);
81
+ if (issues.length === before) out.push(parsed);
82
+ }
83
+ return out;
84
+ } };
85
+ }
86
+ /**
87
+ * An object with a known shape. Unknown keys are dropped rather than carried
88
+ * along, which is what keeps a config file from smuggling fields the templates
89
+ * never asked for into a legal document.
90
+ */
91
+ function object(shape) {
92
+ return { read: (value, path, issues) => {
93
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return fail(issues, path, "expected an object");
94
+ const source = value;
95
+ const out = {};
96
+ for (const [key, schema] of Object.entries(shape)) {
97
+ const present = Object.hasOwn(source, key);
98
+ const raw = present ? source[key] : void 0;
99
+ if (!present && schema.isOptional !== true) {
100
+ fail(issues, [...path, key], "is required");
101
+ continue;
102
+ }
103
+ const before = issues.length;
104
+ const parsed = schema.read(raw, [...path, key], issues);
105
+ if (issues.length === before && parsed !== void 0) out[key] = parsed;
106
+ }
107
+ return out;
108
+ } };
109
+ }
110
+ /** An object of unknown keys, all values sharing one shape. */
111
+ function record(value) {
112
+ return { read: (input, path, issues) => {
113
+ if (typeof input !== "object" || input === null || Array.isArray(input)) return fail(issues, path, "expected an object");
114
+ const out = {};
115
+ for (const [key, raw] of Object.entries(input)) {
116
+ const before = issues.length;
117
+ const parsed = value.read(raw, [...path, key], issues);
118
+ if (issues.length === before) out[key] = parsed;
119
+ }
120
+ return out;
121
+ } };
122
+ }
123
+ /**
124
+ * The first alternative that accepts the value.
125
+ *
126
+ * Reports only the last failure rather than every branch's: a union of a string
127
+ * and an object that was given a number produces two complaints about one
128
+ * field, and the reader has to work out which one they were supposed to satisfy.
129
+ */
130
+ function union(alternatives, message) {
131
+ return { read: (value, path, issues) => {
132
+ for (const alternative of alternatives) {
133
+ const attempt = [];
134
+ const parsed = alternative.read(value, path, attempt);
135
+ if (attempt.length === 0) return parsed;
136
+ }
137
+ return fail(issues, path, message);
138
+ } };
139
+ }
140
+ /**
141
+ * A calendar date, `YYYY-MM-DD`.
142
+ *
143
+ * The shape and the date are both checked: `2026-13-45` matches the pattern and
144
+ * is not a day, and a statement carrying it would print something nonsensical
145
+ * or throw out of the formatter.
146
+ */
147
+ function isoDate() {
148
+ return { read: (value, path, issues) => {
149
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return fail(issues, path, "expected a date as YYYY-MM-DD");
150
+ const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
151
+ if (Number.isNaN(parsed.getTime()) || !parsed.toISOString().startsWith(value)) return fail(issues, path, `${value} is not a real date`);
152
+ return value;
153
+ } };
154
+ }
155
+ /** An ISO 8601 timestamp, as `new Date().toISOString()` writes one. */
156
+ function isoDateTime() {
157
+ return { read: (value, path, issues) => {
158
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value)) return fail(issues, path, "expected an ISO 8601 timestamp");
159
+ if (Number.isNaN(new Date(value).getTime())) return fail(issues, path, `${value} is not a real timestamp`);
160
+ return value;
161
+ } };
162
+ }
163
+ /** An absolute http or https URL. A statement links to it, so it has to work. */
164
+ function url() {
165
+ return { read: (value, path, issues) => {
166
+ if (typeof value !== "string") return fail(issues, path, "expected a URL");
167
+ let parsed;
168
+ try {
169
+ parsed = new URL(value);
170
+ } catch {
171
+ return fail(issues, path, "expected a URL, including https://");
172
+ }
173
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return fail(issues, path, "expected an http or https URL");
174
+ return value;
175
+ } };
176
+ }
177
+ /**
178
+ * An email address.
179
+ *
180
+ * Deliberately loose. The only address that is definitely deliverable is one
181
+ * that has been delivered to, and a stricter pattern would reject valid
182
+ * addresses — which, for the one field the EAA requires a provider to publish,
183
+ * is the worse failure.
184
+ */
185
+ function email() {
186
+ return { read: (value, path, issues) => {
187
+ if (typeof value !== "string" || !/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/.test(value)) return fail(issues, path, "expected an email address");
188
+ return value;
189
+ } };
190
+ }
191
+ //#endregion
192
+ export { withDefault as _, isoDateTime as a, object as c, record as d, safeParse as f, url as g, union as h, isoDate as i, optional as l, transform as m, email as n, nullable as o, string as p, enumeration as r, number as s, array as t, pipe as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eaa-kit",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Build-time WCAG 2.2 AA auditor and EU accessibility statement generator for static sites (EAA / BFSG / BaFG, DACH-localised).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  "cli"
24
24
  ],
25
25
  "engines": {
26
- "node": ">=22.22.2"
26
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
27
27
  },
28
28
  "packageManager": "pnpm@10.28.0",
29
29
  "bin": {
@@ -53,7 +53,7 @@
53
53
  "typecheck": "tsc --noEmit",
54
54
  "lint": "biome check .",
55
55
  "format": "biome check --write .",
56
- "smoke": "pnpm build && node dist/cli/index.js audit tests/fixtures/site --include about/** --format json && node dist/cli/index.js audit tests/fixtures/site --include 'about/**' 'blog/**' 'drafts/**' 'legacy.htm' --concurrency 2 && node dist/cli/index.js audit tests/fixtures/site --include about/** --format html && node dist/cli/index.js audit tests/fixtures/site --baseline examples/baseline.json && node -e \"import('./dist/astro/index.js').then(m => { const i = m.default(); if (i.name !== 'eaa-kit' || typeof i.hooks['astro:build:done'] !== 'function') { throw new Error('astro entry point is not an integration') } console.log('astro entry ok') })\" && node dist/cli/index.js statement --config examples/eaa.config.json && node dist/cli/index.js statement --config examples/eaa.config.json --audit examples/report.json --format html",
56
+ "smoke": "pnpm build && node dist/cli/index.js audit tests/fixtures/site --include about/** --format json && node dist/cli/index.js audit tests/fixtures/site --include \"about/**\" \"blog/**\" \"drafts/**\" \"legacy.htm\" --concurrency 2 && node dist/cli/index.js audit tests/fixtures/site --include about/** --format html && node dist/cli/index.js audit tests/fixtures/site --baseline examples/baseline.json && node -e \"import('./dist/astro/index.js').then(m => { const i = m.default(); if (i.name !== 'eaa-kit' || typeof i.hooks['astro:build:done'] !== 'function') { throw new Error('astro entry point is not an integration') } console.log('astro entry ok') })\" && node dist/cli/index.js statement --config examples/eaa.config.json && node dist/cli/index.js statement --config examples/eaa.config.json --audit examples/report.json --format html",
57
57
  "examples": "pnpm build && node scripts/generate-examples.mjs"
58
58
  },
59
59
  "peerDependencies": {
@@ -73,8 +73,7 @@
73
73
  "commander": "^15.0.0",
74
74
  "jsdom": "^30.0.1",
75
75
  "picocolors": "^1.1.1",
76
- "tinyglobby": "^0.2.17",
77
- "zod": "^4.4.3"
76
+ "tinyglobby": "^0.2.17"
78
77
  },
79
78
  "devDependencies": {
80
79
  "@biomejs/biome": "^2.5.9",
@@ -1,2 +0,0 @@
1
- import { r as runAuditCommand } from "./audit-6gbV0Zjd.js";
2
- export { runAuditCommand };