@mintlify/cli 4.0.1080 → 4.0.1081

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.1080",
3
+ "version": "4.0.1081",
4
4
  "description": "The Mintlify CLI",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -47,10 +47,8 @@
47
47
  "@inquirer/prompts": "7.9.0",
48
48
  "@mintlify/common": "1.0.832",
49
49
  "@mintlify/link-rot": "3.0.1005",
50
- "@mintlify/models": "0.0.287",
51
50
  "@mintlify/prebuild": "1.0.974",
52
51
  "@mintlify/previewing": "4.0.1033",
53
- "@mintlify/scraping": "4.0.696",
54
52
  "@mintlify/validation": "0.1.651",
55
53
  "adm-zip": "0.5.16",
56
54
  "chalk": "5.2.0",
@@ -95,5 +93,5 @@
95
93
  "vitest": "2.1.9",
96
94
  "vitest-mock-process": "1.0.4"
97
95
  },
98
- "gitHead": "1686b983ba34748f3685d0c91f1db11d0df500ea"
96
+ "gitHead": "5ae51fe99e6cdb06b0c0307a0f3f90026b2df180"
99
97
  }
package/src/cli.tsx CHANGED
@@ -1,8 +1,4 @@
1
- import {
2
- buildGraph,
3
- getBrokenExternalLinks,
4
- renameFilesAndUpdateLinksInContent,
5
- } from '@mintlify/link-rot';
1
+ import { buildGraph, getBrokenExternalLinks } from '@mintlify/link-rot';
6
2
  import {
7
3
  addLog,
8
4
  dev,
@@ -16,7 +12,6 @@ import {
16
12
  BrokenLinksLog,
17
13
  WarningLog,
18
14
  } from '@mintlify/previewing';
19
- import { checkUrl } from '@mintlify/scraping';
20
15
  import { render, Text } from 'ink';
21
16
  import fs from 'node:fs/promises';
22
17
  import path from 'path';
@@ -38,9 +33,7 @@ import { init } from './init.js';
38
33
  import { login } from './login.js';
39
34
  import { logout } from './logout.js';
40
35
  import { mdxLinter } from './mdxLinter.js';
41
- import { migrateMdx } from './migrateMdx.js';
42
36
  import { checkOpenApiFile, getOpenApiFilenamesFromDocsConfig } from './openApiCheck.js';
43
- import { scrapeSite, scrapePage, scrapeOpenApi } from './scrape.js';
44
37
  import { status } from './status.js';
45
38
  import { createTelemetryMiddleware } from './telemetry/middleware.js';
46
39
  import { trackTelemetryPreferenceChange } from './telemetry/track.js';
@@ -320,32 +313,6 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
320
313
  await terminate(1);
321
314
  }
322
315
  )
323
- .command(
324
- 'rename <from> <to>',
325
- 'rename a file and update all internal link references',
326
- (yargs) =>
327
- yargs
328
- .positional('from', {
329
- describe: 'the file to rename',
330
- type: 'string',
331
- })
332
- .positional('to', {
333
- describe: 'the new name for the file',
334
- type: 'string',
335
- })
336
- .demandOption(['from', 'to'])
337
- .option('force', {
338
- type: 'boolean',
339
- default: false,
340
- description: 'rename files and skip errors',
341
- })
342
- .epilog('example: `mintlify rename introduction.mdx overview.mdx`'),
343
- async ({ from, to, force }) => {
344
- await autoUpgradeIfNeeded();
345
- await renameFilesAndUpdateLinksInContent(from, to, force);
346
- await terminate(0);
347
- }
348
- )
349
316
  .command(
350
317
  'status',
351
318
  false,
@@ -382,15 +349,6 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
382
349
  await terminate(0);
383
350
  }
384
351
  )
385
- .command(
386
- 'migrate-mdx',
387
- 'migrate mdx openapi endpoint pages to x-mint extensions and docs.json',
388
- () => undefined,
389
- async () => {
390
- await migrateMdx();
391
- await terminate(0);
392
- }
393
- )
394
352
  .command(
395
353
  ['a11y', 'accessibility-check', 'a11y-check', 'accessibility'],
396
354
  'check for accessibility issues in documentation',
@@ -505,80 +463,6 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
505
463
  }
