@mintlify/previewing 4.0.836 → 4.0.838
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__/importCache.test.d.ts +1 -0
- package/dist/__tests__/importCache.test.js +58 -0
- package/dist/local-preview/index.js +10 -4
- package/dist/local-preview/listener/generateDependentSnippets.js +3 -3
- package/dist/local-preview/listener/generatePagesWithImports.js +12 -6
- package/dist/local-preview/listener/getSnippets.js +19 -6
- package/dist/local-preview/listener/importCache.d.ts +9 -0
- package/dist/local-preview/listener/importCache.js +168 -0
- package/dist/local-preview/listener/index.d.ts +2 -0
- package/dist/local-preview/listener/index.js +28 -5
- package/dist/local-preview/listener/utils.d.ts +1 -0
- package/dist/local-preview/listener/utils.js +4 -1
- package/dist/local-preview/run.d.ts +1 -0
- package/dist/local-preview/run.js +3 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import fse from 'fs-extra';
|
|
2
|
+
import { initializeImportCache, updateImportCacheForFile, removeFromImportCache, getImportedFilesFromCache, } from '../local-preview/listener/importCache.js';
|
|
3
|
+
vi.mock('fs-extra', () => ({
|
|
4
|
+
default: { readFile: vi.fn() },
|
|
5
|
+
}));
|
|
6
|
+
vi.mock('@mintlify/prebuild', async () => {
|
|
7
|
+
const actual = await vi.importActual('@mintlify/prebuild');
|
|
8
|
+
return {
|
|
9
|
+
...actual,
|
|
10
|
+
getFileListSync: vi.fn().mockReturnValue([]),
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
const mockReadFile = vi.mocked(fse.readFile);
|
|
14
|
+
describe('importCache', () => {
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
await initializeImportCache('/base');
|
|
18
|
+
});
|
|
19
|
+
it('starts with empty cache', () => {
|
|
20
|
+
expect(getImportedFilesFromCache()).toEqual(new Set());
|
|
21
|
+
});
|
|
22
|
+
it('tracks imports when file is updated', async () => {
|
|
23
|
+
mockReadFile.mockResolvedValue(Buffer.from(`import Foo from './foo.mdx';\n\n<Foo />`));
|
|
24
|
+
await updateImportCacheForFile('/base', 'page.mdx');
|
|
25
|
+
expect(getImportedFilesFromCache()).toEqual(new Set(['/foo.mdx']));
|
|
26
|
+
});
|
|
27
|
+
it('returns newlyImported when import is added', async () => {
|
|
28
|
+
mockReadFile.mockResolvedValue(Buffer.from(`import Bar from '/bar.mdx';\n\n<Bar />`));
|
|
29
|
+
const result = await updateImportCacheForFile('/base', 'page.mdx');
|
|
30
|
+
expect(result.newlyImported).toEqual(['/bar.mdx']);
|
|
31
|
+
});
|
|
32
|
+
it('returns noLongerImported when file is removed', async () => {
|
|
33
|
+
mockReadFile.mockResolvedValue(Buffer.from(`import X from './x.mdx';\n\n<X />`));
|
|
34
|
+
await updateImportCacheForFile('/base', 'a.mdx');
|
|
35
|
+
const result = removeFromImportCache('a.mdx');
|
|
36
|
+
expect(result.noLongerImported).toEqual(['/x.mdx']);
|
|
37
|
+
});
|
|
38
|
+
it('ignores non-mdx files', async () => {
|
|
39
|
+
const result = await updateImportCacheForFile('/base', 'file.js');
|
|
40
|
+
expect(result).toEqual({ newlyImported: [], noLongerImported: [] });
|
|
41
|
+
});
|
|
42
|
+
it('keeps import in cache if still referenced by another file', async () => {
|
|
43
|
+
mockReadFile.mockResolvedValue(Buffer.from(`import S from './shared.mdx';\n\n<S />`));
|
|
44
|
+
await updateImportCacheForFile('/base', 'a.mdx');
|
|
45
|
+
await updateImportCacheForFile('/base', 'b.mdx');
|
|
46
|
+
const result = removeFromImportCache('a.mdx');
|
|
47
|
+
expect(result.noLongerImported).toEqual([]);
|
|
48
|
+
expect(getImportedFilesFromCache()).toEqual(new Set(['/shared.mdx']));
|
|
49
|
+
});
|
|
50
|
+
it('detects when imports change in a file', async () => {
|
|
51
|
+
mockReadFile.mockResolvedValue(Buffer.from(`import Old from './old.mdx';\n\n<Old />`));
|
|
52
|
+
await updateImportCacheForFile('/base', 'page.mdx');
|
|
53
|
+
mockReadFile.mockResolvedValue(Buffer.from(`import New from './new.mdx';\n\n<New />`));
|
|
54
|
+
const result = await updateImportCacheForFile('/base', 'page.mdx');
|
|
55
|
+
expect(result.newlyImported).toEqual(['/new.mdx']);
|
|
56
|
+
expect(result.noLongerImported).toEqual(['/old.mdx']);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -5,8 +5,8 @@ import isOnline from 'is-online';
|
|
|
5
5
|
import { CLIENT_PATH, DOT_MINTLIFY, CMD_EXEC_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, } from '../constants.js';
|
|
6
6
|
import { addLog, clearLogs } from '../logging-state.js';
|
|
7
7
|
import { ErrorLog, SpinnerLog } from '../logs.js';
|
|
8
|
-
import { silentUpdateClient } from './update.js';
|
|
9
8
|
import { run } from './run.js';
|
|
9
|
+
import { silentUpdateClient } from './update.js';
|
|
10
10
|
const dev = async (argv) => {
|
|
11
11
|
const hasInternet = await isOnline();
|
|
12
12
|
const localSchema = argv['local-schema'];
|
|
@@ -26,7 +26,11 @@ const dev = async (argv) => {
|
|
|
26
26
|
process.exit(1);
|
|
27
27
|
}
|
|
28
28
|
addLog(_jsx(SpinnerLog, { message: "preparing local preview..." }));
|
|
29
|
-
const { needsUpdate, error } = await silentUpdateClient({
|
|
29
|
+
const { needsUpdate, error } = await silentUpdateClient({
|
|
30
|
+
versionString,
|
|
31
|
+
clientVersion,
|
|
32
|
+
cliVersion,
|
|
33
|
+
});
|
|
30
34
|
if (error) {
|
|
31
35
|
clearLogs();
|
|
32
36
|
addLog(_jsx(ErrorLog, { message: error }));
|
|
@@ -37,8 +41,10 @@ const dev = async (argv) => {
|
|
|
37
41
|
fse.emptyDirSync(NEXT_PUBLIC_PATH);
|
|
38
42
|
fse.emptyDirSync(NEXT_PROPS_PATH);
|
|
39
43
|
process.chdir(CLIENT_PATH);
|
|
44
|
+
let fileImportsMap;
|
|
40
45
|
try {
|
|
41
|
-
await prebuild(CMD_EXEC_PATH, { localSchema, groups, disableOpenApi });
|
|
46
|
+
const result = await prebuild(CMD_EXEC_PATH, { localSchema, groups, disableOpenApi });
|
|
47
|
+
fileImportsMap = result?.fileImportsMap;
|
|
42
48
|
}
|
|
43
49
|
catch (err) {
|
|
44
50
|
clearLogs();
|
|
@@ -47,6 +53,6 @@ const dev = async (argv) => {
|
|
|
47
53
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
48
54
|
process.exit(1);
|
|
49
55
|
}
|
|
50
|
-
await run({ ...argv, needsUpdate });
|
|
56
|
+
await run({ ...argv, needsUpdate, fileImportsMap });
|
|
51
57
|
};
|
|
52
58
|
export default dev;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findAndRemoveImports, stringifyTree, topologicalSort, hasImports, optionallyAddLeadingSlash, optionallyRemoveLeadingSlash,
|
|
1
|
+
import { findAndRemoveImports, stringifyTree, topologicalSort, hasImports, optionallyAddLeadingSlash, optionallyRemoveLeadingSlash, resolveImportPath, } from '@mintlify/common';
|
|
2
2
|
import { outputFile } from 'fs-extra';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { NEXT_PUBLIC_PATH } from '../../constants.js';
|
|
@@ -20,7 +20,7 @@ const findAllDependents = async (initialFileWithSlash, allSnippets, processedDat
|
|
|
20
20
|
processedDataCache.set(potentialDependentFile, processedData);
|
|
21
21
|
}
|
|
22
22
|
const importsCurrentFile = Object.keys(processedData.importMap).some((importPath) => {
|
|
23
|
-
const resolvedPath =
|
|
23
|
+
const resolvedPath = resolveImportPath(importPath, potentialDependentFile);
|
|
24
24
|
return resolvedPath === currentSourceFile;
|
|
25
25
|
});
|
|
26
26
|
if (importsCurrentFile) {
|
|
@@ -66,7 +66,7 @@ export const generateDependentSnippets = async (changedFilename, newImportData)
|
|
|
66
66
|
const graph = {};
|
|
67
67
|
snippets.forEach((item) => {
|
|
68
68
|
graph[item.filename] = Object.keys(item.importMap)
|
|
69
|
-
.map((dep) =>
|
|
69
|
+
.map((dep) => resolveImportPath(dep, item.filename))
|
|
70
70
|
.filter((resolvedDep) => resolvedDep != null);
|
|
71
71
|
});
|
|
72
72
|
const sortedSnippets = topologicalSort(graph).reverse();
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import { findAndRemoveImports, optionallyRemoveLeadingSlash, resolveAllImports,
|
|
2
|
-
import { preparseMdxTree, getFileListSync } from '@mintlify/prebuild';
|
|
1
|
+
import { findAndRemoveImports, optionallyRemoveLeadingSlash, resolveAllImports, resolveImportPath, stringifyTree, isSnippetExtension, getFileCategory, } from '@mintlify/common';
|
|
2
|
+
import { preparseMdxTree, getFileListSync, getFileExtension } from '@mintlify/prebuild';
|
|
3
3
|
import { promises as _promises } from 'fs';
|
|
4
4
|
import { outputFile } from 'fs-extra';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
import { CMD_EXEC_PATH, NEXT_PROPS_PATH } from '../../constants.js';
|
|
7
7
|
import { getProcessedSnippets } from './getSnippets.js';
|
|
8
|
+
import { getImportedFilesFromCache } from './importCache.js';
|
|
8
9
|
const { readFile } = _promises;
|
|
9
10
|
export const generatePagesWithImports = async (updatedSnippets) => {
|
|
10
11
|
const snippets = await getProcessedSnippets();
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
!file
|
|
12
|
+
const importedFiles = getImportedFilesFromCache();
|
|
13
|
+
const pageFilenames = getFileListSync(CMD_EXEC_PATH).filter((file) => {
|
|
14
|
+
if (!isSnippetExtension(getFileExtension(file))) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const category = getFileCategory(file, { importedFiles });
|
|
18
|
+
return category === 'page';
|
|
19
|
+
});
|
|
14
20
|
await Promise.all(pageFilenames.map(async (pageFilename) => {
|
|
15
21
|
const sourcePath = join(CMD_EXEC_PATH, pageFilename);
|
|
16
22
|
const contentStr = (await readFile(sourcePath)).toString();
|
|
@@ -18,7 +24,7 @@ export const generatePagesWithImports = async (updatedSnippets) => {
|
|
|
18
24
|
const tree = await preparseMdxTree(contentStr, CMD_EXEC_PATH, sourcePath);
|
|
19
25
|
const importsResponse = await findAndRemoveImports(tree);
|
|
20
26
|
if (Object.keys(importsResponse.importMap).some((importPath) => {
|
|
21
|
-
const resolvedPath =
|
|
27
|
+
const resolvedPath = resolveImportPath(importPath, pageFilename);
|
|
22
28
|
return (resolvedPath != null &&
|
|
23
29
|
updatedSnippets.has(optionallyRemoveLeadingSlash(resolvedPath)));
|
|
24
30
|
})) {
|
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
import { optionallyAddLeadingSlash,
|
|
2
|
-
import { getFileListSync, preparseMdxTree } from '@mintlify/prebuild';
|
|
1
|
+
import { optionallyAddLeadingSlash, isSnippetExtension, isImportedAsSnippet, } from '@mintlify/common';
|
|
2
|
+
import { getFileListSync, preparseMdxTree, getFileExtension } from '@mintlify/prebuild';
|
|
3
3
|
import { promises as _promises } from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { CMD_EXEC_PATH, NEXT_PUBLIC_PATH } from '../../constants.js';
|
|
6
|
+
import { getImportedFilesFromCache } from './importCache.js';
|
|
6
7
|
const { readFile } = _promises;
|
|
7
|
-
const getSnippetBase = async (
|
|
8
|
-
const
|
|
9
|
-
const
|
|
8
|
+
const getSnippetBase = async (baseDir) => {
|
|
9
|
+
const importedFiles = getImportedFilesFromCache();
|
|
10
|
+
const allSnippetFilenames = getFileListSync(baseDir).filter((file) => {
|
|
11
|
+
if (!isSnippetExtension(getFileExtension(file))) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (file.startsWith('snippets/') || file.startsWith('_snippets/')) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (getFileExtension(file) === 'jsx') {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return isImportedAsSnippet(file, importedFiles);
|
|
21
|
+
});
|
|
22
|
+
const promises = allSnippetFilenames.map(async (snippetFilename) => {
|
|
10
23
|
try {
|
|
11
|
-
const tree = await preparseMdxTree((await readFile(join(
|
|
24
|
+
const tree = await preparseMdxTree((await readFile(join(baseDir, snippetFilename))).toString(), baseDir, join(baseDir, snippetFilename));
|
|
12
25
|
return {
|
|
13
26
|
filename: optionallyAddLeadingSlash(snippetFilename),
|
|
14
27
|
tree,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ImportCacheChangeResult {
|
|
2
|
+
newlyImported: string[];
|
|
3
|
+
noLongerImported: string[];
|
|
4
|
+
}
|
|
5
|
+
export declare const initializeImportCache: (baseDir: string, prebuildImportMap?: Map<string, Set<string>>) => Promise<void>;
|
|
6
|
+
export declare const updateImportCacheForFile: (baseDir: string, filename: string) => Promise<ImportCacheChangeResult>;
|
|
7
|
+
export declare const removeFromImportCache: (filename: string) => ImportCacheChangeResult;
|
|
8
|
+
export declare const getImportedFilesFromCache: () => Set<string>;
|
|
9
|
+
export declare const syncImportedFileLocations: (changes: ImportCacheChangeResult) => Promise<void>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { optionallyAddLeadingSlash, optionallyRemoveLeadingSlash, isSnippetExtension, extractImportSources, resolveImportPath, findAndRemoveImports, hasImports, stringifyTree, getFileCategory, } from '@mintlify/common';
|
|
2
|
+
import { getFileExtension } from '@mintlify/prebuild';
|
|
3
|
+
import { getFileListSync, createPage, preparseMdxTree } from '@mintlify/prebuild';
|
|
4
|
+
import fse from 'fs-extra';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { CMD_EXEC_PATH, NEXT_PROPS_PATH, NEXT_PUBLIC_PATH } from '../../constants.js';
|
|
7
|
+
import { resolveAllImports } from './resolveAllImports.js';
|
|
8
|
+
import { normalizePathForComparison } from './utils.js';
|
|
9
|
+
const fileImportsMap = new Map();
|
|
10
|
+
const importerCounts = new Map();
|
|
11
|
+
const addImporter = (path) => {
|
|
12
|
+
const count = importerCounts.get(path) ?? 0;
|
|
13
|
+
importerCounts.set(path, count + 1);
|
|
14
|
+
return count === 0;
|
|
15
|
+
};
|
|
16
|
+
const removeImporter = (path) => {
|
|
17
|
+
const count = importerCounts.get(path);
|
|
18
|
+
if (count == null)
|
|
19
|
+
return false;
|
|
20
|
+
if (count <= 1) {
|
|
21
|
+
importerCounts.delete(path);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
importerCounts.set(path, count - 1);
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
const extractFileImports = async (baseDir, filename) => {
|
|
28
|
+
const filePath = join(baseDir, filename);
|
|
29
|
+
try {
|
|
30
|
+
const content = (await fse.readFile(filePath)).toString();
|
|
31
|
+
const tree = await preparseMdxTree(content, baseDir, filePath);
|
|
32
|
+
const importSources = extractImportSources(tree);
|
|
33
|
+
const imports = new Set();
|
|
34
|
+
for (const source of importSources) {
|
|
35
|
+
const resolvedPath = resolveImportPath(source, optionallyAddLeadingSlash(filename));
|
|
36
|
+
if (resolvedPath != null) {
|
|
37
|
+
imports.add(normalizePathForComparison(resolvedPath));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return imports;
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.log('Error extracting imports from file');
|
|
44
|
+
console.log(filename);
|
|
45
|
+
console.log(err);
|
|
46
|
+
return new Set();
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
export const initializeImportCache = async (baseDir, prebuildImportMap) => {
|
|
50
|
+
fileImportsMap.clear();
|
|
51
|
+
importerCounts.clear();
|
|
52
|
+
if (prebuildImportMap) {
|
|
53
|
+
for (const [filePath, imports] of prebuildImportMap) {
|
|
54
|
+
const normalizedPath = normalizePathForComparison(filePath);
|
|
55
|
+
fileImportsMap.set(normalizedPath, imports);
|
|
56
|
+
for (const imp of imports) {
|
|
57
|
+
addImporter(imp);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const allFiles = getFileListSync(baseDir).filter((file) => isSnippetExtension(getFileExtension(file)));
|
|
63
|
+
await Promise.all(allFiles.map(async (filename) => {
|
|
64
|
+
const normalizedPath = normalizePathForComparison(filename);
|
|
65
|
+
const imports = await extractFileImports(baseDir, filename);
|
|
66
|
+
fileImportsMap.set(normalizedPath, imports);
|
|
67
|
+
for (const imp of imports) {
|
|
68
|
+
addImporter(imp);
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
71
|
+
};
|
|
72
|
+
export const updateImportCacheForFile = async (baseDir, filename) => {
|
|
73
|
+
if (!isSnippetExtension(getFileExtension(filename))) {
|
|
74
|
+
return { newlyImported: [], noLongerImported: [] };
|
|
75
|
+
}
|
|
76
|
+
const normalizedPath = normalizePathForComparison(filename);
|
|
77
|
+
const newImports = await extractFileImports(baseDir, filename);
|
|
78
|
+
const oldImports = fileImportsMap.get(normalizedPath) ?? new Set();
|
|
79
|
+
const newlyImported = [];
|
|
80
|
+
const noLongerImported = [];
|
|
81
|
+
for (const imp of newImports) {
|
|
82
|
+
if (!oldImports.has(imp) && addImporter(imp)) {
|
|
83
|
+
newlyImported.push(imp);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const imp of oldImports) {
|
|
87
|
+
if (!newImports.has(imp) && removeImporter(imp)) {
|
|
88
|
+
noLongerImported.push(imp);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
fileImportsMap.set(normalizedPath, newImports);
|
|
92
|
+
return { newlyImported, noLongerImported };
|
|
93
|
+
};
|
|
94
|
+
export const removeFromImportCache = (filename) => {
|
|
95
|
+
const normalizedPath = normalizePathForComparison(filename);
|
|
96
|
+
const oldImports = fileImportsMap.get(normalizedPath);
|
|
97
|
+
if (oldImports == null) {
|
|
98
|
+
return { newlyImported: [], noLongerImported: [] };
|
|
99
|
+
}
|
|
100
|
+
const noLongerImported = [];
|
|
101
|
+
for (const imp of oldImports) {
|
|
102
|
+
if (removeImporter(imp)) {
|
|
103
|
+
noLongerImported.push(imp);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
fileImportsMap.delete(normalizedPath);
|
|
107
|
+
return { newlyImported: [], noLongerImported };
|
|
108
|
+
};
|
|
109
|
+
export const getImportedFilesFromCache = () => {
|
|
110
|
+
return new Set(Array.from(importerCounts.keys(), (key) => key.toLowerCase()));
|
|
111
|
+
};
|
|
112
|
+
const isSnippetByFolder = (path) => {
|
|
113
|
+
const normalized = normalizePathForComparison(path).toLowerCase();
|
|
114
|
+
return normalized.startsWith('/snippets/') || normalized.startsWith('/_snippets/');
|
|
115
|
+
};
|
|
116
|
+
const resolveFileImports = async (sourcePath, relativePath) => {
|
|
117
|
+
let contentStr = (await fse.readFile(sourcePath)).toString();
|
|
118
|
+
const tree = await preparseMdxTree(contentStr, CMD_EXEC_PATH, sourcePath);
|
|
119
|
+
const importsResponse = await findAndRemoveImports(tree);
|
|
120
|
+
if (hasImports(importsResponse)) {
|
|
121
|
+
contentStr = stringifyTree(await resolveAllImports({ ...importsResponse, filename: relativePath }));
|
|
122
|
+
}
|
|
123
|
+
return contentStr;
|
|
124
|
+
};
|
|
125
|
+
export const syncImportedFileLocations = async (changes) => {
|
|
126
|
+
for (const importedPath of changes.newlyImported) {
|
|
127
|
+
if (isSnippetByFolder(importedPath))
|
|
128
|
+
continue;
|
|
129
|
+
if (!isSnippetExtension(getFileExtension(importedPath)))
|
|
130
|
+
continue;
|
|
131
|
+
const relativePath = optionallyRemoveLeadingSlash(importedPath);
|
|
132
|
+
const sourcePath = join(CMD_EXEC_PATH, relativePath);
|
|
133
|
+
const targetPath = join(NEXT_PUBLIC_PATH, relativePath);
|
|
134
|
+
try {
|
|
135
|
+
const contentStr = await resolveFileImports(sourcePath, relativePath);
|
|
136
|
+
await fse.outputFile(targetPath, contentStr, { flag: 'w' });
|
|
137
|
+
await fse.remove(join(NEXT_PROPS_PATH, relativePath));
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
console.log('Error processing newly imported snippet');
|
|
141
|
+
console.log(relativePath);
|
|
142
|
+
console.log(err);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
for (const importedPath of changes.noLongerImported) {
|
|
146
|
+
if (isSnippetByFolder(importedPath))
|
|
147
|
+
continue;
|
|
148
|
+
if (!isSnippetExtension(getFileExtension(importedPath)))
|
|
149
|
+
continue;
|
|
150
|
+
const relativePath = optionallyRemoveLeadingSlash(importedPath);
|
|
151
|
+
const sourcePath = join(CMD_EXEC_PATH, relativePath);
|
|
152
|
+
await fse.remove(join(NEXT_PUBLIC_PATH, relativePath));
|
|
153
|
+
if (getFileCategory(relativePath) !== 'page')
|
|
154
|
+
continue;
|
|
155
|
+
if (await fse.pathExists(sourcePath)) {
|
|
156
|
+
try {
|
|
157
|
+
const contentStr = await resolveFileImports(sourcePath, relativePath);
|
|
158
|
+
const { pageContent } = await createPage(relativePath, contentStr, CMD_EXEC_PATH, [], [], true);
|
|
159
|
+
await fse.outputFile(join(NEXT_PROPS_PATH, relativePath), pageContent, { flag: 'w' });
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
console.log('Error regenerating page after import status change');
|
|
163
|
+
console.log(relativePath);
|
|
164
|
+
console.log(err);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
@@ -14,6 +14,7 @@ import { AddedLog, DeletedLog, EditedLog, WarningLog, InfoLog, ErrorLog } from '
|
|
|
14
14
|
import { generateDependentSnippets } from './generateDependentSnippets.js';
|
|
15
15
|
import { generatePagesWithImports } from './generatePagesWithImports.js';
|
|
16
16
|
import { getDocsState } from './getDocsState.js';
|
|
17
|
+
import { initializeImportCache, updateImportCacheForFile, removeFromImportCache, getImportedFilesFromCache, syncImportedFileLocations, } from './importCache.js';
|
|
17
18
|
import { resolveAllImports } from './resolveAllImports.js';
|
|
18
19
|
import { updateCustomLanguages, updateGeneratedNav, updateOpenApiFiles, upsertOpenApiFile, } from './update.js';
|
|
19
20
|
import { getMintIgnoreGlobs, isFileSizeValid, isJsonValid, shouldRegenerateNavForPage, } from './utils.js';
|
|
@@ -72,7 +73,13 @@ const onUnlinkEvent = async (filename, options) => {
|
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
74
75
|
try {
|
|
75
|
-
const
|
|
76
|
+
const importedFiles = getImportedFilesFromCache();
|
|
77
|
+
const potentialCategory = getFileCategory(filename, { importedFiles });
|
|
78
|
+
if (potentialCategory == null) {
|
|
79
|
+
const importChanges = removeFromImportCache(filename);
|
|
80
|
+
await syncImportedFileLocations(importChanges);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
76
83
|
const targetPath = getTargetPath(potentialCategory, filename);
|
|
77
84
|
if (potentialCategory === 'page' ||
|
|
78
85
|
potentialCategory === 'snippet' ||
|
|
@@ -99,13 +106,18 @@ const onUnlinkEvent = async (filename, options) => {
|
|
|
99
106
|
try {
|
|
100
107
|
await fse.emptyDir(NEXT_PUBLIC_PATH);
|
|
101
108
|
await fse.emptyDir(NEXT_PROPS_PATH);
|
|
102
|
-
await prebuild(CMD_EXEC_PATH, options);
|
|
109
|
+
const prebuildResult = await prebuild(CMD_EXEC_PATH, options);
|
|
110
|
+
if (prebuildResult) {
|
|
111
|
+
await initializeImportCache(CMD_EXEC_PATH, prebuildResult.fileImportsMap);
|
|
112
|
+
}
|
|
103
113
|
}
|
|
104
114
|
catch (err) {
|
|
105
115
|
console.error('Error rebuilding after .mintignore deletion:', err);
|
|
106
116
|
}
|
|
107
117
|
break;
|
|
108
118
|
}
|
|
119
|
+
const importChanges = removeFromImportCache(filename);
|
|
120
|
+
await syncImportedFileLocations(importChanges);
|
|
109
121
|
addChangeLog(_jsx(DeletedLog, { filename: filename }));
|
|
110
122
|
}
|
|
111
123
|
catch (error) {
|
|
@@ -159,13 +171,20 @@ const validateConfigFiles = async () => {
|
|
|
159
171
|
*/
|
|
160
172
|
const onUpdateEvent = async (filename, callback, options = {}) => {
|
|
161
173
|
const filePath = pathUtil.join(CMD_EXEC_PATH, filename);
|
|
162
|
-
const
|
|
163
|
-
|
|
174
|
+
const importChanges = await updateImportCacheForFile(CMD_EXEC_PATH, filename);
|
|
175
|
+
await syncImportedFileLocations(importChanges);
|
|
176
|
+
const importedFiles = getImportedFilesFromCache();
|
|
177
|
+
const potentialCategory = getFileCategory(filename, { importedFiles });
|
|
178
|
+
if (potentialCategory == null) {
|
|
179
|
+
callback();
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
164
182
|
let regenerateNav = false;
|
|
165
183
|
let category = potentialCategory === 'potentialYamlOpenApiSpec' ||
|
|
166
184
|
potentialCategory === 'potentialJsonOpenApiSpec'
|
|
167
185
|
? 'staticFile'
|
|
168
186
|
: potentialCategory;
|
|
187
|
+
const targetPath = getTargetPath(potentialCategory, filename);
|
|
169
188
|
switch (potentialCategory) {
|
|
170
189
|
case 'page': {
|
|
171
190
|
let contentStr = (await readFile(filePath)).toString();
|
|
@@ -227,7 +246,10 @@ const onUpdateEvent = async (filename, callback, options = {}) => {
|
|
|
227
246
|
addChangeLog(_jsx(InfoLog, { message: ".mintignore has been updated. Rebuilding..." }));
|
|
228
247
|
await fse.emptyDir(NEXT_PUBLIC_PATH);
|
|
229
248
|
await fse.emptyDir(NEXT_PROPS_PATH);
|
|
230
|
-
await prebuild(CMD_EXEC_PATH, options);
|
|
249
|
+
const prebuildResult = await prebuild(CMD_EXEC_PATH, options);
|
|
250
|
+
if (prebuildResult) {
|
|
251
|
+
await initializeImportCache(CMD_EXEC_PATH, prebuildResult.fileImportsMap);
|
|
252
|
+
}
|
|
231
253
|
}
|
|
232
254
|
catch (err) {
|
|
233
255
|
console.error(err.message);
|
|
@@ -291,4 +313,5 @@ const onUpdateEvent = async (filename, callback, options = {}) => {
|
|
|
291
313
|
callback();
|
|
292
314
|
return category;
|
|
293
315
|
};
|
|
316
|
+
export { initializeImportCache };
|
|
294
317
|
export default listener;
|
|
@@ -8,3 +8,4 @@ export declare const isJsonValid: (filePath: string) => {
|
|
|
8
8
|
error?: string;
|
|
9
9
|
};
|
|
10
10
|
export declare const shouldRegenerateNavForPage: (filename: string, contentStr: string, frontmatterHashes: Map<string, string>) => Promise<boolean>;
|
|
11
|
+
export declare function normalizePathForComparison(filePath: string): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseFrontmatter, processMintIgnoreString } from '@mintlify/common';
|
|
1
|
+
import { parseFrontmatter, processMintIgnoreString, optionallyAddLeadingSlash, } from '@mintlify/common';
|
|
2
2
|
import crypto from 'crypto';
|
|
3
3
|
import { promises as _promises, readFileSync, existsSync } from 'fs';
|
|
4
4
|
import fse from 'fs-extra';
|
|
@@ -65,3 +65,6 @@ export const shouldRegenerateNavForPage = async (filename, contentStr, frontmatt
|
|
|
65
65
|
return true;
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
|
+
export function normalizePathForComparison(filePath) {
|
|
69
|
+
return optionallyAddLeadingSlash(filePath).toLowerCase();
|
|
70
|
+
}
|
|
@@ -3,11 +3,11 @@ import open from 'better-opn';
|
|
|
3
3
|
import express from 'express';
|
|
4
4
|
import { createServer } from 'http';
|
|
5
5
|
import { Server as SocketServer } from 'socket.io';
|
|
6
|
-
import { NEXT_PUBLIC_PATH } from '../constants.js';
|
|
6
|
+
import { CMD_EXEC_PATH, NEXT_PUBLIC_PATH } from '../constants.js';
|
|
7
7
|
import { addLog, removeLastLog } from '../logging-state.js';
|
|
8
8
|
import { LaunchLog, UpdateLog } from '../logs.js';
|
|
9
9
|
import { maybeFixMissingWindowsEnvVar } from '../util.js';
|
|
10
|
-
import listener from './listener/index.js';
|
|
10
|
+
import listener, { initializeImportCache } from './listener/index.js';
|
|
11
11
|
import { getLocalNetworkIp } from './network.js';
|
|
12
12
|
import { setupNext } from './setupNext.js';
|
|
13
13
|
export const run = async (argv) => {
|
|
@@ -48,5 +48,6 @@ export const run = async (argv) => {
|
|
|
48
48
|
process.on('SIGINT', onExit);
|
|
49
49
|
process.on('SIGTERM', onExit);
|
|
50
50
|
});
|
|
51
|
+
await initializeImportCache(CMD_EXEC_PATH, argv.fileImportsMap);
|
|
51
52
|
listener(onChange);
|
|
52
53
|
};
|