swwa-mcp 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 +21 -0
- package/README.md +50 -0
- package/assets/alt-text-ko.json +7 -0
- package/assets/axe-rule-map.json +196 -0
- package/assets/certification.json +47 -0
- package/assets/kwcag22-checklist.md +123 -0
- package/assets/kwcag22.json +1688 -0
- package/assets/link-text-ko.json +8 -0
- package/assets/mobile-app-2.0.md +38 -0
- package/assets/sources.json +68 -0
- package/assets/wcag22.json +780 -0
- package/bin/swwa-mcp.mjs +15 -0
- package/dist/color/contrast.js +175 -0
- package/dist/color/contrast.js.map +1 -0
- package/dist/data/axe-map.js +32 -0
- package/dist/data/axe-map.js.map +1 -0
- package/dist/data/certification.js +54 -0
- package/dist/data/certification.js.map +1 -0
- package/dist/data/kwcag22.js +91 -0
- package/dist/data/kwcag22.js.map +1 -0
- package/dist/data/loader.js +18 -0
- package/dist/data/loader.js.map +1 -0
- package/dist/data/sources.js +44 -0
- package/dist/data/sources.js.map +1 -0
- package/dist/data/wcag22.js +44 -0
- package/dist/data/wcag22.js.map +1 -0
- package/dist/data/wordlists.js +40 -0
- package/dist/data/wordlists.js.map +1 -0
- package/dist/engine/browser-detect.js +44 -0
- package/dist/engine/browser-detect.js.map +1 -0
- package/dist/engine/browser.js +114 -0
- package/dist/engine/browser.js.map +1 -0
- package/dist/engine/static-worker.js +18 -0
- package/dist/engine/static-worker.js.map +1 -0
- package/dist/engine/static.js +139 -0
- package/dist/engine/static.js.map +1 -0
- package/dist/engine/url-guard.js +37 -0
- package/dist/engine/url-guard.js.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.js +176 -0
- package/dist/messages.js.map +1 -0
- package/dist/normalize/axe.js +72 -0
- package/dist/normalize/axe.js.map +1 -0
- package/dist/normalize/checkpoints.js +47 -0
- package/dist/normalize/checkpoints.js.map +1 -0
- package/dist/normalize/finding.js +24 -0
- package/dist/normalize/finding.js.map +1 -0
- package/dist/normalize/locale.js +20 -0
- package/dist/normalize/locale.js.map +1 -0
- package/dist/prompts/audit-report.js +45 -0
- package/dist/prompts/audit-report.js.map +1 -0
- package/dist/prompts/review-markup.js +35 -0
- package/dist/prompts/review-markup.js.map +1 -0
- package/dist/report/cert.js +72 -0
- package/dist/report/cert.js.map +1 -0
- package/dist/report/format.js +36 -0
- package/dist/report/format.js.map +1 -0
- package/dist/report/summarize.js +61 -0
- package/dist/report/summarize.js.map +1 -0
- package/dist/report/types.js +2 -0
- package/dist/report/types.js.map +1 -0
- package/dist/resources/index.js +69 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/rules/b/b-focus-order.js +33 -0
- package/dist/rules/b/b-focus-order.js.map +1 -0
- package/dist/rules/b/b-focus-visible.js +71 -0
- package/dist/rules/b/b-focus-visible.js.map +1 -0
- package/dist/rules/b/b-keyboard-reachable.js +82 -0
- package/dist/rules/b/b-keyboard-reachable.js.map +1 -0
- package/dist/rules/b/b-motion-runtime.js +50 -0
- package/dist/rules/b/b-motion-runtime.js.map +1 -0
- package/dist/rules/b/b-skip-link-works.js +58 -0
- package/dist/rules/b/b-skip-link-works.js.map +1 -0
- package/dist/rules/b/b-target-size-6mm.js +54 -0
- package/dist/rules/b/b-target-size-6mm.js.map +1 -0
- package/dist/rules/b/index.js +7 -0
- package/dist/rules/b/index.js.map +1 -0
- package/dist/rules/k/index.js +33 -0
- package/dist/rules/k/index.js.map +1 -0
- package/dist/rules/k/k-accesskey.js +20 -0
- package/dist/rules/k/k-accesskey.js.map +1 -0
- package/dist/rules/k/k-alt-meaningless.js +35 -0
- package/dist/rules/k/k-alt-meaningless.js.map +1 -0
- package/dist/rules/k/k-autocomplete-missing.js +36 -0
- package/dist/rules/k/k-autocomplete-missing.js.map +1 -0
- package/dist/rules/k/k-autoplay-media.js +30 -0
- package/dist/rules/k/k-autoplay-media.js.map +1 -0
- package/dist/rules/k/k-captcha-detect.js +24 -0
- package/dist/rules/k/k-captcha-detect.js.map +1 -0
- package/dist/rules/k/k-carousel-no-pause.js +33 -0
- package/dist/rules/k/k-carousel-no-pause.js.map +1 -0
- package/dist/rules/k/k-device-motion.js +22 -0
- package/dist/rules/k/k-device-motion.js.map +1 -0
- package/dist/rules/k/k-down-event-action.js +19 -0
- package/dist/rules/k/k-down-event-action.js.map +1 -0
- package/dist/rules/k/k-error-association.js +31 -0
- package/dist/rules/k/k-error-association.js.map +1 -0
- package/dist/rules/k/k-flash-animation.js +57 -0
- package/dist/rules/k/k-flash-animation.js.map +1 -0
- package/dist/rules/k/k-gesture-listener.js +30 -0
- package/dist/rules/k/k-gesture-listener.js.map +1 -0
- package/dist/rules/k/k-iframe-title.js +23 -0
- package/dist/rules/k/k-iframe-title.js.map +1 -0
- package/dist/rules/k/k-lang-ko-expected.js +29 -0
- package/dist/rules/k/k-lang-ko-expected.js.map +1 -0
- package/dist/rules/k/k-link-same-text-diff-href.js +41 -0
- package/dist/rules/k/k-link-same-text-diff-href.js.map +1 -0
- package/dist/rules/k/k-link-text-generic.js +29 -0
- package/dist/rules/k/k-link-text-generic.js.map +1 -0
- package/dist/rules/k/k-media-track.js +22 -0
- package/dist/rules/k/k-media-track.js.map +1 -0
- package/dist/rules/k/k-mouse-only-handler.js +27 -0
- package/dist/rules/k/k-mouse-only-handler.js.map +1 -0
- package/dist/rules/k/k-new-window-notice.js +27 -0
- package/dist/rules/k/k-new-window-notice.js.map +1 -0
- package/dist/rules/k/k-onload-popup.js +30 -0
- package/dist/rules/k/k-onload-popup.js.map +1 -0
- package/dist/rules/k/k-outline-none.js +55 -0
- package/dist/rules/k/k-outline-none.js.map +1 -0
- package/dist/rules/k/k-parse-errors.js +38 -0
- package/dist/rules/k/k-parse-errors.js.map +1 -0
- package/dist/rules/k/k-placeholder-only-label.js +32 -0
- package/dist/rules/k/k-placeholder-only-label.js.map +1 -0
- package/dist/rules/k/k-select-onchange.js +19 -0
- package/dist/rules/k/k-select-onchange.js.map +1 -0
- package/dist/rules/k/k-sensory-instruction.js +32 -0
- package/dist/rules/k/k-sensory-instruction.js.map +1 -0
- package/dist/rules/k/k-session-timeout-hint.js +29 -0
- package/dist/rules/k/k-session-timeout-hint.js.map +1 -0
- package/dist/rules/k/k-skip-link-first.js +23 -0
- package/dist/rules/k/k-skip-link-first.js.map +1 -0
- package/dist/rules/k/k-skip-target-exists.js +28 -0
- package/dist/rules/k/k-skip-target-exists.js.map +1 -0
- package/dist/rules/k/k-tabindex-positive.js +23 -0
- package/dist/rules/k/k-tabindex-positive.js.map +1 -0
- package/dist/rules/k/k-table-caption.js +26 -0
- package/dist/rules/k/k-table-caption.js.map +1 -0
- package/dist/rules/k/k-table-th-missing.js +28 -0
- package/dist/rules/k/k-table-th-missing.js.map +1 -0
- package/dist/rules/k/k-title-generic.js +35 -0
- package/dist/rules/k/k-title-generic.js.map +1 -0
- package/dist/rules/registry.js +62 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/rules/types.js +2 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/util/browser-dom.js +50 -0
- package/dist/rules/util/browser-dom.js.map +1 -0
- package/dist/rules/util/focusable.js +29 -0
- package/dist/rules/util/focusable.js.map +1 -0
- package/dist/rules/util/selector.js +19 -0
- package/dist/rules/util/selector.js.map +1 -0
- package/dist/rules/util/text.js +13 -0
- package/dist/rules/util/text.js.map +1 -0
- package/dist/schema-dialect.js +41 -0
- package/dist/schema-dialect.js.map +1 -0
- package/dist/server.js +36 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/audit-url.js +109 -0
- package/dist/tools/audit-url.js.map +1 -0
- package/dist/tools/browser-status.js +29 -0
- package/dist/tools/browser-status.js.map +1 -0
- package/dist/tools/cert-readiness.js +76 -0
- package/dist/tools/cert-readiness.js.map +1 -0
- package/dist/tools/check-contrast.js +58 -0
- package/dist/tools/check-contrast.js.map +1 -0
- package/dist/tools/check-html.js +88 -0
- package/dist/tools/check-html.js.map +1 -0
- package/dist/tools/checklist.js +94 -0
- package/dist/tools/checklist.js.map +1 -0
- package/dist/tools/lookup.js +70 -0
- package/dist/tools/lookup.js.map +1 -0
- package/dist/tools/report-schema.js +49 -0
- package/dist/tools/report-schema.js.map +1 -0
- package/package.json +76 -0
package/bin/swwa-mcp.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// 런처: dist가 있으면 로컬 개발 빌드, 없으면 게시본(npx). Windows에서 .mcp.json의 npx 직접
|
|
3
|
+
// 실행 문제를 회피한다(03 §3).
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const dist = fileURLToPath(new URL("../dist/index.js", import.meta.url));
|
|
9
|
+
|
|
10
|
+
if (existsSync(dist)) {
|
|
11
|
+
await import(dist);
|
|
12
|
+
} else {
|
|
13
|
+
const child = spawn("npx", ["-y", "swwa-mcp"], { stdio: "inherit", shell: true });
|
|
14
|
+
child.on("exit", (code) => process.exit(code ?? 1));
|
|
15
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// CSS 색 파싱·상대 휘도·명도 대비 계산(03 §1 color/contrast.ts, check_contrast 도구가 사용).
|
|
2
|
+
// 표준 CSS 색 이름(CSS Color Module Level 3/4) 테이블 — 흔히 쓰이는 이름 위주.
|
|
3
|
+
const NAMED_COLORS = {
|
|
4
|
+
aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255],
|
|
5
|
+
aquamarine: [127, 255, 212], azure: [240, 255, 255], beige: [245, 245, 220],
|
|
6
|
+
bisque: [255, 228, 196], black: [0, 0, 0], blanchedalmond: [255, 235, 205],
|
|
7
|
+
blue: [0, 0, 255], blueviolet: [138, 43, 226], brown: [165, 42, 42],
|
|
8
|
+
burlywood: [222, 184, 135], cadetblue: [95, 158, 160], chartreuse: [127, 255, 0],
|
|
9
|
+
chocolate: [210, 105, 30], coral: [255, 127, 80], cornflowerblue: [100, 149, 237],
|
|
10
|
+
cornsilk: [255, 248, 220], crimson: [220, 20, 60], cyan: [0, 255, 255],
|
|
11
|
+
darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgoldenrod: [184, 134, 11],
|
|
12
|
+
darkgray: [169, 169, 169], darkgreen: [0, 100, 0], darkgrey: [169, 169, 169],
|
|
13
|
+
darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47],
|
|
14
|
+
darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0],
|
|
15
|
+
darksalmon: [233, 150, 122], darkseagreen: [143, 188, 143], darkslateblue: [72, 61, 139],
|
|
16
|
+
darkslategray: [47, 79, 79], darkslategrey: [47, 79, 79], darkturquoise: [0, 206, 209],
|
|
17
|
+
darkviolet: [148, 0, 211], deeppink: [255, 20, 147], deepskyblue: [0, 191, 255],
|
|
18
|
+
dimgray: [105, 105, 105], dimgrey: [105, 105, 105], dodgerblue: [30, 144, 255],
|
|
19
|
+
firebrick: [178, 34, 34], floralwhite: [255, 250, 240], forestgreen: [34, 139, 34],
|
|
20
|
+
fuchsia: [255, 0, 255], gainsboro: [220, 220, 220], ghostwhite: [248, 248, 255],
|
|
21
|
+
gold: [255, 215, 0], goldenrod: [218, 165, 32], gray: [128, 128, 128],
|
|
22
|
+
grey: [128, 128, 128], green: [0, 128, 0], greenyellow: [173, 255, 47],
|
|
23
|
+
honeydew: [240, 255, 240], hotpink: [255, 105, 180], indianred: [205, 92, 92],
|
|
24
|
+
indigo: [75, 0, 130], ivory: [255, 255, 240], khaki: [240, 230, 140],
|
|
25
|
+
lavender: [230, 230, 250], lavenderblush: [255, 240, 245], lawngreen: [124, 252, 0],
|
|
26
|
+
lemonchiffon: [255, 250, 205], lightblue: [173, 216, 230], lightcoral: [240, 128, 128],
|
|
27
|
+
lightcyan: [224, 255, 255], lightgoldenrodyellow: [250, 250, 210], lightgray: [211, 211, 211],
|
|
28
|
+
lightgreen: [144, 238, 144], lightgrey: [211, 211, 211], lightpink: [255, 182, 193],
|
|
29
|
+
lightsalmon: [255, 160, 122], lightseagreen: [32, 178, 170], lightskyblue: [135, 206, 250],
|
|
30
|
+
lightslategray: [119, 136, 153], lightslategrey: [119, 136, 153], lightsteelblue: [176, 196, 222],
|
|
31
|
+
lightyellow: [255, 255, 224], lime: [0, 255, 0], limegreen: [50, 205, 50],
|
|
32
|
+
linen: [250, 240, 230], magenta: [255, 0, 255], maroon: [128, 0, 0],
|
|
33
|
+
mediumaquamarine: [102, 205, 170], mediumblue: [0, 0, 205], mediumorchid: [186, 85, 211],
|
|
34
|
+
mediumpurple: [147, 112, 219], mediumseagreen: [60, 179, 113], mediumslateblue: [123, 104, 238],
|
|
35
|
+
mediumspringgreen: [0, 250, 154], mediumturquoise: [72, 209, 204], mediumvioletred: [199, 21, 133],
|
|
36
|
+
midnightblue: [25, 25, 112], mintcream: [245, 255, 250], mistyrose: [255, 228, 225],
|
|
37
|
+
moccasin: [255, 228, 181], navajowhite: [255, 222, 173], navy: [0, 0, 128],
|
|
38
|
+
oldlace: [253, 245, 230], olive: [128, 128, 0], olivedrab: [107, 142, 35],
|
|
39
|
+
orange: [255, 165, 0], orangered: [255, 69, 0], orchid: [218, 112, 214],
|
|
40
|
+
palegoldenrod: [238, 232, 170], palegreen: [152, 251, 152], paleturquoise: [175, 238, 238],
|
|
41
|
+
palevioletred: [219, 112, 147], papayawhip: [255, 239, 213], peachpuff: [255, 218, 185],
|
|
42
|
+
peru: [205, 133, 63], pink: [255, 192, 203], plum: [221, 160, 221],
|
|
43
|
+
powderblue: [176, 224, 230], purple: [128, 0, 128], rebeccapurple: [102, 51, 153],
|
|
44
|
+
red: [255, 0, 0], rosybrown: [188, 143, 143], royalblue: [65, 105, 225],
|
|
45
|
+
saddlebrown: [139, 69, 19], salmon: [250, 128, 114], sandybrown: [244, 164, 96],
|
|
46
|
+
seagreen: [46, 139, 87], seashell: [255, 245, 238], sienna: [160, 82, 45],
|
|
47
|
+
silver: [192, 192, 192], skyblue: [135, 206, 235], slateblue: [106, 90, 205],
|
|
48
|
+
slategray: [112, 128, 144], slategrey: [112, 128, 144], snow: [255, 250, 250],
|
|
49
|
+
springgreen: [0, 255, 127], steelblue: [70, 130, 180], tan: [210, 180, 140],
|
|
50
|
+
teal: [0, 128, 128], thistle: [216, 191, 216], tomato: [255, 99, 71],
|
|
51
|
+
turquoise: [64, 224, 208], violet: [238, 130, 238], wheat: [245, 222, 179],
|
|
52
|
+
white: [255, 255, 255], whitesmoke: [245, 245, 245], yellow: [255, 255, 0],
|
|
53
|
+
yellowgreen: [154, 205, 50],
|
|
54
|
+
};
|
|
55
|
+
function clamp255(n) {
|
|
56
|
+
return Math.min(255, Math.max(0, Math.round(n)));
|
|
57
|
+
}
|
|
58
|
+
function parsePercentOrNumber(raw, max = 255) {
|
|
59
|
+
const trimmed = raw.trim();
|
|
60
|
+
if (trimmed.endsWith("%"))
|
|
61
|
+
return (parseFloat(trimmed) / 100) * max;
|
|
62
|
+
return parseFloat(trimmed);
|
|
63
|
+
}
|
|
64
|
+
function hslToRgb(h, s, l) {
|
|
65
|
+
const hue = ((h % 360) + 360) % 360;
|
|
66
|
+
const sat = Math.min(1, Math.max(0, s));
|
|
67
|
+
const light = Math.min(1, Math.max(0, l));
|
|
68
|
+
const c = (1 - Math.abs(2 * light - 1)) * sat;
|
|
69
|
+
const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));
|
|
70
|
+
const m = light - c / 2;
|
|
71
|
+
let r1, g1, b1;
|
|
72
|
+
if (hue < 60)
|
|
73
|
+
[r1, g1, b1] = [c, x, 0];
|
|
74
|
+
else if (hue < 120)
|
|
75
|
+
[r1, g1, b1] = [x, c, 0];
|
|
76
|
+
else if (hue < 180)
|
|
77
|
+
[r1, g1, b1] = [0, c, x];
|
|
78
|
+
else if (hue < 240)
|
|
79
|
+
[r1, g1, b1] = [0, x, c];
|
|
80
|
+
else if (hue < 300)
|
|
81
|
+
[r1, g1, b1] = [x, 0, c];
|
|
82
|
+
else
|
|
83
|
+
[r1, g1, b1] = [c, 0, x];
|
|
84
|
+
return [clamp255((r1 + m) * 255), clamp255((g1 + m) * 255), clamp255((b1 + m) * 255)];
|
|
85
|
+
}
|
|
86
|
+
/** hex/rgb()/rgba()/hsl()/hsla()/CSS 색 이름을 파싱한다. 실패 시 null. */
|
|
87
|
+
export function parseColor(input) {
|
|
88
|
+
const s = input.trim().toLowerCase();
|
|
89
|
+
const hex = /^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(s);
|
|
90
|
+
if (hex) {
|
|
91
|
+
const v = hex[1];
|
|
92
|
+
if (v.length === 3 || v.length === 4) {
|
|
93
|
+
const r = parseInt(v[0] + v[0], 16);
|
|
94
|
+
const g = parseInt(v[1] + v[1], 16);
|
|
95
|
+
const b = parseInt(v[2] + v[2], 16);
|
|
96
|
+
const a = v.length === 4 ? parseInt(v[3] + v[3], 16) / 255 : 1;
|
|
97
|
+
return { r, g, b, a };
|
|
98
|
+
}
|
|
99
|
+
const r = parseInt(v.slice(0, 2), 16);
|
|
100
|
+
const g = parseInt(v.slice(2, 4), 16);
|
|
101
|
+
const b = parseInt(v.slice(4, 6), 16);
|
|
102
|
+
const a = v.length === 8 ? parseInt(v.slice(6, 8), 16) / 255 : 1;
|
|
103
|
+
return { r, g, b, a };
|
|
104
|
+
}
|
|
105
|
+
const rgb = /^rgba?\(\s*([\d.]+%?)\s*,\s*([\d.]+%?)\s*,\s*([\d.]+%?)\s*(?:,\s*([\d.]+%?)\s*)?\)$/.exec(s);
|
|
106
|
+
if (rgb) {
|
|
107
|
+
const [, rRaw, gRaw, bRaw, aRaw] = rgb;
|
|
108
|
+
return {
|
|
109
|
+
r: clamp255(parsePercentOrNumber(rRaw)),
|
|
110
|
+
g: clamp255(parsePercentOrNumber(gRaw)),
|
|
111
|
+
b: clamp255(parsePercentOrNumber(bRaw)),
|
|
112
|
+
a: aRaw !== undefined ? parsePercentOrNumber(aRaw, 1) : 1,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const hsl = /^hsla?\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*(?:,\s*([\d.]+%?)\s*)?\)$/.exec(s);
|
|
116
|
+
if (hsl) {
|
|
117
|
+
const [, hRaw, sRaw, lRaw, aRaw] = hsl;
|
|
118
|
+
const [r, g, b] = hslToRgb(parseFloat(hRaw), parseFloat(sRaw) / 100, parseFloat(lRaw) / 100);
|
|
119
|
+
return { r, g, b, a: aRaw !== undefined ? parsePercentOrNumber(aRaw, 1) : 1 };
|
|
120
|
+
}
|
|
121
|
+
const named = NAMED_COLORS[s];
|
|
122
|
+
if (named)
|
|
123
|
+
return { r: named[0], g: named[1], b: named[2], a: 1 };
|
|
124
|
+
if (s === "transparent")
|
|
125
|
+
return { r: 0, g: 0, b: 0, a: 0 };
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
/** 알파가 있는 전경색을 배경 위에 합성한다(불투명 배경 가정). */
|
|
129
|
+
export function compositeOver(fg, bg) {
|
|
130
|
+
if (fg.a >= 1)
|
|
131
|
+
return { r: fg.r, g: fg.g, b: fg.b };
|
|
132
|
+
return {
|
|
133
|
+
r: fg.r * fg.a + bg.r * (1 - fg.a),
|
|
134
|
+
g: fg.g * fg.a + bg.g * (1 - fg.a),
|
|
135
|
+
b: fg.b * fg.a + bg.b * (1 - fg.a),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function srgbChannel(c) {
|
|
139
|
+
const s = c / 255;
|
|
140
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
141
|
+
}
|
|
142
|
+
/** WCAG 상대 휘도(0~1). */
|
|
143
|
+
export function relativeLuminance(rgb) {
|
|
144
|
+
return 0.2126 * srgbChannel(rgb.r) + 0.7152 * srgbChannel(rgb.g) + 0.0722 * srgbChannel(rgb.b);
|
|
145
|
+
}
|
|
146
|
+
/** 두 상대 휘도의 명도 대비율(1~21). */
|
|
147
|
+
export function contrastRatio(l1, l2) {
|
|
148
|
+
const lighter = Math.max(l1, l2);
|
|
149
|
+
const darker = Math.min(l1, l2);
|
|
150
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 전경·배경 문자열로 명도 대비를 계산한다(5.4.3/1.4.3). 큰 글자 = 24px 이상 또는
|
|
154
|
+
* 18.66px 이상 굵게(WCAG 18pt/14pt bold를 96dpi 기준 px로 환산).
|
|
155
|
+
*/
|
|
156
|
+
export function evaluateContrast(foreground, background, fontSizePx = 16, bold = false) {
|
|
157
|
+
const fg = parseColor(foreground);
|
|
158
|
+
const bg = parseColor(background);
|
|
159
|
+
if (!fg || !bg) {
|
|
160
|
+
throw new Error(`색상 값을 해석할 수 없습니다: ${!fg ? foreground : background}`);
|
|
161
|
+
}
|
|
162
|
+
const composited = compositeOver(fg, { r: bg.r, g: bg.g, b: bg.b });
|
|
163
|
+
const ratio = contrastRatio(relativeLuminance(composited), relativeLuminance(bg));
|
|
164
|
+
const largeText = fontSizePx >= 24 || (bold && fontSizePx >= 18.66);
|
|
165
|
+
const threshold = largeText ? 3.0 : 4.5;
|
|
166
|
+
const aaaThreshold = largeText ? 4.5 : 7.0;
|
|
167
|
+
return {
|
|
168
|
+
ratio,
|
|
169
|
+
largeText,
|
|
170
|
+
aa: ratio >= threshold ? "pass" : "fail",
|
|
171
|
+
aaa: ratio >= aaaThreshold ? "pass" : "fail",
|
|
172
|
+
threshold,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=contrast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contrast.js","sourceRoot":"","sources":["../../src/color/contrast.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const overrideSchema = z.object({
|
|
4
|
+
kwcag: z.string().regex(/^\d\.\d\.\d$/).nullable().optional(),
|
|
5
|
+
staticDisabled: z.boolean().optional(),
|
|
6
|
+
});
|
|
7
|
+
const axeRuleMapSchema = z.record(z.string(), overrideSchema);
|
|
8
|
+
function formatIssues(issues) {
|
|
9
|
+
return issues
|
|
10
|
+
.slice(0, 8)
|
|
11
|
+
.map((issue) => `- ${issue.path.join(".")}: ${issue.message}`)
|
|
12
|
+
.join("\n");
|
|
13
|
+
}
|
|
14
|
+
export function parseAxeMap(data) {
|
|
15
|
+
const result = axeRuleMapSchema.safeParse(data);
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
throw new Error(`axe-rule-map.json 검증에 실패했습니다:\n${formatIssues(result.error.issues)}`);
|
|
18
|
+
}
|
|
19
|
+
return result.data;
|
|
20
|
+
}
|
|
21
|
+
export function loadAxeMap() {
|
|
22
|
+
const url = new URL("../../assets/axe-rule-map.json", import.meta.url);
|
|
23
|
+
let json;
|
|
24
|
+
try {
|
|
25
|
+
json = JSON.parse(readFileSync(url, "utf8"));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new Error(`axe-rule-map.json을 읽을 수 없습니다: ${decodeURIComponent(url.pathname)}`);
|
|
29
|
+
}
|
|
30
|
+
return parseAxeMap(json);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=axe-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axe-map.js","sourceRoot":"","sources":["../../src/data/axe-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC7D,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC;AAK9D,SAAS,YAAY,CAAC,MAA2D;IAC/E,OAAO,MAAM;SACV,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAC7D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,kCAAkC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,gCAAgC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvE,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,iCAAiC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const legalBasisSchema = z.object({
|
|
4
|
+
law: z.string().min(1),
|
|
5
|
+
article: z.string().min(1),
|
|
6
|
+
note: z.string().min(1).optional(),
|
|
7
|
+
needsVerification: z.boolean().optional(),
|
|
8
|
+
});
|
|
9
|
+
const criterionSchema = z.object({
|
|
10
|
+
kind: z.enum(["expert", "user", "overall"]),
|
|
11
|
+
text: z.string().min(1),
|
|
12
|
+
value: z.number(),
|
|
13
|
+
needsVerification: z.boolean().optional(),
|
|
14
|
+
verifiedOn: z.string().nullable().optional(),
|
|
15
|
+
sourceUrl: z.string().nullable().optional(),
|
|
16
|
+
});
|
|
17
|
+
const agencySchema = z.object({
|
|
18
|
+
name: z.string().min(1),
|
|
19
|
+
url: z.string().nullable().optional(),
|
|
20
|
+
needsVerification: z.boolean().optional(),
|
|
21
|
+
});
|
|
22
|
+
const certificationFileSchema = z.object({
|
|
23
|
+
legalBasis: z.array(legalBasisSchema),
|
|
24
|
+
standard: z.object({ name: z.string().min(1), checkpoints: z.number().int() }),
|
|
25
|
+
criteria: z.array(criterionSchema),
|
|
26
|
+
validity: z.object({ text: z.string().min(1), needsVerification: z.boolean().optional() }),
|
|
27
|
+
agencies: z.array(agencySchema),
|
|
28
|
+
procedure: z.array(z.string().min(1)),
|
|
29
|
+
});
|
|
30
|
+
function formatIssues(issues) {
|
|
31
|
+
return issues
|
|
32
|
+
.slice(0, 8)
|
|
33
|
+
.map((issue) => `- ${issue.path.join(".")}: ${issue.message}`)
|
|
34
|
+
.join("\n");
|
|
35
|
+
}
|
|
36
|
+
export function parseCertification(data) {
|
|
37
|
+
const result = certificationFileSchema.safeParse(data);
|
|
38
|
+
if (!result.success) {
|
|
39
|
+
throw new Error(`certification.json 검증에 실패했습니다:\n${formatIssues(result.error.issues)}`);
|
|
40
|
+
}
|
|
41
|
+
return result.data;
|
|
42
|
+
}
|
|
43
|
+
export function loadCertification() {
|
|
44
|
+
const url = new URL("../../assets/certification.json", import.meta.url);
|
|
45
|
+
let json;
|
|
46
|
+
try {
|
|
47
|
+
json = JSON.parse(readFileSync(url, "utf8"));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new Error(`certification.json을 읽을 수 없습니다: ${decodeURIComponent(url.pathname)}`);
|
|
51
|
+
}
|
|
52
|
+
return parseCertification(json);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=certification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certification.js","sourceRoot":"","sources":["../../src/data/certification.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const automationSchema = z.enum(["auto", "assist", "manual", "na"]);
|
|
4
|
+
const wcagRefSchema = z.object({
|
|
5
|
+
sc: z.string().min(1),
|
|
6
|
+
level: z.enum(["A", "AA", "AAA"]),
|
|
7
|
+
});
|
|
8
|
+
const checkpointSchema = z.object({
|
|
9
|
+
id: z.string().regex(/^\d\.\d\.\d$/),
|
|
10
|
+
alias: z.string().regex(/^\d\.\d\.\d$/),
|
|
11
|
+
principle: z.object({
|
|
12
|
+
no: z.number().int(),
|
|
13
|
+
alias: z.number().int(),
|
|
14
|
+
name: z.string().min(1),
|
|
15
|
+
}),
|
|
16
|
+
guideline: z.object({
|
|
17
|
+
no: z.string().min(1),
|
|
18
|
+
alias: z.string().min(1),
|
|
19
|
+
name: z.string().min(1),
|
|
20
|
+
}),
|
|
21
|
+
name_ko: z.string().min(1),
|
|
22
|
+
name_en: z.string().min(1).nullable(),
|
|
23
|
+
requirement_ko: z.string().min(1),
|
|
24
|
+
summary_ko: z.string().min(1),
|
|
25
|
+
wcag: z.array(wcagRefSchema),
|
|
26
|
+
automation: automationSchema,
|
|
27
|
+
axeRules: z.array(z.string().min(1)),
|
|
28
|
+
kRules: z.array(z.string().regex(/^k-/)),
|
|
29
|
+
bRules: z.array(z.string().regex(/^b-/)),
|
|
30
|
+
testMethod_ko: z.array(z.string().min(1)),
|
|
31
|
+
commonErrors_ko: z.array(z.string().min(1)),
|
|
32
|
+
passExamples_ko: z.array(z.string().min(1)),
|
|
33
|
+
components: z.array(z.string()),
|
|
34
|
+
newIn22: z.boolean(),
|
|
35
|
+
sources: z.array(z.string().min(1)),
|
|
36
|
+
});
|
|
37
|
+
const kwcag22FileSchema = z.object({
|
|
38
|
+
version: z.string().min(1),
|
|
39
|
+
dataVersion: z.string().min(1),
|
|
40
|
+
updatedAt: z.string().min(1),
|
|
41
|
+
sourceIds: z.array(z.string().min(1)).min(1),
|
|
42
|
+
checkpoints: z.array(checkpointSchema),
|
|
43
|
+
});
|
|
44
|
+
function formatIssues(issues) {
|
|
45
|
+
return issues
|
|
46
|
+
.slice(0, 8)
|
|
47
|
+
.map((issue) => `- ${issue.path.join(".")}: ${issue.message}`)
|
|
48
|
+
.join("\n");
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 단일 소스(ADR-04)의 검사항목 수는 33개로 고정이다. zod 스키마와 별개로 여기서 강제해
|
|
52
|
+
* assets/kwcag22.json 갱신 실수(누락·중복)를 기동 시점에 막는다.
|
|
53
|
+
*/
|
|
54
|
+
export function parseKwcag22(data) {
|
|
55
|
+
const result = kwcag22FileSchema.safeParse(data);
|
|
56
|
+
if (!result.success) {
|
|
57
|
+
throw new Error(`kwcag22.json 검증에 실패했습니다:\n${formatIssues(result.error.issues)}`);
|
|
58
|
+
}
|
|
59
|
+
const { checkpoints } = result.data;
|
|
60
|
+
if (checkpoints.length !== 33) {
|
|
61
|
+
throw new Error(`검사항목은 33개여야 하는데 ${checkpoints.length}개입니다.`);
|
|
62
|
+
}
|
|
63
|
+
const seen = new Set();
|
|
64
|
+
for (const cp of checkpoints) {
|
|
65
|
+
if (seen.has(cp.id))
|
|
66
|
+
throw new Error(`검사항목 ID가 중복됩니다: ${cp.id}`);
|
|
67
|
+
seen.add(cp.id);
|
|
68
|
+
}
|
|
69
|
+
const byId = new Map();
|
|
70
|
+
for (const cp of checkpoints) {
|
|
71
|
+
byId.set(cp.id, cp);
|
|
72
|
+
byId.set(cp.alias, cp);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...result.data,
|
|
76
|
+
findById: (idOrAlias) => byId.get(idOrAlias),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** assets/kwcag22.json을 기동 시 1회 읽어 검증한다. 경로는 import.meta.url 기준(전역 설치·npx 모두 동작). */
|
|
80
|
+
export function loadKwcag22() {
|
|
81
|
+
const url = new URL("../../assets/kwcag22.json", import.meta.url);
|
|
82
|
+
let json;
|
|
83
|
+
try {
|
|
84
|
+
json = JSON.parse(readFileSync(url, "utf8"));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
throw new Error(`kwcag22.json을 읽을 수 없습니다: ${decodeURIComponent(url.pathname)}`);
|
|
88
|
+
}
|
|
89
|
+
return parseKwcag22(json);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=kwcag22.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kwcag22.js","sourceRoot":"","sources":["../../src/data/kwcag22.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { loadKwcag22 } from "./kwcag22.js";
|
|
2
|
+
import { loadWcag22 } from "./wcag22.js";
|
|
3
|
+
import { loadAxeMap } from "./axe-map.js";
|
|
4
|
+
import { loadCertification } from "./certification.js";
|
|
5
|
+
import { loadWordlists } from "./wordlists.js";
|
|
6
|
+
import { loadSources } from "./sources.js";
|
|
7
|
+
/** assets/*.json을 기동 시 1회 읽어 전부 검증한다. 하나라도 실패하면 기동을 중단한다(ADR-08). */
|
|
8
|
+
export function loadDataBundle() {
|
|
9
|
+
return {
|
|
10
|
+
kwcag22: loadKwcag22(),
|
|
11
|
+
wcag22: loadWcag22(),
|
|
12
|
+
axeRuleMap: loadAxeMap(),
|
|
13
|
+
certification: loadCertification(),
|
|
14
|
+
wordlists: loadWordlists(),
|
|
15
|
+
sources: loadSources(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/data/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAsB,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAmB,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAA4B,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,aAAa,EAAkB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAsB,MAAM,cAAc,CAAC;AAY/D,qEAAqE;AACrE,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,OAAO,EAAE,WAAW,EAAE;QACtB,MAAM,EAAE,UAAU,EAAE;QACpB,UAAU,EAAE,UAAU,EAAE;QACxB,aAAa,EAAE,iBAAiB,EAAE;QAClC,SAAS,EAAE,aAAa,EAAE;QAC1B,OAAO,EAAE,WAAW,EAAE;KACvB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const sourceSchema = z.object({
|
|
4
|
+
id: z.string().min(1),
|
|
5
|
+
title: z.string().min(1),
|
|
6
|
+
url: z.string().nullable(),
|
|
7
|
+
accessedOn: z.string().min(1),
|
|
8
|
+
status: z.enum(["ok", "needsVerification"]),
|
|
9
|
+
license: z.string().min(1),
|
|
10
|
+
});
|
|
11
|
+
const sourcesFileSchema = z.object({
|
|
12
|
+
sources: z.array(sourceSchema).min(1),
|
|
13
|
+
});
|
|
14
|
+
function formatIssues(issues) {
|
|
15
|
+
return issues
|
|
16
|
+
.slice(0, 8)
|
|
17
|
+
.map((issue) => `- ${issue.path.join(".")}: ${issue.message}`)
|
|
18
|
+
.join("\n");
|
|
19
|
+
}
|
|
20
|
+
export function parseSources(data) {
|
|
21
|
+
const result = sourcesFileSchema.safeParse(data);
|
|
22
|
+
if (!result.success) {
|
|
23
|
+
throw new Error(`sources.json 검증에 실패했습니다:\n${formatIssues(result.error.issues)}`);
|
|
24
|
+
}
|
|
25
|
+
const seen = new Set();
|
|
26
|
+
for (const source of result.data.sources) {
|
|
27
|
+
if (seen.has(source.id))
|
|
28
|
+
throw new Error(`출처 ID가 중복됩니다: ${source.id}`);
|
|
29
|
+
seen.add(source.id);
|
|
30
|
+
}
|
|
31
|
+
return result.data;
|
|
32
|
+
}
|
|
33
|
+
export function loadSources() {
|
|
34
|
+
const url = new URL("../../assets/sources.json", import.meta.url);
|
|
35
|
+
let json;
|
|
36
|
+
try {
|
|
37
|
+
json = JSON.parse(readFileSync(url, "utf8"));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new Error(`sources.json을 읽을 수 없습니다: ${decodeURIComponent(url.pathname)}`);
|
|
41
|
+
}
|
|
42
|
+
return parseSources(json);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.js","sourceRoot":"","sources":["../../src/data/sources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CACtC,CAAC,CAAC;AAKH,SAAS,YAAY,CAAC,MAA2D;IAC/E,OAAO,MAAM;SACV,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAC7D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,6BAA6B,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACzC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClE,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,4BAA4B,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const criterionSchema = z.object({
|
|
4
|
+
sc: z.string().min(1),
|
|
5
|
+
name_en: z.string().min(1),
|
|
6
|
+
name_ko: z.string().min(1),
|
|
7
|
+
level: z.enum(["A", "AA", "AAA"]),
|
|
8
|
+
since: z.string().min(1),
|
|
9
|
+
kwcagIds: z.array(z.string().regex(/^\d\.\d\.\d$/)),
|
|
10
|
+
removedIn: z.string().min(1).optional(),
|
|
11
|
+
needsVerification: z.boolean().optional(),
|
|
12
|
+
});
|
|
13
|
+
const wcag22FileSchema = z.object({
|
|
14
|
+
criteria: z.array(criterionSchema),
|
|
15
|
+
});
|
|
16
|
+
function formatIssues(issues) {
|
|
17
|
+
return issues
|
|
18
|
+
.slice(0, 8)
|
|
19
|
+
.map((issue) => `- ${issue.path.join(".")}: ${issue.message}`)
|
|
20
|
+
.join("\n");
|
|
21
|
+
}
|
|
22
|
+
export function parseWcag22(data) {
|
|
23
|
+
const result = wcag22FileSchema.safeParse(data);
|
|
24
|
+
if (!result.success) {
|
|
25
|
+
throw new Error(`wcag22.json 검증에 실패했습니다:\n${formatIssues(result.error.issues)}`);
|
|
26
|
+
}
|
|
27
|
+
const bySc = new Map(result.data.criteria.map((c) => [c.sc, c]));
|
|
28
|
+
return {
|
|
29
|
+
criteria: result.data.criteria,
|
|
30
|
+
findBySc: (sc) => bySc.get(sc),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function loadWcag22() {
|
|
34
|
+
const url = new URL("../../assets/wcag22.json", import.meta.url);
|
|
35
|
+
let json;
|
|
36
|
+
try {
|
|
37
|
+
json = JSON.parse(readFileSync(url, "utf8"));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new Error(`wcag22.json을 읽을 수 없습니다: ${decodeURIComponent(url.pathname)}`);
|
|
41
|
+
}
|
|
42
|
+
return parseWcag22(json);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=wcag22.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wcag22.js","sourceRoot":"","sources":["../../src/data/wcag22.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACnD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvC,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC1C,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;CACnC,CAAC,CAAC;AASH,SAAS,YAAY,CAAC,MAA2D;IAC/E,OAAO,MAAM;SACV,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAC7D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,4BAA4B,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAU,CAAC,CAAC,CAAC;IAC1E,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;QAC9B,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,0BAA0B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjE,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,2BAA2B,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const linkTextSchema = z.object({
|
|
4
|
+
generic: z.array(z.string().min(1)),
|
|
5
|
+
generic_prefix: z.array(z.string().min(1)),
|
|
6
|
+
});
|
|
7
|
+
const altTextSchema = z.object({
|
|
8
|
+
meaningless: z.array(z.string().min(1)),
|
|
9
|
+
filenamePattern: z.string().min(1),
|
|
10
|
+
});
|
|
11
|
+
function formatIssues(issues) {
|
|
12
|
+
return issues
|
|
13
|
+
.slice(0, 8)
|
|
14
|
+
.map((issue) => `- ${issue.path.join(".")}: ${issue.message}`)
|
|
15
|
+
.join("\n");
|
|
16
|
+
}
|
|
17
|
+
function readJson(relativePath) {
|
|
18
|
+
const url = new URL(relativePath, import.meta.url);
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(readFileSync(url, "utf8"));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error(`데이터 파일을 읽을 수 없습니다: ${decodeURIComponent(url.pathname)}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function parseWordlists(linkTextData, altTextData) {
|
|
27
|
+
const linkResult = linkTextSchema.safeParse(linkTextData);
|
|
28
|
+
if (!linkResult.success) {
|
|
29
|
+
throw new Error(`link-text-ko.json 검증에 실패했습니다:\n${formatIssues(linkResult.error.issues)}`);
|
|
30
|
+
}
|
|
31
|
+
const altResult = altTextSchema.safeParse(altTextData);
|
|
32
|
+
if (!altResult.success) {
|
|
33
|
+
throw new Error(`alt-text-ko.json 검증에 실패했습니다:\n${formatIssues(altResult.error.issues)}`);
|
|
34
|
+
}
|
|
35
|
+
return { linkText: linkResult.data, altText: altResult.data };
|
|
36
|
+
}
|
|
37
|
+
export function loadWordlists() {
|
|
38
|
+
return parseWordlists(readJson("../../assets/link-text-ko.json"), readJson("../../assets/alt-text-ko.json"));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=wordlists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wordlists.js","sourceRoot":"","sources":["../../src/data/wordlists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACnC,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC3C,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACvC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACnC,CAAC,CAAC;AAUH,SAAS,YAAY,CAAC,MAA2D;IAC/E,OAAO,MAAM;SACV,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAC7D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,YAAoB;IACpC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sBAAsB,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,YAAqB,EAAE,WAAoB;IACxE,MAAM,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kCAAkC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACvD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,iCAAiC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,cAAc,CAAC,QAAQ,CAAC,gCAAgC,CAAC,EAAE,QAAQ,CAAC,+BAA+B,CAAC,CAAC,CAAC;AAC/G,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { chromium } from "playwright-core";
|
|
2
|
+
const INSTALL_HINT = "Chrome 또는 Edge를 설치하거나 `npx playwright install chromium`을 실행하세요.";
|
|
3
|
+
let cached;
|
|
4
|
+
async function tryLaunch(channel) {
|
|
5
|
+
let browser;
|
|
6
|
+
try {
|
|
7
|
+
browser = await chromium.launch(channel ? { channel, headless: true } : { headless: true });
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
return {
|
|
14
|
+
available: true,
|
|
15
|
+
channel: channel ?? "chromium",
|
|
16
|
+
version: browser.version(),
|
|
17
|
+
// channel 기반 실행(chrome·msedge)은 실제 실행 파일 경로를 조회하는 공개 API가 없다
|
|
18
|
+
// (playwright-core의 executablePath()는 번들 chromium 전용). 번들 chromium일 때만 채운다.
|
|
19
|
+
executablePath: channel ? undefined : chromium.executablePath(),
|
|
20
|
+
installHint: INSTALL_HINT,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
await browser.close();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 설치된 Chrome → Edge → Playwright 번들 chromium 순으로 채널을 탐지한다(ADR-03).
|
|
29
|
+
* 프로세스 내 캐시하며, `refresh: true`일 때만 재탐지한다(§3.1 browser_status).
|
|
30
|
+
*/
|
|
31
|
+
export async function detectBrowser(options) {
|
|
32
|
+
if (cached && !options?.refresh)
|
|
33
|
+
return cached;
|
|
34
|
+
for (const channel of ["chrome", "msedge", undefined]) {
|
|
35
|
+
const result = await tryLaunch(channel);
|
|
36
|
+
if (result) {
|
|
37
|
+
cached = result;
|
|
38
|
+
return cached;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
cached = { available: false, channel: null, installHint: INSTALL_HINT };
|
|
42
|
+
return cached;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=browser-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-detect.js","sourceRoot":"","sources":["../../src/engine/browser-detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAY3C,MAAM,YAAY,GAAG,iEAAiE,CAAC;AAEvF,IAAI,MAAiC,CAAC;AAEtC,KAAK,UAAU,SAAS,CAAC,OAAmC;IAC1D,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO;YACL,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,OAAO,IAAI,UAAU;YAC9B,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;YAC1B,6DAA6D;YAC7D,4EAA4E;YAC5E,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,EAAE;YAC/D,WAAW,EAAE,YAAY;SAC1B,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA+B;IACjE,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO;QAAE,OAAO,MAAM,CAAC;IAC/C,KAAK,MAAM,OAAO,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,MAAM,CAAC;YAChB,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,MAAM,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;IACxE,OAAO,MAAM,CAAC;AAChB,CAAC"}
|