506
464
  }
507
465
  )
508
- .command('scrape', 'scrape documentation from external sites', (yargs) =>
509
- yargs
510
- .command(
511
- ['$0 <url>', 'site <url>'],
512
- 'scrape an entire documentation site',
513
- (yargs) =>
514
- yargs
515
- .positional('url', {
516
- describe: 'The URL of the documentation site to scrape',
517
- type: 'string',
518
- demandOption: true,
519
- })
520
- .option('filter', {
521
- describe:
522
- 'Only scrape URLs matching this path filter (e.g. /docs will match /docs and /docs/*)',
523
- type: 'string',
524
- alias: 'f',
525
- })
526
- .check(checkUrl),
527
- async ({ url, filter }) => {
528
- await scrapeSite(url, filter);
529
- }
530
- )
531
- .command(
532
- 'page <url>',
533
- 'scrape a single documentation page',
534
- (yargs) =>
535
- yargs
536
- .positional('url', {
537
- describe: 'The URL of the documentation page to scrape',
538
- type: 'string',
539
- demandOption: true,
540
- })
541
- .check(checkUrl),
542
- async ({ url }) => {
543
- await scrapePage(url);
544
- }
545
- )
546
- .command(
547
- 'openapi <openapiLocation>',
548
- 'generate mdx files from an openapi spec',
549
- (yargs) =>
550
- yargs
551
- .positional('openapiLocation', {
552
- describe: 'The filename or URL location of the OpenAPI spec',
553
- type: 'string',
554
- demandOption: true,
555
- })
556
- .option('writeFiles', {
557
- describe: 'Whether or not to write the frontmatter files',
558
- default: true,
559
- type: 'boolean',
560
- alias: 'w',
561
- })
562
- .option('outDir', {
563
- describe: 'The folder in which to write any created frontmatter files',
564
- type: 'string',
565
- alias: 'o',
566
- })
567
- .option('overwrite', {
568
- describe: 'Whether or not to overwrite existing files',
569
- default: false,
570
- type: 'boolean',
571
- }),
572
- async (argv) => {
573
- await scrapeOpenApi({
574
- openapiLocation: argv.openapiLocation,
575
- writeFiles: argv.writeFiles,
576
- outDir: argv.outDir,
577
- overwrite: argv.overwrite,
578
- });
579
- }
580
- )
581
- )
582
466
  // Print the help menu when the user enters an invalid command.
583
467
  .strictCommands()
584
468
  .demandCommand(1, 'unknown command. see above for the list of supported commands.')
