@mintlify/cli 4.0.1477 → 4.0.1479

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.1477",
3
+ "version": "4.0.1479",
4
4
  "description": "The Mintlify CLI",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -45,12 +45,12 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@inquirer/prompts": "7.9.0",
48
- "@mintlify/common": "1.0.1130",
49
- "@mintlify/link-rot": "3.0.1332",
50
- "@mintlify/models": "0.0.352",
51
- "@mintlify/prebuild": "1.0.1284",
52
- "@mintlify/previewing": "4.0.1356",
53
- "@mintlify/validation": "0.1.847",
48
+ "@mintlify/common": "1.0.1132",
49
+ "@mintlify/link-rot": "3.0.1334",
50
+ "@mintlify/models": "0.0.353",
51
+ "@mintlify/prebuild": "1.0.1286",
52
+ "@mintlify/previewing": "4.0.1358",
53
+ "@mintlify/validation": "0.1.849",
54
54
  "adm-zip": "0.6.0",
55
55
  "chalk": "5.2.0",
56
56
  "color": "4.2.3",
@@ -86,7 +86,7 @@
86
86
  "keytar": "7.9.0"
87
87
  },
88
88
  "devDependencies": {
89
- "@mintlify/editor": "0.0.361",
89
+ "@mintlify/editor": "0.0.363",
90
90
  "@mintlify/ts-config": "2.0.2",
91
91
  "@tsconfig/recommended": "1.0.2",
92
92
  "@types/detect-port": "1.3.2",
@@ -105,5 +105,5 @@
105
105
  "vitest": "2.1.9",
106
106
  "vitest-mock-process": "1.0.4"
107
107
  },
108
- "gitHead": "5af8270e14b6c226994968ae107b2513882b9729"
108
+ "gitHead": "64f3cb09194b3f7a7259c9a08c4e47b7454bf9e9"
109
109
  }
package/src/cli.tsx CHANGED
@@ -45,7 +45,11 @@ import { logout } from './logout.js';
45
45
  import { mdxLinter } from './mdxLinter.js';
46
46
  import { createTelemetryMiddleware } from './middlewares/telemetryMiddleware.js';
47
47
  import { mintTestHandler } from './mintTest.js';
48
- import { checkOpenApiFile, getOpenApiFilenamesFromDocsConfig } from './openApiCheck.js';
48
+ import {
49
+ buildOverlayRegistryForCheck,
50
+ checkOpenApiFile,
51
+ getOpenApiFilenamesFromDocsConfig,
52
+ } from './openApiCheck.js';
49
53
  import { resolveExplicitFiles } from './resolveFiles.js';
50
54
  import { scoreHandler } from './score/index.js';
51
55
  import { signup } from './signup.js';
@@ -225,8 +229,18 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
225
229
  openApiFilenames = getOpenApiFilenamesFromDocsConfig(JSON.parse(docsJson));
226
230
  } catch {}
227
231
 
232
+ let overlayRegistry;
233
+ try {
234
+ overlayRegistry = await buildOverlayRegistryForCheck(argv['local-schema']);
235
+ } catch (error) {
236
+ addLog(<ErrorLog message={error instanceof Error ? error.message : String(error)} />);
237
+ await terminate(1);
238
+ return;
239
+ }
228
240
  const results = await Promise.all(
229
- openApiFilenames.map((file) => checkOpenApiFile(file, argv['local-schema']))
241
+ openApiFilenames.map((file) =>
242
+ checkOpenApiFile(file, argv['local-schema'], overlayRegistry)
243
+ )
230
244
  );
231
245
 
232
246
  if (results.some((valid) => !valid)) {
@@ -308,7 +322,15 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
308
322
  addLog(
309
323
  <WarningLog message="openapi-check is deprecated, use `mintlify validate` instead" />
310
324
  );
311
- const valid = await checkOpenApiFile(filename, localSchema);
325
+ let overlayRegistry;
326
+ try {
327
+ overlayRegistry = await buildOverlayRegistryForCheck(localSchema);
328
+ } catch (error) {
329
+ addLog(<ErrorLog message={error instanceof Error ? error.message : String(error)} />);
330
+ await terminate(1);
331
+ return;
332
+ }
333
+ const valid = await checkOpenApiFile(filename, localSchema, overlayRegistry);
312
334
  await terminate(valid ? 0 : 1);
313
335
  }
314
336
  )
