@mintlify/previewing 4.0.1256 → 4.0.1257
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/dist/__tests__/docs-config-cache.test.js +18 -2
- package/dist/__tests__/get-docs-state.test.d.ts +1 -0
- package/dist/__tests__/get-docs-state.test.js +70 -0
- package/dist/__tests__/referencedFiles.test.d.ts +1 -0
- package/dist/__tests__/referencedFiles.test.js +23 -0
- package/dist/local-preview/listener/docs-config-cache.d.ts +1 -0
- package/dist/local-preview/listener/docs-config-cache.js +7 -1
- package/dist/local-preview/listener/getDocsState.d.ts +4 -1
- package/dist/local-preview/listener/getDocsState.js +32 -20
- package/dist/local-preview/listener/index.d.ts +2 -0
- package/dist/local-preview/listener/index.js +27 -5
- package/dist/local-preview/listener/referencedFiles.d.ts +2 -0
- package/dist/local-preview/listener/referencedFiles.js +33 -4
- package/dist/local-preview/run.js +7 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { clearDocsConfigCaches, getDocsConfigApiHash, getDocsConfigNavigationHash, getVariablesHash, hasDocsConfigApiChanged, hasDocsConfigNavigationChanged, hasNavigationApiReference, hasDocsConfigVariablesChanged, updateDocsConfigHashCache, } from '../local-preview/listener/docs-config-cache.js';
|
|
2
|
+
import { clearDocsConfigCaches, getDocsConfigApiHash, getDocsConfigNavigationHash, getVariablesHash, hasDocsConfigApiChanged, hasDocsConfigNavigationChanged, hasNavigationApiReference, hadDocsConfigApiReference, hasDocsConfigVariablesChanged, updateDocsConfigHashCache, } from '../local-preview/listener/docs-config-cache.js';
|
|
3
3
|
const createDocsConfig = (page) => ({
|
|
4
4
|
$schema: 'https://mintlify.com/docs.json',
|
|
5
5
|
name: 'Mintlify',
|
|
@@ -33,7 +33,7 @@ describe('docsConfigCache', () => {
|
|
|
33
33
|
expect(hasDocsConfigNavigationChanged(getDocsConfigNavigationHash(createDocsConfig('new-page')))).toBe(true);
|
|
34
34
|
expect(hasDocsConfigVariablesChanged(getVariablesHash({ product: 'Mint' }))).toBe(true);
|
|
35
35
|
});
|
|
36
|
-
it('detects
|
|
36
|
+
it('detects API references anywhere in navigation', () => {
|
|
37
37
|
expect(hasNavigationApiReference({
|
|
38
38
|
groups: [
|
|
39
39
|
{
|
|
@@ -69,6 +69,14 @@ describe('docsConfigCache', () => {
|
|
|
69
69
|
},
|
|
70
70
|
],
|
|
71
71
|
})).toBe(true);
|
|
72
|
+
expect(hasNavigationApiReference({
|
|
73
|
+
tabs: [
|
|
74
|
+
{
|
|
75
|
+
tab: 'GraphQL',
|
|
76
|
+
graphql: { source: 'schema.graphql', directory: 'reference' },
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
})).toBe(true);
|
|
72
80
|
});
|
|
73
81
|
it('allows plain MDX navigation through the navigation fast path', () => {
|
|
74
82
|
expect(hasNavigationApiReference({
|
|
@@ -80,4 +88,12 @@ describe('docsConfigCache', () => {
|
|
|
80
88
|
],
|
|
81
89
|
})).toBe(false);
|
|
82
90
|
});
|
|
91
|
+
it('remembers API references so removing the last generated source triggers cleanup', () => {
|
|
92
|
+
const docsConfig = {
|
|
93
|
+
...createDocsConfig('raw-page'),
|
|
94
|
+
navigation: { tabs: [{ tab: 'GraphQL', graphql: 'schema.graphql' }] },
|
|
95
|
+
};
|
|
96
|
+
updateDocsConfigHashCache(docsConfig);
|
|
97
|
+
expect(hadDocsConfigApiReference()).toBe(true);
|
|
98
|
+
});
|
|
83
99
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { access, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { getDocsState } from '../local-preview/listener/getDocsState.js';
|
|
5
|
+
describe('getDocsState', () => {
|
|
6
|
+
let contentDirectory;
|
|
7
|
+
let clientDirectory;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
contentDirectory = await mkdtemp(path.join(os.tmpdir(), 'preview-content-'));
|
|
10
|
+
clientDirectory = await mkdtemp(path.join(os.tmpdir(), 'preview-client-'));
|
|
11
|
+
});
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
await Promise.all([
|
|
14
|
+
rm(contentDirectory, { recursive: true, force: true }),
|
|
15
|
+
rm(clientDirectory, { recursive: true, force: true }),
|
|
16
|
+
]);
|
|
17
|
+
});
|
|
18
|
+
it('rejects case-insensitive GraphQL and AsyncAPI collisions before overwriting either page', async () => {
|
|
19
|
+
await writeFile(path.join(contentDirectory, 'schema.graphql'), 'type Query { ping: String }');
|
|
20
|
+
await writeFile(path.join(contentDirectory, 'asyncapi.json'), JSON.stringify({
|
|
21
|
+
asyncapi: '3.0.0',
|
|
22
|
+
info: { title: 'Events', version: '1.0.0' },
|
|
23
|
+
channels: {
|
|
24
|
+
ping: {
|
|
25
|
+
address: 'ping',
|
|
26
|
+
tags: [{ name: 'Queries' }],
|
|
27
|
+
messages: { ping: { payload: { type: 'string' } } },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
operations: {
|
|
31
|
+
ping: {
|
|
32
|
+
action: 'send',
|
|
33
|
+
channel: { $ref: '#/channels/ping' },
|
|
34
|
+
messages: [{ $ref: '#/channels/ping/messages/ping' }],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
}));
|
|
38
|
+
await writeFile(path.join(contentDirectory, 'docs.json'), JSON.stringify({
|
|
39
|
+
theme: 'mint',
|
|
40
|
+
name: 'Preview collision',
|
|
41
|
+
colors: { primary: '#000000' },
|
|
42
|
+
navigation: {
|
|
43
|
+
tabs: [
|
|
44
|
+
{
|
|
45
|
+
tab: 'GraphQL',
|
|
46
|
+
graphql: { source: 'schema.graphql', directory: 'API' },
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
tab: 'AsyncAPI',
|
|
50
|
+
asyncapi: { source: 'asyncapi.json', directory: 'api' },
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
}));
|
|
55
|
+
const graphqlPath = path.join(clientDirectory, 'src/_props/API/queries/ping.mdx');
|
|
56
|
+
const asyncApiPath = path.join(clientDirectory, 'src/_props/api/queries/ping.mdx');
|
|
57
|
+
await Promise.all([
|
|
58
|
+
mkdir(path.dirname(graphqlPath), { recursive: true }),
|
|
59
|
+
mkdir(path.dirname(asyncApiPath), { recursive: true }),
|
|
60
|
+
]);
|
|
61
|
+
await Promise.all([
|
|
62
|
+
writeFile(graphqlPath, 'existing page'),
|
|
63
|
+
writeFile(asyncApiPath, 'existing page'),
|
|
64
|
+
]);
|
|
65
|
+
await expect(getDocsState(undefined, { contentDirectory, clientDirectory })).rejects.toThrow('Generated GraphQL route');
|
|
66
|
+
await expect(readFile(graphqlPath, 'utf8')).resolves.toBe('existing page');
|
|
67
|
+
await expect(readFile(asyncApiPath, 'utf8')).resolves.toBe('existing page');
|
|
68
|
+
await expect(access(path.join(clientDirectory, 'src/_props/graphql-data.json'))).rejects.toMatchObject({ code: 'ENOENT' });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { getLocalGraphqlSources, shouldRegenerateGraphqlSource, } from '../local-preview/listener/referencedFiles.js';
|
|
3
|
+
describe('getLocalGraphqlSources', () => {
|
|
4
|
+
it('tracks configured local schema paths regardless of extension', () => {
|
|
5
|
+
expect(getLocalGraphqlSources({
|
|
6
|
+
navigation: {
|
|
7
|
+
tabs: [
|
|
8
|
+
{
|
|
9
|
+
tab: 'API',
|
|
10
|
+
graphql: { source: '/schemas/./nested/../schema.custom', directory: 'api' },
|
|
11
|
+
},
|
|
12
|
+
{ tab: 'Remote', graphql: 'HTTPS://example.com/schema.graphql' },
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
})).toEqual([path.normalize('schemas/schema.custom')]);
|
|
16
|
+
});
|
|
17
|
+
it('rebuilds only configured GraphQL sources', () => {
|
|
18
|
+
const configuredSources = new Set([path.normalize('schemas/schema.custom')]);
|
|
19
|
+
expect(shouldRegenerateGraphqlSource('/schemas/./schema.custom', configuredSources)).toBe(true);
|
|
20
|
+
expect(shouldRegenerateGraphqlSource('schema.graphql', configuredSources)).toBe(false);
|
|
21
|
+
expect(shouldRegenerateGraphqlSource('unrelated.txt', configuredSources)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -3,6 +3,7 @@ export declare const getVariablesHash: (variables: Record<string, string> | unde
|
|
|
3
3
|
export declare const getDocsConfigApiHash: (docsConfig: DocsConfig) => string;
|
|
4
4
|
export declare const getDocsConfigNavigationHash: (docsConfig: DocsConfig) => string;
|
|
5
5
|
export declare const updateDocsConfigHashCache: (docsConfig: DocsConfig) => void;
|
|
6
|
+
export declare const hadDocsConfigApiReference: () => boolean;
|
|
6
7
|
export declare const hasNavigationApiReference: (value: unknown) => boolean;
|
|
7
8
|
export declare const hasDocsConfigApiChanged: (newApiHash: string) => boolean;
|
|
8
9
|
export declare const hasDocsConfigNavigationChanged: (newNavigationHash: string) => boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
let docsConfigVariablesHash;
|
|
2
2
|
let docsConfigApiHash;
|
|
3
3
|
let docsConfigNavigationHash;
|
|
4
|
+
let docsConfigHadApiReference = false;
|
|
4
5
|
const getJsonHash = (value) => {
|
|
5
6
|
return JSON.stringify(value ?? {});
|
|
6
7
|
};
|
|
@@ -17,13 +18,17 @@ export const updateDocsConfigHashCache = (docsConfig) => {
|
|
|
17
18
|
docsConfigVariablesHash = getVariablesHash(docsConfig.variables);
|
|
18
19
|
docsConfigApiHash = getDocsConfigApiHash(docsConfig);
|
|
19
20
|
docsConfigNavigationHash = getDocsConfigNavigationHash(docsConfig);
|
|
21
|
+
docsConfigHadApiReference =
|
|
22
|
+
docsConfig.api != null || hasNavigationApiReference(docsConfig.navigation);
|
|
20
23
|
};
|
|
24
|
+
export const hadDocsConfigApiReference = () => docsConfigHadApiReference;
|
|
21
25
|
export const hasNavigationApiReference = (value) => {
|
|
22
26
|
if (value == null || typeof value !== 'object') {
|
|
23
27
|
return false;
|
|
24
28
|
}
|
|
25
29
|
if (Object.prototype.hasOwnProperty.call(value, 'openapi') ||
|
|
26
|
-
Object.prototype.hasOwnProperty.call(value, 'asyncapi')
|
|
30
|
+
Object.prototype.hasOwnProperty.call(value, 'asyncapi') ||
|
|
31
|
+
Object.prototype.hasOwnProperty.call(value, 'graphql')) {
|
|
27
32
|
return true;
|
|
28
33
|
}
|
|
29
34
|
return Object.values(value).some(hasNavigationApiReference);
|
|
@@ -41,4 +46,5 @@ export const clearDocsConfigCaches = () => {
|
|
|
41
46
|
docsConfigVariablesHash = undefined;
|
|
42
47
|
docsConfigApiHash = undefined;
|
|
43
48
|
docsConfigNavigationHash = undefined;
|
|
49
|
+
docsConfigHadApiReference = false;
|
|
44
50
|
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { DecoratedNavigationPage, MintConfig, OpenApiFile } from '@mintlify/models';
|
|
2
2
|
import { DocsConfig } from '@mintlify/validation';
|
|
3
|
-
export declare const getDocsState: (onError?: (message: string) => void
|
|
3
|
+
export declare const getDocsState: (onError?: (message: string) => void, { contentDirectory, clientDirectory, }?: {
|
|
4
|
+
contentDirectory?: string;
|
|
5
|
+
clientDirectory?: string;
|
|
6
|
+
}) => Promise<{
|
|
4
7
|
mintConfig?: MintConfig;
|
|
5
8
|
pagesAcc: Record<string, DecoratedNavigationPage>;
|
|
6
9
|
openApiFiles: OpenApiFile[];
|
|
@@ -1,31 +1,43 @@
|
|
|
1
|
-
import { generateOpenApiAnchorsOrTabs, categorizeFilePaths, generateOpenApiDivisions, getMintIgnore, MintConfigUpdater, DocsConfigUpdater, warnInvalidSpecFiles, } from '@mintlify/prebuild';
|
|
1
|
+
import { generateOpenApiAnchorsOrTabs, categorizeFilePaths, generateOpenApiDivisions, generateAsyncApiDivisions, generateGraphqlDivisionsFromDocsConfig, getMintIgnore, MintConfigUpdater, DocsConfigUpdater, warnInvalidSpecFiles, loadGraphqlSdlSource, writeGraphqlArtifacts, } from '@mintlify/prebuild';
|
|
2
2
|
import { upgradeToDocsConfig } from '@mintlify/validation';
|
|
3
3
|
import fse from 'fs-extra';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { CMD_EXEC_PATH, CLIENT_PATH } from '../../constants.js';
|
|
6
|
-
export const getDocsState = async (onError) => {
|
|
7
|
-
const mintIgnore = await getMintIgnore(
|
|
8
|
-
const { openApiFiles, invalidSpecFiles } = await categorizeFilePaths(
|
|
6
|
+
export const getDocsState = async (onError, { contentDirectory = CMD_EXEC_PATH, clientDirectory = CLIENT_PATH, } = {}) => {
|
|
7
|
+
const mintIgnore = await getMintIgnore(contentDirectory);
|
|
8
|
+
const { openApiFiles, asyncApiFiles, invalidSpecFiles } = await categorizeFilePaths(contentDirectory, mintIgnore);
|
|
9
|
+
let mintConfig;
|
|
10
|
+
let docsConfig;
|
|
11
|
+
let loadedMintConfig;
|
|
9
12
|
try {
|
|
10
|
-
|
|
11
|
-
const docsConfig = upgradeToDocsConfig(mintConfig);
|
|
12
|
-
const { mintConfig: newMintConfig } = await generateOpenApiAnchorsOrTabs(mintConfig, openApiFiles, CLIENT_PATH, undefined, invalidSpecFiles);
|
|
13
|
-
const { newDocsConfig, pagesAcc, openApiFiles: newOpenApiFiles, } = await generateOpenApiDivisions(docsConfig, openApiFiles, CLIENT_PATH, undefined, invalidSpecFiles);
|
|
14
|
-
warnInvalidSpecFiles(invalidSpecFiles);
|
|
15
|
-
return {
|
|
16
|
-
mintConfig: newMintConfig,
|
|
17
|
-
pagesAcc,
|
|
18
|
-
openApiFiles: newOpenApiFiles,
|
|
19
|
-
docsConfig: newDocsConfig,
|
|
20
|
-
};
|
|
13
|
+
loadedMintConfig = await MintConfigUpdater.getConfig(join(contentDirectory, 'mint.json'), false, contentDirectory, onError);
|
|
21
14
|
}
|
|
22
15
|
catch {
|
|
23
|
-
const docsJsonPath = join(
|
|
16
|
+
const docsJsonPath = join(contentDirectory, 'docs.json');
|
|
24
17
|
if (!(await fse.pathExists(docsJsonPath)))
|
|
25
18
|
throw new Error('No config found');
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return { pagesAcc, openApiFiles: newOpenApiFiles, docsConfig: newDocsConfig };
|
|
19
|
+
docsConfig = await DocsConfigUpdater.getConfig(docsJsonPath, false, contentDirectory, onError, {
|
|
20
|
+
allowSourceRefs: true,
|
|
21
|
+
});
|
|
30
22
|
}
|
|
23
|
+
if (loadedMintConfig) {
|
|
24
|
+
docsConfig = upgradeToDocsConfig(loadedMintConfig);
|
|
25
|
+
const result = await generateOpenApiAnchorsOrTabs(loadedMintConfig, openApiFiles, clientDirectory, undefined, invalidSpecFiles);
|
|
26
|
+
mintConfig = result.mintConfig;
|
|
27
|
+
}
|
|
28
|
+
if (!docsConfig)
|
|
29
|
+
throw new Error('No config found');
|
|
30
|
+
const graphqlResult = await generateGraphqlDivisionsFromDocsConfig(docsConfig, (source) => loadGraphqlSdlSource(source, contentDirectory));
|
|
31
|
+
const { newDocsConfig: docsConfigWithGraphqlPages, pagesAcc: pagesAccWithGraphqlPages } = graphqlResult;
|
|
32
|
+
const { newDocsConfig, pagesAcc: pagesAccWithOpenApiPages, openApiFiles: newOpenApiFiles, flushWrites: flushOpenApiWrites, } = await generateOpenApiDivisions(docsConfigWithGraphqlPages, openApiFiles, clientDirectory, undefined, invalidSpecFiles, pagesAccWithGraphqlPages, true);
|
|
33
|
+
const { flushWrites: flushAsyncApiWrites } = await generateAsyncApiDivisions(newDocsConfig, asyncApiFiles, clientDirectory, undefined, pagesAccWithGraphqlPages, false, true);
|
|
34
|
+
await Promise.all([flushOpenApiWrites(), flushAsyncApiWrites()]);
|
|
35
|
+
await writeGraphqlArtifacts(graphqlResult, clientDirectory);
|
|
36
|
+
warnInvalidSpecFiles(invalidSpecFiles);
|
|
37
|
+
return {
|
|
38
|
+
mintConfig,
|
|
39
|
+
pagesAcc: { ...pagesAccWithOpenApiPages, ...pagesAccWithGraphqlPages },
|
|
40
|
+
openApiFiles: newOpenApiFiles,
|
|
41
|
+
docsConfig: newDocsConfig,
|
|
42
|
+
};
|
|
31
43
|
};
|
|
@@ -2,7 +2,9 @@ import { initializeImportCache } from './importCache.js';
|
|
|
2
2
|
type LocalPreviewOptions = {
|
|
3
3
|
localSchema?: boolean;
|
|
4
4
|
groups?: string[];
|
|
5
|
+
disableOpenApi?: boolean;
|
|
5
6
|
allowSourceRefs?: boolean;
|
|
7
|
+
lazyPages?: boolean;
|
|
6
8
|
};
|
|
7
9
|
declare const listener: (triggerRefresh: () => void, options?: LocalPreviewOptions, gate?: Promise<void>) => void;
|
|
8
10
|
declare const initializeFrontmatterHashCache: () => Promise<void>;
|
|
@@ -12,13 +12,13 @@ import { CMD_EXEC_PATH, NEXT_PROPS_PATH, NEXT_PUBLIC_PATH, CLIENT_PATH } from '.
|
|
|
12
12
|
import { addChangeLog, addErrorLog, clearErrorLogs, getCurrentErrorLogs, } from '../../logging-state.js';
|
|
13
13
|
import { AddedLog, DeletedLog, EditedLog, WarningLog, InfoLog, ErrorLog } from '../../logs.js';
|
|
14
14
|
import { reportPageCompileError, reportPageCompileSuccess } from '../on-demand-page.js';
|
|
15
|
-
import { clearDocsConfigCaches, getDocsConfigApiHash, getDocsConfigNavigationHash, getVariablesHash, hasDocsConfigApiChanged, hasDocsConfigNavigationChanged, hasNavigationApiReference, hasDocsConfigVariablesChanged, updateDocsConfigHashCache, } from './docs-config-cache.js';
|
|
15
|
+
import { clearDocsConfigCaches, getDocsConfigApiHash, getDocsConfigNavigationHash, getVariablesHash, hasDocsConfigApiChanged, hasDocsConfigNavigationChanged, hasNavigationApiReference, hadDocsConfigApiReference, hasDocsConfigVariablesChanged, updateDocsConfigHashCache, } from './docs-config-cache.js';
|
|
16
16
|
import { generateDependentSnippets } from './generateDependentSnippets.js';
|
|
17
17
|
import { generatePagesWithImports } from './generatePagesWithImports.js';
|
|
18
18
|
import { getDocsState } from './getDocsState.js';
|
|
19
19
|
import { initializeImportCache, updateImportCacheForFile, removeFromImportCache, getImportedFilesFromCache, syncImportedFileLocations, } from './importCache.js';
|
|
20
20
|
import { clearPageMetadataCache, removePageMetadataCacheEntryForFile, upsertPageMetadataCacheEntry, upsertPageMetadataCacheEntryForFile, } from './page-metadata-cache.js';
|
|
21
|
-
import { hasTrackedReferencedFile, refreshTrackedReferencedFiles } from './referencedFiles.js';
|
|
21
|
+
import { hasTrackedReferencedFile, refreshTrackedReferencedFiles, shouldRegenerateGraphqlSource, } from './referencedFiles.js';
|
|
22
22
|
import { regenerateAllSnippets } from './regenerateAllSnippets.js';
|
|
23
23
|
import { resolveImportsFromImportClosure } from './resolve-imports-from-import-closure.js';
|
|
24
24
|
import { resolvePageImports } from './resolve-page-imports.js';
|
|
@@ -158,6 +158,11 @@ const onUnlinkEvent = async (filename, triggerRefresh, options) => {
|
|
|
158
158
|
if (potentialCategory === 'page') {
|
|
159
159
|
reportPageCompileSuccess(filename);
|
|
160
160
|
}
|
|
161
|
+
if (shouldRegenerateGraphqlSource(filename)) {
|
|
162
|
+
await rebuildGraphqlSchema(triggerRefresh, options);
|
|
163
|
+
addChangeLog(_jsx(DeletedLog, { filename: filename }));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
161
166
|
if (hasTrackedReferencedFile(filename)) {
|
|
162
167
|
try {
|
|
163
168
|
const { mintConfig, openApiFiles, docsConfig } = await getDocsState(handleParseError);
|
|
@@ -308,6 +313,14 @@ const initializeDocsConfigHashCache = async () => {
|
|
|
308
313
|
}
|
|
309
314
|
catch { }
|
|
310
315
|
};
|
|
316
|
+
const rebuildGraphqlSchema = async (triggerRefresh, options) => {
|
|
317
|
+
const prebuildResult = await prebuild(CMD_EXEC_PATH, options);
|
|
318
|
+
await initializeImportCache(CMD_EXEC_PATH, prebuildResult?.fileImportsMap);
|
|
319
|
+
await initializeFrontmatterHashCache();
|
|
320
|
+
await initializeDocsConfigHashCache();
|
|
321
|
+
await refreshTrackedReferencedFiles();
|
|
322
|
+
triggerRefresh();
|
|
323
|
+
};
|
|
311
324
|
/**
|
|
312
325
|
* This function is called when a file is added or changed
|
|
313
326
|
* @param filename
|
|
@@ -316,6 +329,10 @@ const initializeDocsConfigHashCache = async () => {
|
|
|
316
329
|
const onUpdateEvent = async (filename, triggerRefresh, options = {}) => {
|
|
317
330
|
clearErrorLogs();
|
|
318
331
|
const filePath = pathUtil.join(CMD_EXEC_PATH, filename);
|
|
332
|
+
if (shouldRegenerateGraphqlSource(filename)) {
|
|
333
|
+
await rebuildGraphqlSchema(triggerRefresh, options);
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
319
336
|
const importChanges = await updateImportCacheForFile(CMD_EXEC_PATH, filename);
|
|
320
337
|
await syncImportedFileLocations(importChanges);
|
|
321
338
|
const importedFiles = getImportedFilesFromCache();
|
|
@@ -431,8 +448,13 @@ const onUpdateEvent = async (filename, triggerRefresh, options = {}) => {
|
|
|
431
448
|
const navigationChanged = hasDocsConfigNavigationChanged(newNavigationHash);
|
|
432
449
|
const newVariablesHash = getVariablesHash(docsConfig.variables);
|
|
433
450
|
const variablesChanged = hasDocsConfigVariablesChanged(newVariablesHash);
|
|
434
|
-
const shouldUseNavigationFastPath = navigationChanged &&
|
|
435
|
-
|
|
451
|
+
const shouldUseNavigationFastPath = navigationChanged &&
|
|
452
|
+
!apiChanged &&
|
|
453
|
+
!hasDocsConfigApiRoutes(docsConfig) &&
|
|
454
|
+
!hadDocsConfigApiReference();
|
|
455
|
+
const shouldRegenerateGeneratedData = apiChanged ||
|
|
456
|
+
(navigationChanged &&
|
|
457
|
+
(hasDocsConfigApiRoutes(docsConfig) || hadDocsConfigApiReference()));
|
|
436
458
|
await refreshTrackedReferencedFiles();
|
|
437
459
|
if (shouldUseNavigationFastPath) {
|
|
438
460
|
// Plain MDX navigation changed without API changes: regenerate
|
|
@@ -484,8 +506,8 @@ const onUpdateEvent = async (filename, triggerRefresh, options = {}) => {
|
|
|
484
506
|
// mint.json: preserve the original full-rebuild behavior.
|
|
485
507
|
regenerateNav = true;
|
|
486
508
|
try {
|
|
487
|
-
const { mintConfig, openApiFiles, docsConfig } = await getDocsState(handleParseError);
|
|
488
509
|
await refreshTrackedReferencedFiles();
|
|
510
|
+
const { mintConfig, openApiFiles, docsConfig } = await getDocsState(handleParseError);
|
|
489
511
|
if (mintConfig) {
|
|
490
512
|
await MintConfigUpdater.writeConfigFile(mintConfig, CLIENT_PATH);
|
|
491
513
|
}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
export declare const getLocalGraphqlSources: (value: unknown) => string[];
|
|
1
2
|
export declare const refreshTrackedReferencedFiles: () => Promise<void>;
|
|
2
3
|
export declare const hasTrackedReferencedFile: (filePath: string) => boolean;
|
|
4
|
+
export declare const shouldRegenerateGraphqlSource: (filePath: string, configuredSources?: ReadonlySet<string>) => boolean;
|
|
@@ -1,21 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeRelativePath } from '@mintlify/common';
|
|
2
|
+
import { getConfigPath, isRemoteGraphqlSource, resolveFileRefs } from '@mintlify/prebuild';
|
|
2
3
|
import { readFile } from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
3
5
|
import { CMD_EXEC_PATH } from '../../constants.js';
|
|
4
6
|
let trackedReferencedFiles = new Set();
|
|
7
|
+
let trackedGraphqlSources = new Set();
|
|
8
|
+
const normalizeTrackedPath = (filePath) => path.normalize(normalizeRelativePath(filePath));
|
|
9
|
+
export const getLocalGraphqlSources = (value) => {
|
|
10
|
+
if (Array.isArray(value))
|
|
11
|
+
return value.flatMap(getLocalGraphqlSources);
|
|
12
|
+
if (value == null || typeof value !== 'object')
|
|
13
|
+
return [];
|
|
14
|
+
const node = value;
|
|
15
|
+
const graphql = node.graphql;
|
|
16
|
+
const source = typeof graphql === 'string'
|
|
17
|
+
? graphql
|
|
18
|
+
: graphql != null && typeof graphql === 'object' && 'source' in graphql
|
|
19
|
+
? graphql.source
|
|
20
|
+
: undefined;
|
|
21
|
+
const sources = typeof source === 'string' && !isRemoteGraphqlSource(source)
|
|
22
|
+
? [normalizeTrackedPath(source)]
|
|
23
|
+
: [];
|
|
24
|
+
return [...sources, ...Object.values(node).flatMap(getLocalGraphqlSources)];
|
|
25
|
+
};
|
|
5
26
|
export const refreshTrackedReferencedFiles = async () => {
|
|
6
27
|
try {
|
|
7
28
|
const configPath = (await getConfigPath(CMD_EXEC_PATH, 'docs')) ?? (await getConfigPath(CMD_EXEC_PATH, 'mint'));
|
|
8
29
|
if (!configPath) {
|
|
9
30
|
trackedReferencedFiles = new Set();
|
|
31
|
+
trackedGraphqlSources = new Set();
|
|
10
32
|
return;
|
|
11
33
|
}
|
|
12
34
|
const content = await readFile(configPath, 'utf-8');
|
|
13
35
|
const parsed = JSON.parse(content);
|
|
14
|
-
const { referencedFiles } = await resolveFileRefs(parsed, CMD_EXEC_PATH);
|
|
15
|
-
|
|
36
|
+
const { referencedFiles, resolved } = await resolveFileRefs(parsed, CMD_EXEC_PATH);
|
|
37
|
+
const graphqlSources = getLocalGraphqlSources(resolved);
|
|
38
|
+
trackedReferencedFiles = new Set([
|
|
39
|
+
...referencedFiles.map(normalizeTrackedPath),
|
|
40
|
+
...graphqlSources,
|
|
41
|
+
]);
|
|
42
|
+
trackedGraphqlSources = new Set(graphqlSources);
|
|
16
43
|
}
|
|
17
44
|
catch {
|
|
18
45
|
trackedReferencedFiles = new Set();
|
|
46
|
+
trackedGraphqlSources = new Set();
|
|
19
47
|
}
|
|
20
48
|
};
|
|
21
|
-
export const hasTrackedReferencedFile = (filePath) => trackedReferencedFiles.has(filePath);
|
|
49
|
+
export const hasTrackedReferencedFile = (filePath) => trackedReferencedFiles.has(normalizeTrackedPath(filePath));
|
|
50
|
+
export const shouldRegenerateGraphqlSource = (filePath, configuredSources = trackedGraphqlSources) => configuredSources.has(normalizeTrackedPath(filePath));
|
|
@@ -173,7 +173,13 @@ export const run = async (argv) => {
|
|
|
173
173
|
releaseWatcherGate = resolve;
|
|
174
174
|
});
|
|
175
175
|
addDevTimingLog('watching for file changes');
|
|
176
|
-
listener(onChange, {
|
|
176
|
+
listener(onChange, {
|
|
177
|
+
localSchema: argv['local-schema'],
|
|
178
|
+
groups: argv.groups,
|
|
179
|
+
disableOpenApi: argv.disableOpenapi,
|
|
180
|
+
allowSourceRefs: true,
|
|
181
|
+
lazyPages: true,
|
|
182
|
+
}, watcherGate);
|
|
177
183
|
await timeDev('initialize import cache', () => initializeImportCache(CMD_EXEC_PATH, argv.fileImportsMap));
|
|
178
184
|
markOnDemandPagesReady();
|
|
179
185
|
await timeDev('initialize frontmatter cache', () => initializeFrontmatterHashCache());
|