@mintlify/prebuild 1.0.316 → 1.0.318

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.
@@ -0,0 +1,93 @@
1
+ import { validateMintConfig, validateDocsConfig, formatIssue, } from '@mintlify/validation';
2
+ import Chalk from 'chalk';
3
+ import { promises as _promises } from 'fs';
4
+ import fse from 'fs-extra';
5
+ import { join } from 'path';
6
+ const { readFile } = _promises;
7
+ export class ConfigUpdater {
8
+ static getInstance(type) {
9
+ if (!ConfigUpdater.instances.has(type)) {
10
+ ConfigUpdater.instances.set(type, new ConfigUpdater(type));
11
+ }
12
+ return ConfigUpdater.instances.get(type);
13
+ }
14
+ constructor(type) {
15
+ this.validateMintConfigJson = async (configContents) => {
16
+ if (this.type !== 'mint') {
17
+ throw Error('validateMintConfigJson is only available for mint.json');
18
+ }
19
+ const configObj = this.parseConfigJson(configContents);
20
+ const validationResults = validateMintConfig(configObj);
21
+ if (!validationResults.success) {
22
+ console.error(Chalk.red(`🚨 Invalid ${this.type}.json:`));
23
+ validationResults.error.issues.forEach((issue) => console.error(Chalk.red(formatIssue(issue))));
24
+ throw Error();
25
+ }
26
+ if (validationResults.warnings.length > 0) {
27
+ if (validationResults.warnings.length > 0) {
28
+ console.warn(Chalk.yellow(`⚠️ Warnings found in ${this.type}.json:`));
29
+ validationResults.warnings.forEach((issue) => console.warn(Chalk.yellow(formatIssue(issue))));
30
+ }
31
+ }
32
+ return validationResults;
33
+ };
34
+ this.validateDocsConfigJson = async (configContents) => {
35
+ if (this.type !== 'docs') {
36
+ throw Error('validateDocsConfigJson is only available for docs.json');
37
+ }
38
+ const configObj = this.parseConfigJson(configContents);
39
+ const validationResults = validateDocsConfig(configObj);
40
+ if (!validationResults.success) {
41
+ console.error(Chalk.red(`🚨 Invalid ${this.type}.json:`));
42
+ validationResults.error.issues.forEach((issue) => console.error(Chalk.red(formatIssue(issue))));
43
+ throw Error();
44
+ }
45
+ return validationResults;
46
+ };
47
+ this.readConfigFile = async (configPath) => {
48
+ let configContents;
49
+ try {
50
+ configContents = await readFile(configPath, 'utf-8');
51
+ }
52
+ catch (err) {
53
+ throw Error(`Unable to read ${this.type}.json: ${err}`);
54
+ }
55
+ return configContents;
56
+ };
57
+ this.writeConfigFile = async (config, targetDir) => {
58
+ try {
59
+ await fse.outputFile(join(targetDir ?? '', `src/_props/${this.type}.json`), JSON.stringify(config, null, 2), {
60
+ flag: 'w',
61
+ });
62
+ }
63
+ catch (err) {
64
+ throw Error(`Unable to write ${this.type}.json: ${err}`);
65
+ }
66
+ };
67
+ this.parseConfigJson = (configContents) => {
68
+ let configObj;
69
+ try {
70
+ configObj = JSON.parse(configContents);
71
+ }
72
+ catch (e) {
73
+ if (typeof e === 'object' && e != null) {
74
+ if ('name' in e && e.name === 'SyntaxError') {
75
+ console.error(`🚨 ${Chalk.red(`${this.type}.json has invalid JSON. You are likely missing a comma or a bracket. You can paste your ${this.type}.json file into https://jsonlint.com/ to get a more specific error message.`)}`);
76
+ }
77
+ else if ('message' in e) {
78
+ console.error(`🚨 ${Chalk.red(e.message)}`);
79
+ }
80
+ }
81
+ throw Error();
82
+ }
83
+ return configObj;
84
+ };
85
+ this.type = type;
86
+ }
87
+ getConfigType() {
88
+ return this.type;
89
+ }
90
+ }
91
+ ConfigUpdater.instances = new Map();
92
+ export const MintConfigUpdater = ConfigUpdater.getInstance('mint');
93
+ export const DocsConfigUpdater = ConfigUpdater.getInstance('docs');
@@ -0,0 +1,15 @@
1
+ import type { OpenApiFile } from '@mintlify/models';
2
+ import { DecoratedPageConfig, DocsConfig, NavigationConfig } from '@mintlify/validation';
3
+ export declare const generateOpenApiDivisions: (docsConfig: DocsConfig, openApiFiles: OpenApiFile[], targetDir?: string) => Promise<{
4
+ newDocsConfig: DocsConfig;
5
+ pagesAcc: Record<string, DecoratedPageConfig>;
6
+ openApiFiles: OpenApiFile[];
7
+ }>;
8
+ export declare const generateOpenApiFromDocsConfig: (navigation: NavigationConfig, openApiFiles: OpenApiFile[], pagesAcc: Record<string, DecoratedPageConfig>, opts: {
9
+ overwrite?: boolean;
10
+ writeFiles: boolean;
11
+ targetDir?: string;
12
+ }) => Promise<{
13
+ newNav: NavigationConfig;
14
+ newOpenApiFiles: OpenApiFile[];
15
+ }>;
@@ -0,0 +1,129 @@
1
+ import { getOpenApiDocumentFromUrl, optionallyAddLeadingSlash } from '@mintlify/common';
2
+ import { generateOpenApiPagesForDocsConfig } from '@mintlify/scraping';
3
+ import { divisions, } from '@mintlify/validation';
4
+ import * as path from 'path';
5
+ import { getOpenApiFilesFromConfig } from '../read/getOpenApiFilesFromConfig.js';
6
+ const DEFAULT_OUTPUT_DIR = 'api-reference';
7
+ export const generateOpenApiDivisions = async (docsConfig, openApiFiles, targetDir) => {
8
+ const openapiFilesFromDocsConfig = await getOpenApiFilesFromConfig('docs', docsConfig);
9
+ openApiFiles.push(...openapiFilesFromDocsConfig);
10
+ const pagesAcc = {};
11
+ const { newNav, newOpenApiFiles } = await generateOpenApiFromDocsConfig(docsConfig.navigation, openApiFiles, pagesAcc, {
12
+ overwrite: true,
13
+ writeFiles: true,
14
+ targetDir,
15
+ });
16
+ return {
17
+ newDocsConfig: { ...docsConfig, navigation: newNav },
18
+ pagesAcc,
19
+ openApiFiles: [...openApiFiles, ...newOpenApiFiles],
20
+ };
21
+ };
22
+ export const generateOpenApiFromDocsConfig = async (navigation, openApiFiles, pagesAcc, opts) => {
23
+ const { overwrite, writeFiles, targetDir } = opts;
24
+ const newOpenApiFiles = [];
25
+ async function processOpenApiInNav(nav // we will need one of the divisions to be able to get the openapi param (type safety)
26
+ ) {
27
+ let outputDir = DEFAULT_OUTPUT_DIR;
28
+ let openapi;
29
+ if ('openapi' in nav) {
30
+ if (typeof nav.openapi === 'string') {
31
+ openapi = nav.openapi;
32
+ }
33
+ else if (typeof nav.openapi === 'object' && 'source' in nav.openapi) {
34
+ openapi = nav.openapi.source;
35
+ outputDir = nav.openapi.directory;
36
+ }
37
+ }
38
+ if (openapi) {
39
+ let openApiFile = undefined;
40
+ if (openapi.startsWith('https')) {
41
+ openApiFile = await createOpenApiFile(openapi, getDivisionNav(nav)?.division ?? 'unknown');
42
+ newOpenApiFiles.push(openApiFile);
43
+ }
44
+ else {
45
+ openApiFile = openApiFiles.find((file) => file.originalFileLocation != undefined &&
46
+ file.originalFileLocation === optionallyAddLeadingSlash(openapi));
47
+ }
48
+ if (!openApiFile) {
49
+ throw new Error(`Openapi file ${openapi} defined in ${getDivisionNav(nav)
50
+ ?.division} in your docs.json does not exist`);
51
+ }
52
+ const { pagesAcc: pagesAccFromGeneratedOpenApiPages, nav: navFromGeneratedOpenApiPages } = await generateOpenApiPagesForDocsConfig(openApiFile.spec, {
53
+ openApiFilePath: openApiFile.originalFileLocation,
54
+ writeFiles,
55
+ outDir: outputDir,
56
+ outDirBasePath: path.join(targetDir ?? '', 'src', '_props'),
57
+ overwrite,
58
+ });
59
+ Object.entries(pagesAccFromGeneratedOpenApiPages).forEach(([key, value]) => {
60
+ pagesAcc[key] = value;
61
+ });
62
+ const divisionNav = getDivisionNav(nav);
63
+ if (divisionNav?.division) {
64
+ return {
65
+ [divisionNav.division]: divisionNav.name,
66
+ groups: navFromGeneratedOpenApiPages,
67
+ ...divisionNav.nav,
68
+ };
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ async function processNav(nav) {
74
+ const processedNav = await processOpenApiInNav(nav);
75
+ if (processedNav) {
76
+ return processedNav;
77
+ }
78
+ let newNav = { ...nav };
79
+ for (const division of ['groups', ...divisions]) {
80
+ if (division in newNav) {
81
+ const items = newNav[division];
82
+ newNav = {
83
+ ...newNav,
84
+ [division]: (await Promise.all(items.map((item) => processNav(item)))),
85
+ };
86
+ }
87
+ }
88
+ return newNav;
89
+ }
90
+ const processedNavigation = await processNav(navigation);
91
+ navigation = processedNavigation;
92
+ return {
93
+ newNav: processedNavigation,
94
+ newOpenApiFiles,
95
+ };
96
+ };
97
+ function getDivisionNav(nav) {
98
+ if ('openapi' in nav) {
99
+ const { openapi: _, ...updatedNav } = nav;
100
+ const divisionMap = {
101
+ group: 'group',
102
+ anchor: 'anchor',
103
+ tab: 'tab',
104
+ version: 'version',
105
+ language: 'language',
106
+ dropdown: 'dropdown',
107
+ };
108
+ const divisionType = Object.keys(divisionMap).find((key) => key in updatedNav);
109
+ return {
110
+ division: divisionMap[divisionType],
111
+ name: updatedNav[divisionType],
112
+ nav: updatedNav,
113
+ };
114
+ }
115
+ return undefined;
116
+ }
117
+ async function createOpenApiFile(openApiUrl, division) {
118
+ try {
119
+ const document = await getOpenApiDocumentFromUrl(openApiUrl);
120
+ return {
121
+ filename: `openapi-from-${division}-1`,
122
+ spec: document,
123
+ };
124
+ }
125
+ catch (err) {
126
+ console.error(err);
127
+ throw err;
128
+ }
129
+ }