@mintlify/cli 4.0.737 → 4.0.738

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,97 @@
1
+ import Color from 'color';
2
+ export const WCAG_STANDARDS = {
3
+ AA_NORMAL: 4.5,
4
+ AA_LARGE: 3,
5
+ AAA_NORMAL: 7,
6
+ AAA_LARGE: 4.5,
7
+ };
8
+ export function checkColorContrast(foreground, background) {
9
+ try {
10
+ const fg = Color(foreground);
11
+ const bg = Color(background);
12
+ const ratio = fg.contrast(bg);
13
+ const level = fg.level(bg);
14
+ const meetsAA = level === 'AA' || level === 'AAA';
15
+ const meetsAAA = level === 'AAA';
16
+ let recommendation;
17
+ let message;
18
+ if (meetsAAA) {
19
+ recommendation = 'pass';
20
+ message = `Excellent contrast ratio: ${ratio.toFixed(2)}:1 (meets WCAG AAA)`;
21
+ }
22
+ else if (meetsAA) {
23
+ recommendation = 'warning';
24
+ message = `Good contrast ratio: ${ratio.toFixed(2)}:1 (meets WCAG AA, consider AAA for better accessibility)`;
25
+ }
26
+ else {
27
+ recommendation = 'fail';
28
+ message = `Poor contrast ratio: ${ratio.toFixed(2)}:1 (fails WCAG AA, minimum required: ${WCAG_STANDARDS.AA_NORMAL}:1)`;
29
+ }
30
+ return {
31
+ ratio,
32
+ meetsAA,
33
+ meetsAAA,
34
+ recommendation,
35
+ message,
36
+ };
37
+ }
38
+ catch (_a) {
39
+ return null;
40
+ }
41
+ }
42
+ export function checkDocsColors(colors, background, navigation) {
43
+ var _a;
44
+ const lightBackground = background.lightHex;
45
+ const darkBackground = background.darkHex;
46
+ const primaryContrast = colors.primary
47
+ ? checkColorContrast(colors.primary, lightBackground)
48
+ : null;
49
+ const lightContrast = colors.light ? checkColorContrast(colors.light, darkBackground) : null;
50
+ const darkContrast = colors.dark ? checkColorContrast(colors.dark, darkBackground) : null;
51
+ const darkOnLightContrast = colors.dark ? checkColorContrast(colors.dark, lightBackground) : null;
52
+ const anchorResults = [];
53
+ if ((_a = navigation === null || navigation === void 0 ? void 0 : navigation.global) === null || _a === void 0 ? void 0 : _a.anchors) {
54
+ for (const anchor of navigation.global.anchors) {
55
+ if (anchor.color) {
56
+ const lightContrast = anchor.color.light
57
+ ? checkColorContrast(anchor.color.light, lightBackground)
58
+ : null;
59
+ const darkContrast = anchor.color.dark
60
+ ? checkColorContrast(anchor.color.dark, darkBackground)
61
+ : null;
62
+ anchorResults.push({
63
+ name: anchor.anchor,
64
+ lightContrast,
65
+ darkContrast,
66
+ });
67
+ }
68
+ }
69
+ }
70
+ const results = [
71
+ primaryContrast,
72
+ lightContrast,
73
+ darkContrast,
74
+ darkOnLightContrast,
75
+ ...anchorResults.flatMap((anchor) => [anchor.lightContrast, anchor.darkContrast]),
76
+ ].filter(Boolean);
77
+ const hasFailure = results.some((result) => result.recommendation === 'fail');
78
+ const hasWarning = results.some((result) => result.recommendation === 'warning');
79
+ let overallScore;
80
+ if (hasFailure) {
81
+ overallScore = 'fail';
82
+ }
83
+ else if (hasWarning) {
84
+ overallScore = 'warning';
85
+ }
86
+ else {
87
+ overallScore = 'pass';
88
+ }
89
+ return {
90
+ primaryContrast,
91
+ lightContrast,
92
+ darkContrast,
93
+ darkOnLightContrast,
94
+ anchorResults,
95
+ overallScore,
96
+ };
97
+ }
@@ -0,0 +1,83 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ import { getBackgroundColors } from '@mintlify/common';
12
+ import { getConfigObj, getConfigPath } from '@mintlify/prebuild';
13
+ import { addLog, ErrorLog, WarningLog } from '@mintlify/previewing';
14
+ import { Text } from 'ink';
15
+ import { checkDocsColors } from './accessibility.js';
16
+ import { CMD_EXEC_PATH } from './constants.js';
17
+ import { checkForDocsJson } from './helpers.js';
18
+ export const accessibilityCheck = () => __awaiter(void 0, void 0, void 0, function* () {
19
+ try {
20
+ yield checkForDocsJson();
21
+ const docsConfigPath = yield getConfigPath(CMD_EXEC_PATH, 'docs');
22
+ const mintConfigPath = yield getConfigPath(CMD_EXEC_PATH, 'mint');
23
+ if (!docsConfigPath && !mintConfigPath) {
24
+ addLog(_jsx(ErrorLog, { message: "No configuration file found. Please run this command from a directory with a mint.json or docs.json file." }));
25
+ return 1;
26
+ }
27
+ const configType = docsConfigPath ? 'docs' : 'mint';
28
+ const config = yield getConfigObj(CMD_EXEC_PATH, configType);
29
+ if (!config.colors) {
30
+ addLog(_jsx(WarningLog, { message: "No colors section found in configuration file" }));
31
+ return 0;
32
+ }
33
+ const { colors, navigation } = config;
34
+ const { lightHex, darkHex } = getBackgroundColors(config);
35
+ const results = checkDocsColors(colors, { lightHex, darkHex }, navigation);
36
+ const displayContrastResult = (result, label, prefix = '') => {
37
+ if (!result)
38
+ return;
39
+ const { recommendation, message } = result;
40
+ const icon = recommendation === 'pass' ? 'PASS' : recommendation === 'warning' ? 'WARN' : 'FAIL';
41
+ const color = recommendation === 'pass' ? 'green' : recommendation === 'warning' ? 'yellow' : 'red';
42
+ addLog(_jsxs(Text, { children: [_jsxs(Text, { bold: prefix === '', children: [prefix, label, ":", ' '] }), _jsxs(Text, { color: color, children: [icon, " ", message] })] }));
43
+ };
44
+ addLog(_jsx(Text, { bold: true, color: "cyan", children: "Checking color accessibility..." }));
45
+ addLog(_jsx(Text, {}));
46
+ displayContrastResult(results.primaryContrast, `Primary Color (${colors.primary}) vs Light Background`);
47
+ displayContrastResult(results.lightContrast, `Light Color (${colors.light}) vs Dark Background`);
48
+ displayContrastResult(results.darkContrast, `Dark Color (${colors.dark}) vs Dark Background`);
49
+ displayContrastResult(results.darkOnLightContrast, `Dark Color (${colors.dark}) vs Light Background`);
50
+ const anchorsWithResults = results.anchorResults.filter((anchor) => anchor.lightContrast || anchor.darkContrast);
51
+ if (anchorsWithResults.length > 0) {
52
+ addLog(_jsx(Text, {}));
53
+ addLog(_jsx(Text, { bold: true, color: "cyan", children: "Navigation Anchors:" }));
54
+ for (const anchor of anchorsWithResults) {
55
+ addLog(_jsxs(Text, { bold: true, children: [" ", anchor.name, ":"] }));
56
+ displayContrastResult(anchor.lightContrast, 'Light variant vs Light Background', ' ');
57
+ displayContrastResult(anchor.darkContrast, 'Dark variant vs Dark Background', ' ');
58
+ }
59
+ }
60
+ addLog(_jsx(Text, {}));
61
+ const overallIcon = results.overallScore === 'pass'
62
+ ? 'PASS'
63
+ : results.overallScore === 'warning'
64
+ ? 'WARN'
65
+ : 'FAIL';
66
+ const overallColor = results.overallScore === 'pass'
67
+ ? 'green'
68
+ : results.overallScore === 'warning'
69
+ ? 'yellow'
70
+ : 'red';
71
+ const overallMessage = results.overallScore === 'pass'
72
+ ? 'All colors meet accessibility standards!'
73
+ : results.overallScore === 'warning'
74
+ ? 'Some colors could be improved for better accessibility'
75
+ : 'Some colors fail accessibility standards and should be updated';
76
+ addLog(_jsx(Text, { children: _jsxs(Text, { bold: true, color: overallColor, children: ["Overall Assessment: ", overallIcon, " ", overallMessage] }) }));
77
+ return results.overallScore === 'fail' ? 1 : 0;
78
+ }
79
+ catch (error) {
80
+ addLog(_jsx(ErrorLog, { message: `Accessibility check failed: ${error instanceof Error ? error.message : 'Unknown error'}` }));
81
+ return 1;
82
+ }
83
+ });
package/bin/cli.js CHANGED
@@ -15,6 +15,7 @@ import { render, Text } from 'ink';
15
15
  import path from 'path';
16
16
  import yargs from 'yargs';
17
17
  import { hideBin } from 'yargs/helpers';
18
+ import { accessibilityCheck } from './accessibilityCheck.js';
18
19
  import { checkPort, checkForMintJson, checkNodeVersion, upgradeConfig, checkForDocsJson, getVersions, suppressConsoleWarnings, terminate, readLocalOpenApiFile, } from './helpers.js';
19
20
  import { migrateMdx } from './migrateMdx.js';
20
21
  import { update } from './update.js';
@@ -171,6 +172,10 @@ export const cli = ({ packageName = 'mint' }) => {
171
172
  .command('migrate-mdx', 'migrate MDX OpenAPI endpoint pages to x-mint extensions and docs.json', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () {
172
173
  yield migrateMdx();
173
174
  yield terminate(0);
175
+ }))
176
+ .command('accessibility-check', false, () => undefined, () => __awaiter(void 0, void 0, void 0, function* () {
177
+ const terminateCode = yield accessibilityCheck();
178
+ yield terminate(terminateCode);
174
179
  }))
175
180
  .command(['version', 'v'], 'display the current version of the CLI and client', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () {
176
181
  const { cli, client } = getVersions();