@mintlify/cli 4.0.1338 → 4.0.1340

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/cli",
3
- "version": "4.0.1338",
3
+ "version": "4.0.1340",
4
4
  "description": "The Mintlify CLI",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -33,7 +33,7 @@
33
33
  "scripts": {
34
34
  "dev": "yarn build && NODE_NO_WARNINGS=1 node bin/index.js",
35
35
  "prepare": "npm run build",
36
- "build": "tsc --project tsconfig.build.json",
36
+ "build": "tsc --project tsconfig.build.json && node scripts/bundle-converter.mjs",
37
37
  "clean:build": "rimraf bin",
38
38
  "clean:all": "rimraf node_modules .eslintcache && yarn clean:build",
39
39
  "watch": "tsc --watch",
@@ -46,7 +46,7 @@
46
46
  "dependencies": {
47
47
  "@inquirer/prompts": "7.9.0",
48
48
  "@mintlify/common": "1.0.1042",
49
- "@mintlify/link-rot": "3.0.1234",
49
+ "@mintlify/link-rot": "3.0.1235",
50
50
  "@mintlify/models": "0.0.343",
51
51
  "@mintlify/prebuild": "1.0.1190",
52
52
  "@mintlify/previewing": "4.0.1259",
@@ -64,9 +64,18 @@
64
64
  "open": "8.4.2",
65
65
  "openid-client": "6.8.2",
66
66
  "posthog-node": "5.17.2",
67
+ "prosemirror-model": "^1.25.0",
67
68
  "react": "19.2.3",
69
+ "remark": "^15.0.1",
70
+ "remark-frontmatter": "^5.0.0",
71
+ "remark-gfm": "^4.0.1",
72
+ "remark-math": "^6.0.0",
73
+ "remark-mdx": "^3.1.1",
74
+ "remark-stringify": "^11.0.0",
68
75
  "semver": "7.7.2",
76
+ "unified": "^11.0.5",
69
77
  "unist-util-visit": "5.0.0",
78
+ "yaml": "^2.8.3",
70
79
  "yargs": "17.7.1",
71
80
  "zod": "4.3.6"
72
81
  },
@@ -74,6 +83,7 @@
74
83
  "keytar": "7.9.0"
75
84
  },
76
85
  "devDependencies": {
86
+ "@mintlify/editor": "0.0.248",
77
87
  "@mintlify/ts-config": "2.0.2",
78
88
  "@tsconfig/recommended": "1.0.2",
79
89
  "@types/adm-zip": "0.5.7",
@@ -82,6 +92,7 @@
82
92
  "@types/mdast": "4.0.4",
83
93
  "@types/node": "18.15.0",
84
94
  "@types/yargs": "17.0.22",
95
+ "esbuild": "0.25.12",
85
96
  "openapi-types": "12.1.3",
86
97
  "oxfmt": "^0.51.0",
87
98
  "oxlint": "1.66.0",
@@ -92,5 +103,5 @@
92
103
  "vitest": "2.1.9",
93
104
  "vitest-mock-process": "1.0.4"
94
105
  },
95
- "gitHead": "d8790a8402b1fd3460e84c83d060de276a1cb163"
106
+ "gitHead": "a35c4acbb224d6bfb0155931033e6c0c51896dc7"
96
107
  }
@@ -0,0 +1,24 @@
1
+ import { build } from 'esbuild';
2
+ import { createRequire } from 'node:module';
3
+
4
+ const require = createRequire(import.meta.url);
5
+ const entry = require.resolve('@mintlify/editor/converter');
6
+
7
+ await build({
8
+ entryPoints: [entry],
9
+ outfile: 'bin/vendor/converter.js',
10
+ bundle: true,
11
+ format: 'esm',
12
+ platform: 'node',
13
+ target: 'node18',
14
+ external: [
15
+ '@mintlify/common',
16
+ '@mintlify/validation',
17
+ 'mdast-util-*',
18
+ 'prosemirror-*',
19
+ 'remark*',
20
+ 'unified',
21
+ 'unist-util-*',
22
+ 'yaml',
23
+ ],
24
+ });
package/src/cli.tsx CHANGED
@@ -24,6 +24,8 @@ import { setTelemetryEnabled } from './config.js';
24
24
  import { getConfigValue, setConfigValue, clearConfigValue } from './config.js';
25
25
  import { API_URL } from './constants.js';
26
26
  import { deslopHandler } from './deslop/index.js';
