@mintlify/cli 4.0.1478 → 4.0.1480

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.
@@ -1331,11 +1331,7 @@ import remarkFrontmatter from "remark-frontmatter";
1331
1331
  import remarkGfm from "remark-gfm";
1332
1332
  import remarkMath from "remark-math";
1333
1333
  import remarkMdx from "remark-mdx";
1334
- function buildRemark(singleDollarTextMath) {
1335
- return remark().use(remarkMdx).use(remarkGfm).use(remarkFrontmatter, ["yaml", "toml"]).use(remarkMath, { singleDollarTextMath }).freeze();
1336
- }
1337
- var coreRemark = buildRemark(true);
1338
- var noSingleDollarTextMathRemark = buildRemark(false);
1334
+ var coreRemark = remark().use(remarkMdx).use(remarkGfm).use(remarkFrontmatter, ["yaml", "toml"]).use(remarkMath).freeze();
1339
1335
  function convertHtmlCommentsToJsx(mdx) {
1340
1336
  const parts = mdx.split(/(```[\s\S]*?```|~~~[\s\S]*?~~~)/);
1341
1337
  return parts.map((part, i) => i % 2 === 0 ? part.replace(/<!--([\s\S]*?)-->/g, (_m, c) => `{/* ${c} */}`) : part).join("");
@@ -1348,14 +1344,13 @@ function preprocessMdxSource(mdx, options = {}) {
1348
1344
  preprocessed: preprocessCustomHeadingIds(sanitized, { preserveOriginal: true })
1349
1345
  };
1350
1346
  }
1351
- function parsePreprocessedMdx(preprocessed, options = {}) {
1352
- const parser = options.singleDollarTextMath === false ? noSingleDollarTextMathRemark : coreRemark;
1353
- return parser().parse(preprocessed);
1347
+ function parsePreprocessedMdx(preprocessed) {
1348
+ return coreRemark().parse(preprocessed);
1354
1349
  }
1355
1350
  function mdxToMdast(mdx, options = {
1356
1351
  omitHtmlComments: true
1357
1352
  }) {
1358
- return parsePreprocessedMdx(preprocessMdxSource(mdx, options).preprocessed, options);
1353
+ return parsePreprocessedMdx(preprocessMdxSource(mdx, options).preprocessed);
1359
1354
  }
1360
1355
 
1361
1356
  // ../editor/dist/converter/parse/handlers/prompt.js
@@ -12266,7 +12261,7 @@ var Preserver = class _Preserver {
12266
12261
  const coords = SourceCoords.create(source, sanitized, preprocessed);
12267
12262
  if (!coords)
12268
12263
  return null;
12269
- const root = parsePreprocessedMdx(preprocessed, parseOptions);
12264
+ const root = parsePreprocessedMdx(preprocessed);
12270
12265
  const ser = Object.assign(Object.assign({}, serializerOptions), { removeTrailingNewline: true, hasReferenceDefinitions: hasReferenceDefinitions(doc) });
12271
12266
  return new _Preserver(doc, coords, root, parseOptions, ser);
12272
12267
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/cli",
3
- "version": "4.0.1478",
3
+ "version": "4.0.1480",
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.1131",
49
- "@mintlify/link-rot": "3.0.1333",
48
+ "@mintlify/common": "1.0.1132",
49
+ "@mintlify/link-rot": "3.0.1334",
50
50
  "@mintlify/models": "0.0.353",
51
- "@mintlify/prebuild": "1.0.1285",
52
- "@mintlify/previewing": "4.0.1357",
53
- "@mintlify/validation": "0.1.848",
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.362",
89
+ "@mintlify/editor": "0.0.364",
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": "1860a3818bea322e6f6500313f1d2695be7432ee"
108
+ "gitHead": "c1d033f6c135aa4e10b8ed049bde57698764563d"
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
  )
package/src/format.tsx CHANGED
@@ -45,7 +45,7 @@ export const formatHandler = async (): Promise<void> => {
45
45
  let formatted = raw;
46
46
  let originalFrontmatterKeys = 0;
47
47
  for (let pass = 0; pass < 3; pass++) {
48
- const { doc, frontmatter } = mdxToPm(formatted, { singleDollarTextMath: false });
48
+ const { doc, frontmatter } = mdxToPm(formatted);
49
49
  if (pass === 0) originalFrontmatterKeys = Object.keys(frontmatter).length;
50
50
  const next = `${pmToMdx(doc, { frontmatter, ...canonicalPmToMdxOptions })}\n`;
51
51
  if (next === formatted) break;
@@ -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) {