@mintlify/prebuild 1.0.1122 → 1.0.1124

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.
@@ -1,11 +1,12 @@
1
1
  export interface PrebuildResult {
2
2
  fileImportsMap: Map<string, Set<string>>;
3
3
  }
4
- export declare const prebuild: (contentDirectoryPath: string, { localSchema, groups, disableOpenApi, strict, }?: {
4
+ export declare const prebuild: (contentDirectoryPath: string, { localSchema, groups, disableOpenApi, strict, allowSourceRefs, }?: {
5
5
  localSchema?: boolean;
6
6
  groups?: string[];
7
7
  disableOpenApi?: boolean;
8
8
  strict?: boolean;
9
+ allowSourceRefs?: boolean;
9
10
  }) => Promise<PrebuildResult | undefined>;
10
11
  export * from './categorizeFilePaths.js';
11
12
  export * from './getOpenApiFiles.js';
@@ -3,7 +3,7 @@ import { categorizeFilePaths } from './categorizeFilePaths.js';
3
3
  import { warnInvalidSpecFiles } from './invalidSpecFiles.js';
4
4
  import { update } from './update/index.js';
5
5
  import { clearWarnings, checkStrictMode } from './warnings.js';
6
- export const prebuild = async (contentDirectoryPath, { localSchema, groups, disableOpenApi, strict, } = {}) => {
6
+ export const prebuild = async (contentDirectoryPath, { localSchema, groups, disableOpenApi, strict, allowSourceRefs, } = {}) => {
7
7
  if (process.env.IS_MULTI_TENANT === 'true') {
8
8
  console.log('Skipping prebuild in multi-tenant mode.');
9
9
  return;
@@ -32,6 +32,7 @@ export const prebuild = async (contentDirectoryPath, { localSchema, groups, disa
32
32
  disableOpenApi,
33
33
  strict,
34
34
  invalidSpecFiles,
35
+ allowSourceRefs,
35
36
  });
36
37
  // Deferred until after update so files that fail the build don't also warn
37
38
  warnInvalidSpecFiles(invalidSpecFiles);
@@ -1,10 +1,13 @@
1
1
  import { ConfigType } from '@mintlify/models';
2
+ type GetConfigOptions = {
3
+ allowSourceRefs?: boolean;
4
+ };
2
5
  export declare class ConfigUpdater<T> {
3
6
  private type;
4
7
  constructor(type: ConfigType);
5
8
  getConfigType(): "mint" | "docs";
6
- getConfig(configPath: string, strict?: boolean, contentDirectoryPath?: string, onError?: (message: string) => void): Promise<T>;
7
- validateConfigJsonString: (configContents: string, strict?: boolean, onError?: (message: string) => void) => Promise<{
9
+ getConfig(configPath: string, strict?: boolean, contentDirectoryPath?: string, onError?: (message: string) => void, options?: GetConfigOptions): Promise<T>;
10
+ validateConfigJsonString: (configContents: string, strict?: boolean, onError?: (message: string) => void, options?: GetConfigOptions) => Promise<{
8
11
  data: T;
9
12
  warnings: import("zod").ZodIssue[];
10
13
  success: true;
@@ -3469,3 +3472,4 @@ export declare const DocsConfigUpdater: ConfigUpdater<{
3469
3472
  instructions?: string | string[] | undefined;
3470
3473
  } | undefined;
3471
3474
  }>;
3475
+ export {};
@@ -1,18 +1,74 @@
1
- import { validateMintConfig, validateDocsConfig, formatIssue, } from '@mintlify/validation';
1
+ import { validateMintConfig, validateDocsConfig, validateSourceRefDocsConfig, formatIssue, } from '@mintlify/validation';
2
2
  import Chalk from 'chalk';
3
3
  import { promises as _promises } from 'fs';
4
4
  import { outputFile } from 'fs-extra';
5
5
  import { join } from 'path';
6
6
  import { resolveFileRefs } from '../resolveRefs.js';
7
7
  const { readFile } = _promises;
8
+ const strippedSourceRef = Symbol('strippedSourceRef');
9
+ function isSourceRef(value) {
10
+ return (typeof value === 'object' &&
11
+ value !== null &&
12
+ !Array.isArray(value) &&
13
+ typeof value.sourceRef === 'string');
14
+ }
15
+ function hasSourceRefs(value) {
16
+ if (Array.isArray(value)) {
17
+ return value.some(hasSourceRefs);
18
+ }
19
+ if (typeof value !== 'object' || value === null) {
20
+ return false;
21
+ }
22
+ if (isSourceRef(value)) {
23
+ return true;
24
+ }
25
+ return Object.values(value).some(hasSourceRefs);
26
+ }
27
+ function stripSourceRefsForLocalPreview(value) {
28
+ if (isSourceRef(value)) {
29
+ return strippedSourceRef;
30
+ }
31
+ if (Array.isArray(value)) {
32
+ return value
33
+ .map((entry) => stripSourceRefsForLocalPreview(entry))
34
+ .filter((entry) => entry !== strippedSourceRef);
35
+ }
36
+ if (typeof value !== 'object' || value === null) {
37
+ return value;
38
+ }
39
+ return Object.fromEntries(Object.entries(value)
40
+ .map(([key, entry]) => [key, stripSourceRefsForLocalPreview(entry)])
41
+ .filter(([, entry]) => entry !== strippedSourceRef));
42
+ }
8
43
  export class ConfigUpdater {
9
44
  constructor(type) {
10
- this.validateConfigJsonString = async (configContents, strict, onError) => {
45
+ this.validateConfigJsonString = async (configContents, strict, onError, options = {}) => {
11
46
  const configObj = this.parseConfigJson(configContents, onError);
12
- return this.validateConfigObj(configObj, strict, onError);
47
+ return this.validateConfigObj(configObj, strict, onError, options);
13
48
  };
14
- this.validateConfigObj = async (configObj, strict, onError) => {
15
- const validationResults = this.type === 'mint' ? validateMintConfig(configObj) : validateDocsConfig(configObj);
49
+ this.validateConfigObj = async (configObj, strict, onError, options = {}) => {
50
+ const hasSourceRefEntries = hasSourceRefs(configObj);
51
+ const allowSourceRefs = this.type === 'docs' && options.allowSourceRefs;
52
+ if (allowSourceRefs && hasSourceRefEntries) {
53
+ const sourceRefValidation = validateSourceRefDocsConfig(configObj);
54
+ if (!sourceRefValidation.success) {
55
+ const errorMsg = `🚨 Invalid ${this.type}.json:`;
56
+ const issues = sourceRefValidation.error.issues.map((issue) => formatIssue(issue));
57
+ if (onError) {
58
+ onError(errorMsg);
59
+ issues.forEach((issue) => onError(issue));
60
+ }
61
+ else {
62
+ console.error(Chalk.red(errorMsg));
63
+ issues.forEach((issue) => console.error(Chalk.red(issue)));
64
+ }
65
+ throw Error();
66
+ }
67
+ }
68
+ const validationInput = allowSourceRefs && hasSourceRefEntries
69
+ ? stripSourceRefsForLocalPreview(configObj)
70
+ : configObj;
71
+ const validationResults = this.type === 'mint' ? validateMintConfig(configObj) : validateDocsConfig(validationInput);
16
72
  if (!validationResults.success) {
17
73
  const errorMsg = `🚨 Invalid ${this.type}.json:`;
18
74
  const issues = validationResults.error.issues.map((issue) => formatIssue(issue));
@@ -26,6 +82,15 @@ export class ConfigUpdater {
26
82
  }
27
83
  throw Error();
28
84
  }
85
+ if (this.type === 'docs' && options.allowSourceRefs && hasSourceRefEntries) {
86
+ const warnMsg = '⚠️ sourceRef entries are resolved during multi-repository deployments and are omitted from local preview.';
87
+ if (onError) {
88
+ onError(warnMsg);
89
+ }
90
+ else {
91
+ console.warn(Chalk.yellow(warnMsg));
92
+ }
93
+ }
29
94
  if ('warnings' in validationResults && validationResults.warnings.length > 0) {
30
95
  const warnMsg = `⚠️ Warnings found in ${this.type}.json:`;
31
96
  const warnings = validationResults.warnings.map((issue) => formatIssue(issue));
@@ -98,7 +163,7 @@ export class ConfigUpdater {
98
163
  getConfigType() {
99
164
  return this.type;
100
165
  }
101
- async getConfig(configPath, strict, contentDirectoryPath, onError) {
166
+ async getConfig(configPath, strict, contentDirectoryPath, onError, options = {}) {
102
167
  const configContents = await this.readConfigFile(configPath);
103
168
  const configObj = this.parseConfigJson(configContents, onError);
104
169
  let resolvedObj = configObj;
@@ -115,7 +180,7 @@ export class ConfigUpdater {
115
180
  throw Error(msg);
116
181
  }
117
182
  }
118
- const { data: config } = await this.validateConfigObj(resolvedObj, strict, onError);
183
+ const { data: config } = await this.validateConfigObj(resolvedObj, strict, onError, options);
119
184
  return config;
120
185
  }
121
186
  }
@@ -2,7 +2,7 @@ import { AsyncAPIFile } from '@mintlify/common';
2
2
  import { OpenApiFile, DecoratedNavigationPage } from '@mintlify/models';
3
3
  import { DocsConfig } from '@mintlify/validation';
4
4
  import type { InvalidSpecFile } from '../../invalidSpecFiles.js';
5
- export declare function updateDocsConfigFile({ contentDirectoryPath, openApiFiles, asyncApiFiles, docsConfig, localSchema, disableOpenApi, strict, invalidSpecFiles, }: {
5
+ export declare function updateDocsConfigFile({ contentDirectoryPath, openApiFiles, asyncApiFiles, docsConfig, localSchema, disableOpenApi, strict, invalidSpecFiles, allowSourceRefs, }: {
6
6
  contentDirectoryPath: string;
7
7
  openApiFiles: OpenApiFile[];
8
8
  asyncApiFiles: AsyncAPIFile[];
@@ -11,6 +11,7 @@ export declare function updateDocsConfigFile({ contentDirectoryPath, openApiFile
11
11
  disableOpenApi?: boolean;
12
12
  strict?: boolean;
13
13
  invalidSpecFiles?: InvalidSpecFile[];
14
+ allowSourceRefs?: boolean;
14
15
  }): Promise<{
15
16
  docsConfig: DocsConfig;
16
17
  pagesAcc: Record<string, DecoratedNavigationPage>;
@@ -4,13 +4,15 @@ import { generateAsyncApiDivisions } from './generateAsyncApiDivisions.js';
4
4
  import { generateOpenApiDivisions } from './generateOpenApiDivisions.js';
5
5
  import { getCustomLanguages } from './getCustomLanguages.js';
6
6
  const NOT_CORRECT_PATH_ERROR = 'must be run in a directory where a docs.json file exists.';
7
- export async function updateDocsConfigFile({ contentDirectoryPath, openApiFiles, asyncApiFiles, docsConfig, localSchema, disableOpenApi, strict, invalidSpecFiles, }) {
7
+ export async function updateDocsConfigFile({ contentDirectoryPath, openApiFiles, asyncApiFiles, docsConfig, localSchema, disableOpenApi, strict, invalidSpecFiles, allowSourceRefs, }) {
8
8
  const configPath = await getConfigPath(contentDirectoryPath, 'docs');
9
9
  if (configPath == null && docsConfig == null) {
10
10
  throw Error(NOT_CORRECT_PATH_ERROR);
11
11
  }
12
12
  if (docsConfig == null && configPath) {
13
- docsConfig = await DocsConfigUpdater.getConfig(configPath, strict, contentDirectoryPath);
13
+ docsConfig = await DocsConfigUpdater.getConfig(configPath, strict, contentDirectoryPath, undefined, {
14
+ allowSourceRefs,
15
+ });
14
16
  }
15
17
  if (docsConfig == null) {
16
18
  throw Error(NOT_CORRECT_PATH_ERROR);
@@ -17,8 +17,9 @@ type UpdateArgs = {
17
17
  disableOpenApi?: boolean;
18
18
  strict?: boolean;
19
19
  invalidSpecFiles?: InvalidSpecFile[];
20
+ allowSourceRefs?: boolean;
20
21
  };
21
- export declare const update: ({ contentDirectoryPath, staticFilenames, openApiFiles, asyncApiFiles, contentFilenames, snippets, snippetV2Filenames, docsConfigPath, localSchema, groups, mintIgnore, disableOpenApi, strict, invalidSpecFiles, }: UpdateArgs) => Promise<{
22
+ export declare const update: ({ contentDirectoryPath, staticFilenames, openApiFiles, asyncApiFiles, contentFilenames, snippets, snippetV2Filenames, docsConfigPath, localSchema, groups, mintIgnore, disableOpenApi, strict, invalidSpecFiles, allowSourceRefs, }: UpdateArgs) => Promise<{
22
23
  name: string;
23
24
  $schema: string;
24
25
  theme: "mint";
@@ -12,7 +12,7 @@ import { writeAsyncApiFiles } from './write/writeAsyncApiFiles.js';
12
12
  import { writeFiles, writeFile } from './write/writeFiles.js';
13
13
  import { writeOpenApiData } from './write/writeOpenApiData.js';
14
14
  import { writeRssFiles } from './write/writeRssFiles.js';
15
- export const update = async ({ contentDirectoryPath, staticFilenames, openApiFiles, asyncApiFiles, contentFilenames, snippets, snippetV2Filenames, docsConfigPath, localSchema, groups, mintIgnore, disableOpenApi, strict, invalidSpecFiles, }) => {
15
+ export const update = async ({ contentDirectoryPath, staticFilenames, openApiFiles, asyncApiFiles, contentFilenames, snippets, snippetV2Filenames, docsConfigPath, localSchema, groups, mintIgnore, disableOpenApi, strict, invalidSpecFiles, allowSourceRefs, }) => {
16
16
  const mintConfigResult = await updateMintConfigFile(contentDirectoryPath, openApiFiles, localSchema, strict, invalidSpecFiles);
17
17
  // we used the original mint config without openapi pages injected
18
18
  // because we will do it in `updateDocsConfigFile`, this will avoid duplicated openapi pages
@@ -26,6 +26,7 @@ export const update = async ({ contentDirectoryPath, staticFilenames, openApiFil
26
26
  disableOpenApi,
27
27
  strict,
28
28
  invalidSpecFiles,
29
+ allowSourceRefs,
29
30
  });
30
31
  const pagePromises = readPageContents({
31
32
  contentDirectoryPath,