@@ -1,236 +0,0 @@
1
- import { toPosixPath } from '@mintlify/common';
2
- import { getConfigObj, getConfigPath } from '@mintlify/prebuild';
3
- import * as previewing from '@mintlify/previewing';
4
- import { validateDocsConfig } from '@mintlify/validation';
5
- import fs from 'fs';
6
- import { outputFile } from 'fs-extra';
7
-
8
- import { migrateMdx } from '../src/migrateMdx.js';
9
-
10
- vi.mock('../src/constants.js', () => ({
11
- HOME_DIR: '/home/test-user',
12
- CMD_EXEC_PATH: '/project',
13
- }));
14
-
15
- vi.mock('@mintlify/prebuild', async () => {
16
- const original = await vi.importActual<typeof import('@mintlify/prebuild')>('@mintlify/prebuild');
17
- return {
18
- ...original,
19
- getConfigPath: vi.fn(),
20
- getConfigObj: vi.fn(),
21
- };
22
- });
23
-
24
- vi.mock('@mintlify/validation', async () => {
25
- const original =
26
- await vi.importActual<typeof import('@mintlify/validation')>('@mintlify/validation');
27
- return {
28
- ...original,
29
- validateDocsConfig: vi.fn(),
30
- };
31
- });
32
-
33
- vi.mock('fs-extra', () => ({
34
- outputFile: vi.fn(),
35
- }));
36
-
37
- const addLogSpy = vi.spyOn(previewing, 'addLog');
38
-
39
- describe('migrateMdx', () => {
40
- beforeEach(() => {
41
- vi.clearAllMocks();
42
- });
43
-
44
- const mkDirent = (name: string, isDir: boolean) =>
45
- ({ name, isDirectory: () => isDir, isFile: () => !isDir }) as unknown as fs.Dirent;
46
-
47
- const readdirSpy = vi.spyOn(fs.promises, 'readdir');
48
- readdirSpy.mockImplementation(async (p: Parameters<typeof fs.promises.readdir>[0]) => {
49
- const value = toPosixPath(
50
- typeof p === 'string' ? p : (p as unknown as { toString(): string }).toString()
51
- );
52
- if (value === '/project') {
53
- return [
54
- mkDirent('api', true),
55
- mkDirent('webhooks', true),
56
- mkDirent('openapi.json', false),
57
- mkDirent('openapi1.json', false),
58
- ];
59
- }
60
- if (value === '/project/api') {
61
- return [mkDirent('pets.mdx', false)];
62
- }
63
- if (value === '/project/webhooks') {
64
- return [mkDirent('newPet.mdx', false)];
65
- }
66
- return [] as unknown as fs.Dirent[];
67
- });
68
-
69
- it('logs and exits when docs.json is not found', async () => {
70
- vi.mocked(getConfigPath).mockResolvedValueOnce(undefined as unknown as string);
71
-
72
- await migrateMdx();
73
-
74
- expect(addLogSpy).toHaveBeenCalledWith(
75
- expect.objectContaining({ props: { message: 'docs.json not found in current directory' } })
76
- );
77
- });
78
-
79
- it('migrates a path operation MDX page to x-mint and updates docs.json and spec', async () => {
80
- vi.mocked(getConfigPath).mockResolvedValueOnce('/project/docs.json');
81
- vi.mocked(getConfigObj).mockResolvedValueOnce({
82
- navigation: {
83
- pages: ['api/pets'],
84
- },
85
- } as unknown as object);
86
- vi.mocked(validateDocsConfig).mockResolvedValueOnce({
87
- success: true,
88
- data: {
89
- navigation: {
90
- pages: ['api/pets'],
91
- },
92
- },
93
- } as unknown as ReturnType<typeof validateDocsConfig>);
94
-
95
- const existsSyncSpy = vi.spyOn(fs, 'existsSync');
96
- existsSyncSpy.mockImplementation((p: fs.PathLike) => {
97
- const value = toPosixPath(String(p));
98
- return value === '/project/api/pets.mdx' || value === 'openapi.json';
99
- });
100
-
101
- const readFileSpy = vi.spyOn(fs.promises, 'readFile');
102
- readFileSpy.mockImplementation(async (p: Parameters<typeof fs.promises.readFile>[0]) => {
103
- const value = toPosixPath(
104
- typeof p === 'string' ? p : (p as unknown as { toString(): string }).toString()
105
- );
106
- if (value === '/project/docs.json') {
107
- return JSON.stringify({ navigation: { pages: ['api/pets'] } });
108
- }
109
- if (value === '/project/api/pets.mdx') {
110
- return `---\nopenapi: openapi.json GET /pets\n---\n\n# Title\nContent`;
111
- }
112
- if (value === '/project/openapi.json') {
113
- return JSON.stringify({
114
- openapi: '3.0.0',
115
- info: { title: 'Test', version: '1.0.0' },
116
- paths: {
117
- '/pets': {
118
- get: {
119
- summary: 'List pets',
120
- responses: { '200': { description: 'ok' } },
121
- },
122
- },
123
- },
124
- });
125
- }
126
- throw new Error('Unexpected readFile path: ' + value);
127
- });
128
-
129
- const unlinkSpy = vi.spyOn(fs.promises, 'unlink').mockResolvedValueOnce();
130
-
131
- await migrateMdx();
132
-
133
- expect(addLogSpy).toHaveBeenCalledWith(
134
- expect.objectContaining({ props: { message: 'docs.json updated' } })
135
- );
136
-
137
- expect(outputFile).toHaveBeenCalledWith(
138
- '/project/docs.json',
139
- expect.stringContaining('openapi.json get /pets')
140
- );
141
-
142
- const specWriteCall = vi
143
- .mocked(outputFile)
144
- .mock.calls.find(
145
- (c) => typeof c[0] === 'string' && (c[0] as string).includes('openapi.json')
146
- );
147
- expect(specWriteCall).toBeTruthy();
148
- const writtenSpec = JSON.parse(specWriteCall?.[1] as string);
149
- expect(writtenSpec.paths['/pets'].get['x-mint']).toEqual(
150
- expect.objectContaining({ href: '/api/pets' })
151
- );
152
-
153
- expect(
154
- unlinkSpy.mock.calls.some((c) => toPosixPath(c[0] as string) === '/project/api/pets.mdx')
155
- ).toBe(true);
156
-
157
- expect(addLogSpy).toHaveBeenCalledWith(
158
- expect.objectContaining({ props: { message: 'migration complete' } })
159
- );
160
- });
161
-
162
- it('migrates a webhook MDX page to x-mint on the webhook operation', async () => {
163
- vi.mocked(getConfigPath).mockResolvedValueOnce('/project/docs.json');
164
- vi.mocked(getConfigObj).mockResolvedValueOnce({
165
- navigation: {
166
- pages: ['webhooks/newPet'],
167
- },
168
- } as unknown as object);
169
- vi.mocked(validateDocsConfig).mockResolvedValueOnce({
170
- success: true,
171
- data: {
172
- navigation: {
173
- pages: ['webhooks/newPet'],
174
- },
175
- },
176
- } as unknown as ReturnType<typeof validateDocsConfig>);
177
-
178
- const existsSyncSpy = vi.spyOn(fs, 'existsSync');
179
- existsSyncSpy.mockImplementation((p: fs.PathLike) => {
180
- const value = toPosixPath(String(p));
181
- return value === '/project/webhooks/newPet.mdx' || value === 'openapi1.json';
182
- });
183
-
184
- const readFileSpy = vi.spyOn(fs.promises, 'readFile');
185
- readFileSpy.mockImplementation(async (p: Parameters<typeof fs.promises.readFile>[0]) => {
186
- const value = toPosixPath(
187
- typeof p === 'string' ? p : (p as unknown as { toString(): string }).toString()
188
- );
189
- if (value === '/project/docs.json') {
190
- return JSON.stringify({ navigation: { pages: ['webhooks/newPet'] } });
191
- }
192
- if (value === '/project/webhooks/newPet.mdx') {
193
- return `---\nopenapi: openapi1.json webhook newPet\n---\n\n# Webhook\nBody`;
194
- }
195
- if (value === '/project/openapi1.json') {
196
- return JSON.stringify({
197
- openapi: '3.1.0',
198
- info: { title: 'Test', version: '1.0.0' },
199
- webhooks: {
200
- newPet: {
201
- post: {
202
- summary: 'Webhook - new pet',
203
- requestBody: {},
204
- responses: { '200': { description: 'ok' } },
205
- },
206
- },
207
- },
208
- });
209
- }
210
- throw new Error('Unexpected readFile path: ' + value);
211
- });
212
-
213
- vi.spyOn(fs.promises, 'unlink').mockResolvedValueOnce();
214
-
215
- await migrateMdx();
216
-
217
- expect(addLogSpy).toHaveBeenCalledWith(
218
- expect.objectContaining({ props: { message: 'docs.json updated' } })
219
- );
220
-
221
- const specWriteCall = vi
222
- .mocked(outputFile)
223
- .mock.calls.find(
224
- (c) => typeof c[0] === 'string' && (c[0] as string).includes('openapi1.json')
225
- );
226
- expect(specWriteCall).toBeTruthy();
227
- const writtenSpec = JSON.parse(specWriteCall?.[1] as string);
228
- expect(writtenSpec.webhooks.newPet.post['x-mint']).toEqual(
229
- expect.objectContaining({ href: '/webhooks/newPet' })
230
- );
231
-
232
- expect(addLogSpy).toHaveBeenCalledWith(
233
- expect.objectContaining({ props: { message: 'migration complete' } })
234
- );
235
- });
236
- });