@poetora/cli 0.0.1
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/.prettierignore +2 -0
- package/README.md +3 -0
- package/__test__/brokenLinks.test.ts +93 -0
- package/__test__/checkPort.test.ts +92 -0
- package/__test__/openApiCheck.test.ts +127 -0
- package/__test__/update.test.ts +108 -0
- package/__test__/utils.ts +20 -0
- package/bin/accessibility.d.ts +44 -0
- package/bin/accessibility.js +110 -0
- package/bin/accessibilityCheck.d.ts +2 -0
- package/bin/accessibilityCheck.js +70 -0
- package/bin/cli.d.ts +11 -0
- package/bin/cli.js +201 -0
- package/bin/constants.d.ts +2 -0
- package/bin/constants.js +3 -0
- package/bin/helpers.d.ts +17 -0
- package/bin/helpers.js +104 -0
- package/bin/index.d.ts +4 -0
- package/bin/index.js +92 -0
- package/bin/init.d.ts +1 -0
- package/bin/init.js +73 -0
- package/bin/mdxAccessibility.d.ts +13 -0
- package/bin/mdxAccessibility.js +102 -0
- package/bin/mdxLinter.d.ts +2 -0
- package/bin/mdxLinter.js +45 -0
- package/bin/start.d.ts +2 -0
- package/bin/start.js +4 -0
- package/bin/update.d.ts +3 -0
- package/bin/update.js +32 -0
- package/package.json +83 -0
- package/src/accessibility.ts +180 -0
- package/src/accessibilityCheck.tsx +145 -0
- package/src/cli.tsx +302 -0
- package/src/constants.ts +4 -0
- package/src/helpers.tsx +131 -0
- package/src/index.ts +110 -0
- package/src/init.tsx +93 -0
- package/src/mdxAccessibility.ts +133 -0
- package/src/mdxLinter.tsx +88 -0
- package/src/start.ts +6 -0
- package/src/update.tsx +37 -0
- package/tsconfig.build.json +16 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +8 -0
package/bin/start.d.ts
ADDED
package/bin/start.js
ADDED
package/bin/update.d.ts
ADDED
package/bin/update.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SpinnerLog, SuccessLog, ErrorLog, addLog, clearLogs } from '@poetora/previewing';
|
|
3
|
+
import { execAsync, getLatestCliVersion, getVersions, detectPackageManager } from './helpers.js';
|
|
4
|
+
export const update = async ({ packageName }) => {
|
|
5
|
+
addLog(_jsx(SpinnerLog, { message: "updating..." }));
|
|
6
|
+
const { cli: existingCliVersion } = getVersions();
|
|
7
|
+
const latestCliVersion = getLatestCliVersion(packageName);
|
|
8
|
+
const isUpToDate = existingCliVersion && latestCliVersion && latestCliVersion.trim() === existingCliVersion.trim();
|
|
9
|
+
if (isUpToDate) {
|
|
10
|
+
addLog(_jsx(SuccessLog, { message: "already up to date" }));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (existingCliVersion && latestCliVersion.trim() !== existingCliVersion.trim()) {
|
|
14
|
+
try {
|
|
15
|
+
clearLogs();
|
|
16
|
+
addLog(_jsx(SpinnerLog, { message: `updating ${packageName} package...` }));
|
|
17
|
+
const packageManager = await detectPackageManager({ packageName });
|
|
18
|
+
if (packageManager === 'pnpm') {
|
|
19
|
+
await execAsync(`pnpm install -g ${packageName}@latest --silent`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
await execAsync(`npm install -g ${packageName}@latest --silent`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
addLog(_jsx(ErrorLog, { message: `failed to update ${packageName}@latest` }));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
clearLogs();
|
|
31
|
+
addLog(_jsx(SuccessLog, { message: `updated ${packageName} to the latest version: ${latestCliVersion}` }));
|
|
32
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@poetora/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "The CLI for Poetora documentation Engine",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=18.0.0"
|
|
7
|
+
},
|
|
8
|
+
"author": "Poetora",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/poetora/docs/issues"
|
|
11
|
+
},
|
|
12
|
+
"license": "Elastic-2.0",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"poetora",
|
|
15
|
+
"poet",
|
|
16
|
+
"cli"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public",
|
|
21
|
+
"registry": "https://registry.npmjs.org/"
|
|
22
|
+
},
|
|
23
|
+
"exports": "./bin/index.js",
|
|
24
|
+
"bin": {
|
|
25
|
+
"poet": "bin/index.js",
|
|
26
|
+
"poetora": "bin/index.js"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"dev": "pnpm build && NODE_NO_WARNINGS=1 node bin/index.js",
|
|
30
|
+
"build": "tsc --project tsconfig.build.json",
|
|
31
|
+
"clean:build": "rimraf bin",
|
|
32
|
+
"clean:all": "rimraf node_modules .eslintcache && pnpm clean:build",
|
|
33
|
+
"watch": "tsc --watch",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"type": "tsc --noEmit",
|
|
36
|
+
"format": "prettier . --write",
|
|
37
|
+
"format:check": "prettier . --check"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@inquirer/prompts": "7.9.0",
|
|
41
|
+
"@poetora/link-rot": "workspace:*",
|
|
42
|
+
"@poetora/prebuild": "workspace:*",
|
|
43
|
+
"@poetora/previewing": "workspace:*",
|
|
44
|
+
"@poetora/shared": "workspace:*",
|
|
45
|
+
"@poetora/validation": "workspace:*",
|
|
46
|
+
"adm-zip": "0.5.16",
|
|
47
|
+
"chalk": "5.2.0",
|
|
48
|
+
"color": "4.2.3",
|
|
49
|
+
"detect-port": "1.5.1",
|
|
50
|
+
"front-matter": "4.0.2",
|
|
51
|
+
"fs-extra": "11.2.0",
|
|
52
|
+
"ink": "6.3.0",
|
|
53
|
+
"inquirer": "12.3.0",
|
|
54
|
+
"js-yaml": "4.1.0",
|
|
55
|
+
"mdast-util-mdx-jsx": "3.2.0",
|
|
56
|
+
"react": "19.2.1",
|
|
57
|
+
"semver": "7.7.2",
|
|
58
|
+
"unist-util-visit": "5.0.0",
|
|
59
|
+
"yargs": "17.7.1"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@trivago/prettier-plugin-sort-imports": "4.3.0",
|
|
63
|
+
"@tsconfig/recommended": "1.0.2",
|
|
64
|
+
"@types/adm-zip": "0.5.7",
|
|
65
|
+
"@types/color": "^3.0.3",
|
|
66
|
+
"@types/detect-port": "1.3.2",
|
|
67
|
+
"@types/fs-extra": "^9.0.13",
|
|
68
|
+
"@types/js-yaml": "^4.0.9",
|
|
69
|
+
"@types/mdast": "4.0.4",
|
|
70
|
+
"@types/node": "catalog:",
|
|
71
|
+
"@types/yargs": "17.0.22",
|
|
72
|
+
"@typescript-eslint/eslint-plugin": "catalog:",
|
|
73
|
+
"@typescript-eslint/parser": "catalog:",
|
|
74
|
+
"eslint": "catalog:",
|
|
75
|
+
"eslint-config-prettier": "catalog:",
|
|
76
|
+
"openapi-types": "12.1.3",
|
|
77
|
+
"prettier": "3.1.1",
|
|
78
|
+
"rimraf": "5.0.1",
|
|
79
|
+
"typescript": "catalog:",
|
|
80
|
+
"vitest": "catalog:",
|
|
81
|
+
"vitest-mock-process": "1.0.4"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import Color from 'color';
|
|
2
|
+
|
|
3
|
+
export const WCAG_STANDARDS = {
|
|
4
|
+
AA_NORMAL: 4.5,
|
|
5
|
+
AA_LARGE: 3,
|
|
6
|
+
AAA_NORMAL: 7,
|
|
7
|
+
AAA_LARGE: 4.5,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export type ContrastResult = {
|
|
11
|
+
ratio: number;
|
|
12
|
+
meetsAA: boolean;
|
|
13
|
+
meetsAAA: boolean;
|
|
14
|
+
recommendation: 'pass' | 'warning' | 'fail';
|
|
15
|
+
message: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function checkColorContrast(
|
|
19
|
+
foreground: string,
|
|
20
|
+
background: string,
|
|
21
|
+
minThreshold: number = WCAG_STANDARDS.AA_NORMAL
|
|
22
|
+
): ContrastResult | null {
|
|
23
|
+
try {
|
|
24
|
+
const fg = Color(foreground);
|
|
25
|
+
const bg = Color(background);
|
|
26
|
+
|
|
27
|
+
const ratio = fg.contrast(bg);
|
|
28
|
+
const level = fg.level(bg);
|
|
29
|
+
|
|
30
|
+
const meetsAA = level === 'AA' || level === 'AAA';
|
|
31
|
+
const meetsAAA = level === 'AAA';
|
|
32
|
+
|
|
33
|
+
let recommendation: 'pass' | 'warning' | 'fail';
|
|
34
|
+
let message: string;
|
|
35
|
+
|
|
36
|
+
if (minThreshold !== WCAG_STANDARDS.AA_NORMAL) {
|
|
37
|
+
if (ratio >= minThreshold) {
|
|
38
|
+
recommendation = 'pass';
|
|
39
|
+
message = `Contrast ratio: ${ratio.toFixed(
|
|
40
|
+
2
|
|
41
|
+
)}:1 (meets minimum threshold of ${minThreshold}:1)`;
|
|
42
|
+
} else {
|
|
43
|
+
recommendation = 'fail';
|
|
44
|
+
message = `Poor contrast ratio: ${ratio.toFixed(
|
|
45
|
+
2
|
|
46
|
+
)}:1 (fails minimum threshold, required: ${minThreshold}:1)`;
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
if (meetsAAA) {
|
|
50
|
+
recommendation = 'pass';
|
|
51
|
+
message = `Excellent contrast ratio: ${ratio.toFixed(2)}:1 (meets WCAG AAA)`;
|
|
52
|
+
} else if (meetsAA) {
|
|
53
|
+
recommendation = 'warning';
|
|
54
|
+
message = `Good contrast ratio: ${ratio.toFixed(
|
|
55
|
+
2
|
|
56
|
+
)}:1 (meets WCAG AA, consider AAA for better accessibility)`;
|
|
57
|
+
} else {
|
|
58
|
+
recommendation = 'fail';
|
|
59
|
+
message = `Poor contrast ratio: ${ratio.toFixed(2)}:1 (fails WCAG AA, minimum required: ${
|
|
60
|
+
WCAG_STANDARDS.AA_NORMAL
|
|
61
|
+
}:1)`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
ratio,
|
|
67
|
+
meetsAA,
|
|
68
|
+
meetsAAA,
|
|
69
|
+
recommendation,
|
|
70
|
+
message,
|
|
71
|
+
};
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface AccessibilityCheckResult {
|
|
78
|
+
primaryContrast: ContrastResult | null;
|
|
79
|
+
lightContrast: ContrastResult | null;
|
|
80
|
+
darkContrast: ContrastResult | null;
|
|
81
|
+
darkOnLightContrast: ContrastResult | null;
|
|
82
|
+
anchorResults: Array<{
|
|
83
|
+
name: string;
|
|
84
|
+
lightContrast: ContrastResult | null;
|
|
85
|
+
darkContrast: ContrastResult | null;
|
|
86
|
+
}>;
|
|
87
|
+
overallScore: 'pass' | 'warning' | 'fail';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function checkDocsColors(
|
|
91
|
+
colors: {
|
|
92
|
+
primary?: string;
|
|
93
|
+
light?: string;
|
|
94
|
+
dark?: string;
|
|
95
|
+
},
|
|
96
|
+
background: {
|
|
97
|
+
lightHex: string;
|
|
98
|
+
darkHex: string;
|
|
99
|
+
},
|
|
100
|
+
navigation?: {
|
|
101
|
+
global?: {
|
|
102
|
+
anchors?: Array<{
|
|
103
|
+
anchor: string;
|
|
104
|
+
color?: {
|
|
105
|
+
light?: string;
|
|
106
|
+
dark?: string;
|
|
107
|
+
};
|
|
108
|
+
}>;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
): AccessibilityCheckResult {
|
|
112
|
+
const lightBackground = background.lightHex;
|
|
113
|
+
const darkBackground = background.darkHex;
|
|
114
|
+
|
|
115
|
+
const primaryContrast = colors.primary
|
|
116
|
+
? checkColorContrast(colors.primary, lightBackground)
|
|
117
|
+
: null;
|
|
118
|
+
|
|
119
|
+
const lightContrast = colors.light ? checkColorContrast(colors.light, darkBackground) : null;
|
|
120
|
+
|
|
121
|
+
const darkContrast = colors.dark ? checkColorContrast(colors.dark, darkBackground, 3) : null;
|
|
122
|
+
|
|
123
|
+
const darkOnLightContrast = colors.dark
|
|
124
|
+
? checkColorContrast(colors.dark, lightBackground, 3)
|
|
125
|
+
: null;
|
|
126
|
+
|
|
127
|
+
const anchorResults: Array<{
|
|
128
|
+
name: string;
|
|
129
|
+
lightContrast: ContrastResult | null;
|
|
130
|
+
darkContrast: ContrastResult | null;
|
|
131
|
+
}> = [];
|
|
132
|
+
|
|
133
|
+
if (navigation?.global?.anchors) {
|
|
134
|
+
for (const anchor of navigation.global.anchors) {
|
|
135
|
+
if (anchor.color) {
|
|
136
|
+
const lightContrast = anchor.color.light
|
|
137
|
+
? checkColorContrast(anchor.color.light, lightBackground)
|
|
138
|
+
: null;
|
|
139
|
+
const darkContrast = anchor.color.dark
|
|
140
|
+
? checkColorContrast(anchor.color.dark, darkBackground)
|
|
141
|
+
: null;
|
|
142
|
+
|
|
143
|
+
anchorResults.push({
|
|
144
|
+
name: anchor.anchor,
|
|
145
|
+
lightContrast,
|
|
146
|
+
darkContrast,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const results = [
|
|
153
|
+
primaryContrast,
|
|
154
|
+
lightContrast,
|
|
155
|
+
darkContrast,
|
|
156
|
+
darkOnLightContrast,
|
|
157
|
+
...anchorResults.flatMap((anchor) => [anchor.lightContrast, anchor.darkContrast]),
|
|
158
|
+
].filter(Boolean);
|
|
159
|
+
|
|
160
|
+
const hasFailure = results.some((result) => result!.recommendation === 'fail');
|
|
161
|
+
const hasWarning = results.some((result) => result!.recommendation === 'warning');
|
|
162
|
+
|
|
163
|
+
let overallScore: 'pass' | 'warning' | 'fail';
|
|
164
|
+
if (hasFailure) {
|
|
165
|
+
overallScore = 'fail';
|
|
166
|
+
} else if (hasWarning) {
|
|
167
|
+
overallScore = 'warning';
|
|
168
|
+
} else {
|
|
169
|
+
overallScore = 'pass';
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
primaryContrast,
|
|
174
|
+
lightContrast,
|
|
175
|
+
darkContrast,
|
|
176
|
+
darkOnLightContrast,
|
|
177
|
+
anchorResults,
|
|
178
|
+
overallScore,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { getConfigObj, getConfigPath } from '@poetora/prebuild';
|
|
2
|
+
import { addLog, ErrorLog, WarningLog } from '@poetora/previewing';
|
|
3
|
+
import { getBackgroundColors } from '@poetora/shared';
|
|
4
|
+
import { Text } from 'ink';
|
|
5
|
+
|
|
6
|
+
import { checkDocsColors, type AccessibilityCheckResult } from './accessibility.js';
|
|
7
|
+
import { ContrastResult } from './accessibility.js';
|
|
8
|
+
import { CMD_EXEC_PATH } from './constants.js';
|
|
9
|
+
|
|
10
|
+
export type TerminateCode = 0 | 1;
|
|
11
|
+
|
|
12
|
+
export const accessibilityCheck = async (): Promise<TerminateCode> => {
|
|
13
|
+
try {
|
|
14
|
+
const docsConfigPath = await getConfigPath(CMD_EXEC_PATH);
|
|
15
|
+
|
|
16
|
+
if (!docsConfigPath) {
|
|
17
|
+
addLog(
|
|
18
|
+
<ErrorLog message="No configuration file found. Please run this command from a directory with a docs.json file." />
|
|
19
|
+
);
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const config = await getConfigObj(CMD_EXEC_PATH);
|
|
24
|
+
|
|
25
|
+
if (!config.colors) {
|
|
26
|
+
addLog(<WarningLog message="No colors section found in configuration file" />);
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { colors, navigation } = config;
|
|
31
|
+
|
|
32
|
+
const { lightHex, darkHex } = getBackgroundColors(config);
|
|
33
|
+
|
|
34
|
+
const results: AccessibilityCheckResult = checkDocsColors(
|
|
35
|
+
colors,
|
|
36
|
+
{ lightHex, darkHex },
|
|
37
|
+
navigation
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const displayContrastResult = (
|
|
41
|
+
result: ContrastResult | null,
|
|
42
|
+
label: string,
|
|
43
|
+
prefix: string = ''
|
|
44
|
+
) => {
|
|
45
|
+
if (!result) return;
|
|
46
|
+
|
|
47
|
+
const { recommendation, message } = result;
|
|
48
|
+
const icon =
|
|
49
|
+
recommendation === 'pass' ? 'PASS' : recommendation === 'warning' ? 'WARN' : 'FAIL';
|
|
50
|
+
const color =
|
|
51
|
+
recommendation === 'pass' ? 'green' : recommendation === 'warning' ? 'yellow' : 'red';
|
|
52
|
+
|
|
53
|
+
addLog(
|
|
54
|
+
<Text>
|
|
55
|
+
<Text bold={prefix === ''}>
|
|
56
|
+
{prefix}
|
|
57
|
+
{label}:{' '}
|
|
58
|
+
</Text>
|
|
59
|
+
<Text color={color}>
|
|
60
|
+
{icon} {message}
|
|
61
|
+
</Text>
|
|
62
|
+
</Text>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
addLog(
|
|
67
|
+
<Text bold color="cyan">
|
|
68
|
+
Checking color accessibility...
|
|
69
|
+
</Text>
|
|
70
|
+
);
|
|
71
|
+
addLog(<Text></Text>);
|
|
72
|
+
|
|
73
|
+
displayContrastResult(
|
|
74
|
+
results.primaryContrast,
|
|
75
|
+
`Primary Color (${colors.primary}) vs Light Background`
|
|
76
|
+
);
|
|
77
|
+
displayContrastResult(
|
|
78
|
+
results.lightContrast,
|
|
79
|
+
`Light Color (${colors.light}) vs Dark Background`
|
|
80
|
+
);
|
|
81
|
+
displayContrastResult(results.darkContrast, `Dark Color (${colors.dark}) vs Dark Background`);
|
|
82
|
+
displayContrastResult(
|
|
83
|
+
results.darkOnLightContrast,
|
|
84
|
+
`Dark Color (${colors.dark}) vs Light Background`
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const anchorsWithResults = results.anchorResults.filter(
|
|
88
|
+
(anchor) => anchor.lightContrast || anchor.darkContrast
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (anchorsWithResults.length > 0) {
|
|
92
|
+
addLog(<Text></Text>);
|
|
93
|
+
addLog(
|
|
94
|
+
<Text bold color="cyan">
|
|
95
|
+
Navigation Anchors:
|
|
96
|
+
</Text>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
for (const anchor of anchorsWithResults) {
|
|
100
|
+
addLog(<Text bold> {anchor.name}:</Text>);
|
|
101
|
+
displayContrastResult(anchor.lightContrast, 'Light variant vs Light Background', ' ');
|
|
102
|
+
displayContrastResult(anchor.darkContrast, 'Dark variant vs Dark Background', ' ');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
addLog(<Text></Text>);
|
|
107
|
+
const overallIcon =
|
|
108
|
+
results.overallScore === 'pass'
|
|
109
|
+
? 'PASS'
|
|
110
|
+
: results.overallScore === 'warning'
|
|
111
|
+
? 'WARN'
|
|
112
|
+
: 'FAIL';
|
|
113
|
+
const overallColor =
|
|
114
|
+
results.overallScore === 'pass'
|
|
115
|
+
? 'green'
|
|
116
|
+
: results.overallScore === 'warning'
|
|
117
|
+
? 'yellow'
|
|
118
|
+
: 'red';
|
|
119
|
+
const overallMessage =
|
|
120
|
+
results.overallScore === 'pass'
|
|
121
|
+
? 'All colors meet accessibility standards!'
|
|
122
|
+
: results.overallScore === 'warning'
|
|
123
|
+
? 'Some colors could be improved for better accessibility'
|
|
124
|
+
: 'Some colors fail accessibility standards and should be updated';
|
|
125
|
+
|
|
126
|
+
addLog(
|
|
127
|
+
<Text>
|
|
128
|
+
<Text bold color={overallColor}>
|
|
129
|
+
Overall Assessment: {overallIcon} {overallMessage}
|
|
130
|
+
</Text>
|
|
131
|
+
</Text>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
return results.overallScore === 'fail' ? 1 : 0;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
addLog(
|
|
137
|
+
<ErrorLog
|
|
138
|
+
message={`Accessibility check failed: ${
|
|
139
|
+
error instanceof Error ? error.message : 'Unknown error'
|
|
140
|
+
}`}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
return 1;
|
|
144
|
+
}
|
|
145
|
+
};
|