27
+ import { resolveExplicitFiles } from './deslop/resolveFiles.js';
28
+ import { formatHandler } from './format.js';
27
29
  import {
28
30
  CMD_EXEC_PATH,
29
31
  checkPort,
@@ -296,6 +298,11 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
296
298
  'Check for broken links',
297
299
  (yargs) =>
298
300
  yargs
301
+ .option('files', {
302
+ type: 'string',
303
+ array: true,
304
+ description: 'Files or globs to check (defaults to the whole site)',
305
+ })
299
306
  .option('check-anchors', {
300
307
  type: 'boolean',
301
308
  default: false,
@@ -315,19 +322,35 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
315
322
  type: 'boolean',
316
323
  default: false,
317
324
  description: 'also check that docs.json redirect destinations resolve to valid paths',
318
- }),
325
+ })
326
+ .example('mint broken-links --files introduction.mdx', 'Check a specific page')
327
+ .example('mint broken-links --files "guides/**/*.mdx"', 'Check pages matching a glob'),
319
328
  async (argv) => {
320
329
  await autoUpgradeIfNeeded();
321
330
  addLog(<SpinnerLog message="checking for broken links..." />);
322
331
  try {
332
+ const fileArgs = (argv.files ?? []).map(String).filter(Boolean);
333
+ const sourceFiles =
334
+ fileArgs.length > 0
335
+ ? new Set(
336
+ (await resolveExplicitFiles(CMD_EXEC_PATH, fileArgs)).map((file) =>
337
+ path.normalize(file)
338
+ )
339
+ )
340
+ : undefined;
323
341
  const graph = await buildGraph(undefined, {
324
342
  checkSnippets: argv['check-snippets'],
325
343
  });
326
344
  graph.precomputeFileResolutions();
327
345
 
328
- const brokenInternalLinks = graph.getBrokenInternalLinks({
329
- checkAnchors: argv['check-anchors'],
330
- });
346
+ const brokenInternalLinks = graph
347
+ .getBrokenInternalLinks({
348
+ checkAnchors: argv['check-anchors'],
349
+ })
350
+ .filter(
351
+ ({ relativeDir, filename }) =>
352
+ !sourceFiles || sourceFiles.has(path.join(relativeDir, filename))
353
+ );
331
354
 
332
355
  const brokenLinksByFile: Record<string, string[]> = {};
333
356
 
@@ -342,7 +365,10 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
342
365
  });
343
366
 
344
367
  if (argv['check-external']) {
345
- const brokenExternalLinks = await getBrokenExternalLinks(graph);
368
+ const brokenExternalLinks = await getBrokenExternalLinks(
369
+ graph,
370
+ sourceFiles ? { sourceFiles } : undefined
371
+ );
346
372
  for (const result of brokenExternalLinks) {
347
373
  for (const source of result.sources) {
348
374
  const label = result.status
@@ -711,6 +737,15 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
711
737
  ),
712
738
  deslopHandler
713
739
  )
740
+ .command(
741
+ 'format',
742
+ 'Format MDX files in the current directory',
743
+ (yargs) =>
744
+ yargs
745
+ .usage('usage: mint format')
746
+ .example('mint format', 'format all MDX files in the current directory'),
747
+ formatHandler
748
+ )
714
749
  // Coming soon commands — visible in help, tracked via telemetry to gauge interest.
715
750
  .command(
716
751
  'ai',
package/src/format.tsx ADDED
@@ -0,0 +1,67 @@
1
+ import { isMintIgnored, processMintIgnoreString } from '@mintlify/common';
2
+ import { getMintIgnore } from '@mintlify/prebuild';
3
+ import { addLog, ErrorLog, SuccessLog } from '@mintlify/previewing';
4
+ import fs from 'node:fs/promises';
5
+ import path from 'node:path';
6
+
7
+ import { CMD_EXEC_PATH, terminate } from './helpers.js';
8
+
9
+ async function getGitIgnore(): Promise<string[]> {
10
+ try {
11
+ const content = await fs.readFile(path.join(CMD_EXEC_PATH, '.gitignore'), 'utf-8');
12
+ return processMintIgnoreString(content);
13
+ } catch {
14
+ return [];
15
+ }
16
+ }
17
+
18
+ async function* walk(dir: string, ignores: string[]): AsyncGenerator<string> {
19
+ const entries = await fs.readdir(dir, { withFileTypes: true });
20
+ for (const entry of entries) {
21
+ const full = path.join(dir, entry.name);
22
+ const relative = path.relative(CMD_EXEC_PATH, full).split(path.sep).join('/');
23
+ if (entry.isDirectory()) {
24
+ if (isMintIgnored(`${relative}/`, ignores)) continue;
25
+ yield* walk(full, ignores);
26
+ } else if (entry.name.endsWith('.mdx')) {
27
+ if (isMintIgnored(relative, ignores)) continue;
28
+ yield full;
29
+ }
30
+ }
31
+ }
32
+
33
+ export const formatHandler = async (): Promise<void> => {
34
+ const { mdxToPm, pmToMdx } = await import('./vendor/converter.js');
35
+ const ignores = [...(await getGitIgnore()), ...(await getMintIgnore(CMD_EXEC_PATH))];
36
+ let total = 0;
37
+ let changed = 0;
38
+ let failed = 0;
39
+
40
+ for await (const file of walk(CMD_EXEC_PATH, ignores)) {
41
+ total++;
42
+ const relative = path.relative(CMD_EXEC_PATH, file);
43
+ try {
44
+ const raw = await fs.readFile(file, 'utf-8');
45
+ const { doc, frontmatter } = mdxToPm(raw, { singleDollarTextMath: false });
46
+ const formatted = `${pmToMdx(doc, { frontmatter })}\n`;
47
+ if (formatted !== raw) {
48
+ await fs.writeFile(file, formatted);
49
+ changed++;
50
+ }
51
+ } catch (error) {
52
+ failed++;
53
+ addLog(
54
+ <ErrorLog
55
+ message={`${relative}: ${error instanceof Error ? error.message : 'unknown error'}`}
56
+ />
57
+ );
58
+ }
59
+ }
60
+
61
+ addLog(
62
+ <SuccessLog
63
+ message={`formatted ${changed} of ${total} mdx file${total === 1 ? '' : 's'}${failed > 0 ? ` (${failed} failed)` : ''}`}
64
+ />
65
+ );
66
+ await terminate(failed > 0 ? 1 : 0);
67
+ };
@@ -0,0 +1 @@
1
+ export * from '@mintlify/editor/converter';