@@ -1,24 +1,75 @@
1
- import { validate, getOpenApiDocumentFromUrl, isAllowedLocalSchemaUrl } from '@mintlify/common';
1
+ import {
2
+ applyOverlays,
3
+ createOverlayRegistry,
4
+ getOpenApiDocumentFromUrl,
5
+ isAllowedLocalSchemaUrl,
6
+ resolveOverlaysForSpec,
7
+ validate,
8
+ type OverlayRegistry,
9
+ } from '@mintlify/common';
10
+ import { discoverOverlayFiles, getMintIgnore, resolveFileRefs } from '@mintlify/prebuild';
2
11
  import { addLog, ErrorLog, SuccessLog, WarningLog } from '@mintlify/previewing';
3
- import type { DocsConfig } from '@mintlify/validation';
12
+ import {
13
+ collectOpenApiOverlayConfig,
14
+ extractOpenApiEntries,
15
+ type DocsConfig,
16
+ } from '@mintlify/validation';
17
+ import { promises as fs } from 'fs';
18
+ import path from 'path';
4
19
 
5
- import { readLocalOpenApiFile } from './helpers.js';
20
+ import { CMD_EXEC_PATH, readLocalOpenApiFile } from './helpers.js';
6
21
 
7
22
  export const getOpenApiFilenamesFromDocsConfig = (config: Pick<DocsConfig, 'api'>): string[] => {
8
- const openapi = config.api?.openapi;
9
- if (openapi === undefined) return [];
10
- if (typeof openapi === 'string') return [openapi];
11
- if (Array.isArray(openapi)) return openapi;
12
- return [openapi.source];
23
+ return extractOpenApiEntries(config.api?.openapi).map((entry) => entry.source);
24
+ };
25
+
26
+ /**
27
+ * Builds the overlay registry so checks validate specs with overlays applied.
28
+ * Throws when docs.json configures conflicting overlay lists, matching the build.
29
+ */
30
+ export const buildOverlayRegistryForCheck = async (
31
+ localSchema?: boolean
32
+ ): Promise<OverlayRegistry | undefined> => {
33
+ // Discovery failures propagate and fail the check: silently skipping overlays would
34
+ // validate a different document than the one the build produces.
35
+ const mintIgnore = await getMintIgnore(CMD_EXEC_PATH);
36
+ const discovered = await discoverOverlayFiles(CMD_EXEC_PATH, mintIgnore);
37
+
38
+ let rawConfig: unknown;
39
+ try {
40
+ rawConfig = JSON.parse(await fs.readFile(path.join(CMD_EXEC_PATH, 'docs.json'), 'utf-8'));
41
+ } catch {
42
+ rawConfig = undefined;
43
+ }
44
+ if (rawConfig !== undefined) {
45
+ try {
46
+ rawConfig = (await resolveFileRefs(rawConfig, CMD_EXEC_PATH)).resolved;
47
+ } catch {
48
+ // Broken $refs are reported by regular config validation; collect from the root file.
49
+ }
50
+ }
51
+ const explicit = rawConfig == undefined ? undefined : collectOpenApiOverlayConfig(rawConfig);
52
+
53
+ if (explicit == undefined && discovered.length === 0) return undefined;
54
+
55
+ return createOverlayRegistry({
56
+ explicit,
57
+ discovered,
58
+ localSchema,
59
+ loadLocalDocument: (normalizedPath) => readLocalOpenApiFile(normalizedPath),
60
+ });
13
61
  };
14
62
 
15
63
  export const checkOpenApiFile = async (
16
64
  filename: string,
17
- localSchema: boolean
65
+ localSchema: boolean,
66
+ overlayRegistry?: OverlayRegistry
18
67
  ): Promise<boolean> => {
19
68
  try {
69
+ const overlays = overlayRegistry ? await resolveOverlaysForSpec(overlayRegistry, filename) : [];
70
+
20
71
  if (isAllowedLocalSchemaUrl(filename, localSchema)) {
21
- await getOpenApiDocumentFromUrl(filename);
72
+ await getOpenApiDocumentFromUrl(filename, { overlays });
22
73
  addLog(<SuccessLog message="OpenAPI definition is valid." />);
23
74
  return true;
24
75
  }
@@ -37,7 +88,11 @@ export const checkOpenApiFile = async (
37
88
  'failed to parse OpenAPI spec: could not parse file correctly, please check for any syntax errors.'
38
89
  );
39
90
  }
40
- await validate(document);
91
+ const overlaid: unknown = overlays.length > 0 ? applyOverlays(document, overlays) : document;
92
+ if (overlaid == undefined || typeof overlaid !== 'object') {
93
+ throw new Error('applying overlays produced an invalid OpenAPI document.');
94
+ }
95
+ await validate(overlaid);
41
96
  addLog(<SuccessLog message="OpenAPI definition is valid." />);
42
97
  return true;
43
98
  } catch (err) {