@mintlify/cli 4.0.1741 → 4.0.1742

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.
@@ -21,6 +21,7 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  import { jsx as _jsx } from "react/jsx-runtime";
22
22
  import { addLog, checkBuild, clearLogs, ErrorLog, SpinnerLog } from '@mintlify/previewing';
23
23
  import path from 'node:path';
24
+ import { format } from 'node:util';
24
25
  import { CMD_EXEC_PATH, errorMessage, getVersions, terminate } from '../helpers.js';
25
26
  import { resolveExplicitFiles } from '../resolveFiles.js';
26
27
  import { sendPublishPrompt } from '../signup.js';
@@ -32,6 +33,26 @@ export const splitList = (values) => values.flatMap((value) => value
32
33
  .split(',')
33
34
  .map((item) => item.trim())
34
35
  .filter(Boolean));
36
+ const write = (text) => new Promise((resolve) => {
37
+ process.stdout.write(text, () => resolve());
38
+ });
39
+ /**
40
+ * Writes console output straight to stderr, so --format json leaves stdout to the report. Ink
41
+ * patches console and redraws on stdout, so redirecting to console.error isn't enough.
42
+ */
43
+ const consoleToStderr = () => {
44
+ const original = {
45
+ log: console.log,
46
+ info: console.info,
47
+ warn: console.warn,
48
+ error: console.error,
49
+ };
50
+ const toStderr = (...args) => {
51
+ process.stderr.write(`${format(...args)}\n`);
52
+ };
53
+ console.log = console.info = console.warn = console.error = toStderr;
54
+ return () => Object.assign(console, original);
55
+ };
35
56
  const resolveSelection = (baseDir, values) => __awaiter(void 0, void 0, void 0, function* () {
36
57
  const args = (values !== null && values !== void 0 ? values : []).map(String).filter(Boolean);
37
58
  if (args.length === 0)
@@ -42,13 +63,16 @@ const resolveSelection = (baseDir, values) => __awaiter(void 0, void 0, void 0,
42
63
  /** mint validate: one pass over every selected rule, then the strict build when nothing failed. */
43
64
  export const validateHandler = (argv_1, packageName_1, ...args_1) => __awaiter(void 0, [argv_1, packageName_1, ...args_1], void 0, function* (argv, packageName, baseDir = CMD_EXEC_PATH) {
44
65
  var _a;
66
+ const json = argv.format === 'json';
67
+ const restoreConsole = json ? consoleToStderr() : undefined;
45
68
  try {
46
69
  const rules = selectRules({
47
70
  enable: argv.enable,
48
71
  disable: (_a = argv.disable) !== null && _a !== void 0 ? _a : [],
49
72
  });
50
73
  const selected = yield resolveSelection(baseDir, argv.files);
51
- addLog(_jsx(SpinnerLog, { message: "validating..." }));
74
+ if (!json)
75
+ addLog(_jsx(SpinnerLog, { message: "validating..." }));
52
76
  const _b = yield checkSite(baseDir, rules, {
53
77
  selected,
54
78
  localSchema: argv['local-schema'],
@@ -67,7 +91,8 @@ export const validateHandler = (argv_1, packageName_1, ...args_1) => __awaiter(v
67
91
  build = { ran: false, reason: 'errors found' };
68
92
  }
69
93
  else {
70
- addLog(_jsx(SpinnerLog, { message: "building..." }));
94
+ if (!json)
95
+ addLog(_jsx(SpinnerLog, { message: "building..." }));
71
96
  const { cli: cliVersion } = getVersions(packageName);
72
97
  site.build = yield checkBuild(Object.assign(Object.assign({}, argv), { _: [], $0: packageName, packageName,
73
98
  cliVersion, disableOpenapi: !rules.some(({ group }) => group === 'openapi') }));
@@ -75,16 +100,28 @@ export const validateHandler = (argv_1, packageName_1, ...args_1) => __awaiter(v
75
100
  build = { ran: true, passed: site.build.passed };
76
101
  }
77
102
  const report = toReport(diagnostics, build, argv.fix ? fixed : undefined);
78
- clearLogs();
79
- logReport(report);
80
- if (report.passed && build.ran && build.passed)
81
- yield sendPublishPrompt();
103
+ if (json) {
104
+ restoreConsole === null || restoreConsole === void 0 ? void 0 : restoreConsole();
105
+ yield write(`${JSON.stringify(report)}\n`);
106
+ }
107
+ else {
108
+ clearLogs();
109
+ logReport(report);
110
+ if (report.passed && build.ran && build.passed)
111
+ yield sendPublishPrompt();
112
+ }
82
113
  yield terminate(report.passed ? EXIT.passed : EXIT.failed);
83
114
  }
84
115
  catch (error) {
85
116
  // Bad arguments and crashes alike mean validate could not run
86
- clearLogs();
87
- addLog(_jsx(ErrorLog, { message: errorMessage(error) }));
117
+ if (json) {
118
+ restoreConsole === null || restoreConsole === void 0 ? void 0 : restoreConsole();
119
+ process.stderr.write(`Error: ${errorMessage(error)}\n`);
120
+ }
121
+ else {
122
+ clearLogs();
123
+ addLog(_jsx(ErrorLog, { message: errorMessage(error) }));
124
+ }
88
125
  yield terminate(EXIT.crashed);
89
126
  }
90
127
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/cli",
3
- "version": "4.0.1741",
3
+ "version": "4.0.1742",
4
4
  "description": "The Mintlify CLI",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -46,11 +46,11 @@
46
46
  "dependencies": {
47
47
  "@inquirer/prompts": "7.9.0",
48
48
  "@mintlify/common": "1.0.1307",
49
- "@mintlify/link-rot": "3.0.1537",
49
+ "@mintlify/link-rot": "3.0.1538",
50
50
  "@mintlify/models": "0.0.379",
51
51
  "@mintlify/og": "0.0.106",
52
52
  "@mintlify/prebuild": "1.0.1474",
53
- "@mintlify/previewing": "4.0.1555",
53
+ "@mintlify/previewing": "4.0.1556",
54
54
  "@mintlify/validation": "0.1.944",
55
55
  "adm-zip": "0.6.0",
56
56
  "chalk": "5.2.0",
@@ -101,5 +101,5 @@
101
101
  "vitest": "2.1.9",
102
102
  "vitest-mock-process": "1.0.4"
103
103
  },
104
- "gitHead": "4e0cdb6a51f1b140f02f0579f9e4c32592220434"
104
+ "gitHead": "d186b90eab824aece48724f71d3b71f2cdebdbe2"
105
105
  }
package/src/cli.tsx CHANGED
@@ -406,6 +406,13 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
406
406
  default: false,
407
407
  description: 'Apply the fixes and check again',
408
408
  })
409
+ .option('format', {
410
+ type: 'string',
411
+ choices: ['text', 'json'] as const,
412
+ default: 'text' as const,
413
+ description:
414
+ 'Output format; json prints one report ({ passed, summary, diagnostics, build }) and nothing else on stdout, and errors to stderr',
415
+ })
409
416
  .usage('usage: mint validate [options]')
410
417
  .epilogue(
411
418
  [
@@ -415,6 +422,10 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
415
422
  ].join('\n')
416
423
  )
417
424
  .example('mint validate', 'run every check and the build')
425
+ .example(
426
+ 'mint validate --no-build --format json',
427
+ 'fast offline check for scripts and agents'
428
+ )
418
429
  .example(
419
430
  'mint validate --files "guides/**/*.mdx" --fix',
420
431
  'check some pages and apply fixes'
@@ -1,5 +1,6 @@
1
1
  import { addLog, checkBuild, clearLogs, ErrorLog, SpinnerLog } from '@mintlify/previewing';
2
2
  import path from 'node:path';
3
+ import { format } from 'node:util';
3
4
 
4
5
  import { CMD_EXEC_PATH, errorMessage, getVersions, terminate } from '../helpers.js';
5
6
  import { resolveExplicitFiles } from '../resolveFiles.js';
@@ -17,6 +18,7 @@ export type ValidateArgs = {
17
18
  enable?: string[];
18
19
  disable?: string[];
19
20
  fix: boolean;
21
+ format: 'text' | 'json';
20
22
  };
21
23
 
22
24
  export const EXIT = { passed: 0, failed: 1, crashed: 2 } as const;
@@ -29,6 +31,29 @@ export const splitList = (values: string[]) =>
29
31
  .filter(Boolean)
30
32
  );
31
33
 
34
+ const write = (text: string) =>
35
+ new Promise<void>((resolve) => {
36
+ process.stdout.write(text, () => resolve());
37
+ });
38
+
39
+ /**
40
+ * Writes console output straight to stderr, so --format json leaves stdout to the report. Ink
41
+ * patches console and redraws on stdout, so redirecting to console.error isn't enough.
42
+ */
43
+ const consoleToStderr = () => {
44
+ const original = {
45
+ log: console.log,
46
+ info: console.info,
47
+ warn: console.warn,
48
+ error: console.error,
49
+ };
50
+ const toStderr = (...args: unknown[]) => {
51
+ process.stderr.write(`${format(...args)}\n`);
52
+ };
53
+ console.log = console.info = console.warn = console.error = toStderr;
54
+ return () => Object.assign(console, original);
55
+ };
56
+
32
57
  const resolveSelection = async (baseDir: string, values: (string | number)[] | undefined) => {
33
58
  const args = (values ?? []).map(String).filter(Boolean);
34
59
  if (args.length === 0) return undefined;
@@ -46,13 +71,15 @@ export const validateHandler = async (
46
71
  packageName: string,
47
72
  baseDir = CMD_EXEC_PATH
48
73
  ) => {
74
+ const json = argv.format === 'json';
75
+ const restoreConsole = json ? consoleToStderr() : undefined;
49
76
  try {
50
77
  const rules = selectRules({
51
78
  enable: argv.enable,
52
79
  disable: argv.disable ?? [],
53
80
  });
54
81
  const selected = await resolveSelection(baseDir, argv.files);
55
- addLog(<SpinnerLog message="validating..." />);
82
+ if (!json) addLog(<SpinnerLog message="validating..." />);
56
83
 
57
84
  const { site, fixed, ...checked } = await checkSite(baseDir, rules, {
58
85
  selected,
@@ -70,7 +97,7 @@ export const validateHandler = async (
70
97
  } else if (diagnostics.some(({ severity }) => severity === 'error')) {
71
98
  build = { ran: false, reason: 'errors found' };
72
99
  } else {
73
- addLog(<SpinnerLog message="building..." />);
100
+ if (!json) addLog(<SpinnerLog message="building..." />);
74
101
  const { cli: cliVersion } = getVersions(packageName);
75
102
  site.build = await checkBuild({
76
103
  ...argv,
@@ -85,14 +112,24 @@ export const validateHandler = async (
85
112
  }
86
113
 
87
114
  const report = toReport(diagnostics, build, argv.fix ? fixed : undefined);
88
- clearLogs();
89
- logReport(report);
90
- if (report.passed && build.ran && build.passed) await sendPublishPrompt();
115
+ if (json) {
116
+ restoreConsole?.();
117
+ await write(`${JSON.stringify(report)}\n`);
118
+ } else {
119
+ clearLogs();
120
+ logReport(report);
121
+ if (report.passed && build.ran && build.passed) await sendPublishPrompt();
122
+ }
91
123
  await terminate(report.passed ? EXIT.passed : EXIT.failed);
92
124
  } catch (error) {
93
125
  // Bad arguments and crashes alike mean validate could not run
94
- clearLogs();
95
- addLog(<ErrorLog message={errorMessage(error)} />);
126
+ if (json) {
127
+ restoreConsole?.();
128
+ process.stderr.write(`Error: ${errorMessage(error)}\n`);
129
+ } else {
130
+ clearLogs();
131
+ addLog(<ErrorLog message={errorMessage(error)} />);
132
+ }
96
133
  await terminate(EXIT.crashed);
97
134
  }
98
135
  };