mintlify 1.3.0 → 2.0.3

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.
Files changed (64) hide show
  1. package/CONTRIBUTING.md +2 -0
  2. package/README.md +3 -3
  3. package/bin/local-preview/index.js +14 -60
  4. package/bin/local-preview/index.js.map +1 -1
  5. package/bin/local-preview/listener/categorizeFiles.js +47 -0
  6. package/bin/local-preview/listener/categorizeFiles.js.map +1 -0
  7. package/bin/local-preview/listener/generate.js +89 -0
  8. package/bin/local-preview/listener/generate.js.map +1 -0
  9. package/bin/local-preview/listener/index.js +135 -0
  10. package/bin/local-preview/listener/index.js.map +1 -0
  11. package/bin/local-preview/listener/update.js +41 -0
  12. package/bin/local-preview/listener/update.js.map +1 -0
  13. package/bin/local-preview/listener/utils/createPage.js +167 -0
  14. package/bin/local-preview/listener/utils/createPage.js.map +1 -0
  15. package/bin/local-preview/listener/utils/fileIsMdxOrMd.js +12 -0
  16. package/bin/local-preview/listener/utils/fileIsMdxOrMd.js.map +1 -0
  17. package/bin/local-preview/listener/utils/getOpenApiContext.js +57 -0
  18. package/bin/local-preview/listener/utils/getOpenApiContext.js.map +1 -0
  19. package/bin/local-preview/listener/utils/mintConfigFile.js +22 -0
  20. package/bin/local-preview/listener/utils/mintConfigFile.js.map +1 -0
  21. package/bin/local-preview/listener/utils/toTitleCase.js +36 -0
  22. package/bin/local-preview/listener/utils/toTitleCase.js.map +1 -0
  23. package/bin/local-preview/listener/utils/types.js +2 -0
  24. package/bin/local-preview/listener/utils/types.js.map +1 -0
  25. package/bin/local-preview/listener/utils.js +62 -0
  26. package/bin/local-preview/listener/utils.js.map +1 -0
  27. package/bin/local-preview/utils/mintConfigFile.js +1 -1
  28. package/bin/local-preview/utils/mintConfigFile.js.map +1 -1
  29. package/bin/scraping/detectFramework.js +1 -1
  30. package/bin/scraping/detectFramework.js.map +1 -1
  31. package/bin/scraping/scrapePageCommands.js +2 -2
  32. package/bin/scraping/scrapePageCommands.js.map +1 -1
  33. package/bin/scraping/site-scrapers/alternateGroupTitle.js +1 -1
  34. package/bin/scraping/site-scrapers/alternateGroupTitle.js.map +1 -1
  35. package/bin/scraping/site-scrapers/openNestedDocusaurusMenus.js +3 -3
  36. package/bin/scraping/site-scrapers/openNestedDocusaurusMenus.js.map +1 -1
  37. package/bin/scraping/site-scrapers/openNestedGitbookMenus.js +1 -2
  38. package/bin/scraping/site-scrapers/openNestedGitbookMenus.js.map +1 -1
  39. package/package.json +12 -6
  40. package/src/local-preview/index.ts +19 -74
  41. package/src/local-preview/listener/categorizeFiles.ts +55 -0
  42. package/src/local-preview/listener/generate.ts +110 -0
  43. package/src/local-preview/listener/index.ts +169 -0
  44. package/src/local-preview/listener/update.ts +45 -0
  45. package/src/local-preview/listener/utils/createPage.ts +211 -0
  46. package/src/local-preview/listener/utils/fileIsMdxOrMd.ts +11 -0
  47. package/src/local-preview/{utils → listener/utils}/getOpenApiContext.ts +0 -0
  48. package/src/local-preview/listener/utils/mintConfigFile.ts +28 -0
  49. package/src/local-preview/listener/utils/toTitleCase.ts +40 -0
  50. package/src/local-preview/listener/utils/types.ts +1 -0
  51. package/src/local-preview/listener/utils.ts +69 -0
  52. package/src/scraping/scrapePageCommands.ts +2 -2
  53. package/tsconfig.json +6 -5
  54. package/bin/init-command/index.js +0 -51
  55. package/bin/init-command/index.js.map +0 -1
  56. package/bin/init-command/templates.js +0 -41
  57. package/bin/init-command/templates.js.map +0 -1
  58. package/src/local-preview/utils/categorizeFiles.ts +0 -82
  59. package/src/local-preview/utils/injectFavicons.ts +0 -76
  60. package/src/local-preview/utils/listener.ts +0 -124
  61. package/src/local-preview/utils/metadata.ts +0 -151
  62. package/src/local-preview/utils/mintConfigFile.ts +0 -48
  63. package/src/local-preview/utils/openApiCheck.ts +0 -18
  64. package/src/local-preview/utils/slugToTitle.ts +0 -7
@@ -6,80 +6,14 @@ import inquirer from "inquirer";
6
6
  import { isInternetAvailable } from "is-internet-available";
7
7
  import path from "path";
8
8
  import shell from "shelljs";
9
- import categorizeFiles from "./utils/categorizeFiles.js";
10
9
  import {
11
- CMD_EXEC_PATH,
12
10
  CLIENT_PATH,
13
11
  HOME_DIR,
14
12
  DOT_MINTLIFY,
13
+ CMD_EXEC_PATH,
15
14
  } from "../constants.js";
16
- import { injectFavicons } from "./utils/injectFavicons.js";
17
- import listener from "./utils/listener.js";
18
- import { createPage, createMetadataFileFromPages } from "./utils/metadata.js";
19
- import { updateConfigFile } from "./utils/mintConfigFile.js";
20
15
  import { buildLogger, ensureYarn } from "../util.js";
21
-
22
- const { readFile } = _promises;
23
-
24
- const copyFiles = async (logger: any) => {
25
- logger.start("Syncing doc files...");
26
- shell.cd(CMD_EXEC_PATH);
27
- const { markdownFiles, staticFiles, openApi } = await categorizeFiles();
28
-
29
- const configObj = await updateConfigFile(logger);
30
-
31
- const openApiTargetPath = path.join(CLIENT_PATH, "src", "openapi.json");
32
- if (openApi) {
33
- logger.succeed("OpenApi file synced");
34
- await fse.outputFile(openApiTargetPath, JSON.stringify(openApi), {
35
- flag: "w",
36
- });
37
- } else {
38
- await fse.outputFile(openApiTargetPath, "{}", { flag: "w" });
39
- }
40
- let pages = {};
41
- const mdPromises = [];
42
- markdownFiles.forEach((filename) => {
43
- mdPromises.push(
44
- (async () => {
45
- const sourcePath = path.join(CMD_EXEC_PATH, filename);
46
- const pagesDir = path.join(CLIENT_PATH, "src", "pages");
47
- const targetPath = path.join(pagesDir, filename);
48
-
49
- await fse.remove(targetPath);
50
- await fse.copy(sourcePath, targetPath);
51
-
52
- const fileContent = await readFile(sourcePath);
53
- const contentStr = fileContent.toString();
54
- const page = createPage(filename, contentStr, openApi);
55
- pages = {
56
- ...pages,
57
- ...page,
58
- };
59
- })()
60
- );
61
- });
62
- const staticFilePromises = [];
63
- staticFiles.forEach((filename) => {
64
- staticFilePromises.push(
65
- (async () => {
66
- const sourcePath = path.join(CMD_EXEC_PATH, filename);
67
- const publicDir = path.join(CLIENT_PATH, "public");
68
- const targetPath = path.join(publicDir, filename);
69
-
70
- await fse.remove(targetPath);
71
- await fse.copy(sourcePath, targetPath);
72
- })()
73
- );
74
- });
75
- await Promise.all([
76
- ...mdPromises,
77
- ...staticFilePromises,
78
- await injectFavicons(configObj, logger),
79
- ]);
80
- createMetadataFileFromPages(pages, configObj);
81
- logger.succeed("All files synced");
82
- };
16
+ import listener from "./listener/index.js";
83
17
 
84
18
  const shellExec = (cmd: string) => {
85
19
  return shell.exec(cmd, { silent: true });
@@ -116,7 +50,19 @@ const dev = async () => {
116
50
  await promptForYarn();
117
51
  const logger = buildLogger("Starting a local Mintlify instance...");
118
52
  await fse.ensureDir(path.join(DOT_MINTLIFY, "mint"));
119
- shell.cd(path.join(HOME_DIR, ".mintlify", "mint"));
53
+ const MINT_PATH = path.join(DOT_MINTLIFY, "mint");
54
+ shell.cd(MINT_PATH);
55
+ const gitPullStatus = shellExec("git show").stdout;
56
+ const currBranch = shellExec("git rev-parse --abbrev-ref HEAD").stdout;
57
+ if (
58
+ gitPullStatus.startsWith(
59
+ "commit 78d764335877932a0dc305d615411dedd18bd18a"
60
+ ) ||
61
+ currBranch === "legacy-components-import"
62
+ ) {
63
+ await fse.emptyDir(MINT_PATH);
64
+ }
65
+
120
66
  let runYarn = true;
121
67
  const gitInstalled = shell.which("git");
122
68
  let firstInstallation = false;
@@ -144,9 +90,7 @@ const dev = async () => {
144
90
  if (internet && gitInstalled) {
145
91
  shellExec("git config core.sparseCheckout true");
146
92
  shellExec('echo "client/" >> .git/info/sparse-checkout');
147
- pullOutput = shellExec(
148
- "git pull mint-origin legacy-components-import"
149
- ).stdout;
93
+ pullOutput = shellExec("git pull mint-origin main").stdout;
150
94
  shellExec("git config core.sparseCheckout false");
151
95
  shellExec("rm .git/info/sparse-checkout");
152
96
  }
@@ -176,7 +120,8 @@ const dev = async () => {
176
120
  `);
177
121
  process.exit(1);
178
122
  }
179
- await copyFiles(logger);
123
+ shellExec(`yarn preconfigure ../../../../..${CMD_EXEC_PATH}`);
124
+ logger.succeed("Local Mintlify instance initialized");
180
125
  run();
181
126
  };
182
127
 
@@ -187,7 +132,7 @@ const run = () => {
187
132
  "Navigate to your local preview at http://localhost:3000"
188
133
  )}`
189
134
  );
190
- shell.exec("npm run dev", { async: true });
135
+ shell.exec("npm run dev-watch", { async: true });
191
136
  open("http://localhost:3000");
192
137
  listener();
193
138
  };
@@ -0,0 +1,55 @@
1
+ // TODO - put in prebuild package
2
+ import path from "path";
3
+
4
+ import { getFileExtension, openApiCheck, getFileList } from "./utils.js";
5
+
6
+ const categorizeFiles = async (contentDirectoryPath: string) => {
7
+ const allFilesInCmdExecutionPath = await getFileList(contentDirectoryPath);
8
+ const contentFilenames = [];
9
+ const staticFilenames = [];
10
+ const promises = [];
11
+ const openApiFiles = [];
12
+ const snippets = [];
13
+ allFilesInCmdExecutionPath.forEach((filename) => {
14
+ promises.push(
15
+ (async () => {
16
+ const extension = getFileExtension(filename);
17
+ let isOpenApi = false;
18
+ if (extension && (extension === "mdx" || extension === "md")) {
19
+ if (filename.startsWith("/_snippets")) {
20
+ snippets.push(filename);
21
+ } else {
22
+ contentFilenames.push(filename);
23
+ }
24
+ } else if (
25
+ extension &&
26
+ (extension === "json" || extension === "yaml" || extension === "yml")
27
+ ) {
28
+ const openApiInfo = await openApiCheck(
29
+ path.join(contentDirectoryPath, filename)
30
+ );
31
+ isOpenApi = openApiInfo.isOpenApi;
32
+ if (isOpenApi) {
33
+ const fileName = path.parse(filename).base;
34
+ openApiFiles.push({
35
+ filename: fileName.substring(0, fileName.lastIndexOf(".")),
36
+ spec: openApiInfo.spec,
37
+ });
38
+ }
39
+ } else if (
40
+ (!filename.endsWith("mint.config.json") ||
41
+ !filename.endsWith("mint.json")) &&
42
+ !isOpenApi
43
+ ) {
44
+ // all other files
45
+ staticFilenames.push(filename);
46
+ }
47
+ })()
48
+ );
49
+ });
50
+ await Promise.all(promises);
51
+
52
+ return { contentFilenames, staticFilenames, openApiFiles, snippets };
53
+ };
54
+
55
+ export default categorizeFiles;
@@ -0,0 +1,110 @@
1
+ // TODO - add types
2
+ import { promises as _promises } from "fs";
3
+ import { outputFile } from "fs-extra";
4
+ import path from "path";
5
+ import createPage from "./utils/createPage.js";
6
+ import { OpenApiFile } from "./utils/types.js";
7
+ import categorizeFiles from "./categorizeFiles.js";
8
+ import { CMD_EXEC_PATH } from "../../constants.js";
9
+ import { getConfigObj } from "./utils/mintConfigFile.js";
10
+ const { readFile } = _promises;
11
+
12
+ // TODO: Put in prebuild package
13
+ const generateNavFromPages = (pages, mintConfigNav) => {
14
+ const createNav = (nav) => {
15
+ return {
16
+ group: nav.group,
17
+ version: nav.version,
18
+ pages: nav.pages.map((page) => {
19
+ if (typeof page === "string") {
20
+ return pages[page];
21
+ }
22
+ return createNav(page);
23
+ }),
24
+ };
25
+ };
26
+
27
+ if (mintConfigNav == null) {
28
+ return;
29
+ }
30
+
31
+ let navFile = mintConfigNav.map((nav) => createNav(nav));
32
+ const filterOutNullInPages = (pages) => {
33
+ const newPages = [];
34
+ pages.forEach((page) => {
35
+ if (page == null) {
36
+ return;
37
+ }
38
+ if (page?.pages) {
39
+ const newGroup = filterOutNullInGroup(page);
40
+ newPages.push(newGroup);
41
+ } else {
42
+ newPages.push(page);
43
+ }
44
+ });
45
+
46
+ return newPages;
47
+ };
48
+ const filterOutNullInGroup = (group) => {
49
+ const newPages = filterOutNullInPages(group.pages);
50
+ const newGroup = {
51
+ ...group,
52
+ pages: newPages,
53
+ };
54
+ return newGroup;
55
+ };
56
+ const newNavFile = navFile.map((group) => {
57
+ return filterOutNullInGroup(group);
58
+ });
59
+ return newNavFile;
60
+ };
61
+
62
+ // TODO: Put in prebuild package
63
+ const createPagesAcc = async (
64
+ contentDirectoryPath: string,
65
+ contentFilenames: string[],
66
+ openApiFiles: OpenApiFile[],
67
+ clientPath?: string,
68
+ writeFiles = false
69
+ ) => {
70
+ let pagesAcc = {};
71
+ const contentPromises = [];
72
+ contentFilenames.forEach((filename) => {
73
+ contentPromises.push(
74
+ (async () => {
75
+ const sourcePath = path.join(contentDirectoryPath, filename);
76
+
77
+ const contentStr = (await readFile(sourcePath)).toString();
78
+ const { slug, pageMetadata, pageContent } = await createPage(
79
+ filename,
80
+ contentStr,
81
+ contentDirectoryPath,
82
+ openApiFiles
83
+ );
84
+ if (clientPath && writeFiles) {
85
+ const targetPath = path.join(clientPath, "src", "_props", filename);
86
+ await outputFile(targetPath, pageContent, {
87
+ flag: "w",
88
+ });
89
+ }
90
+ pagesAcc = {
91
+ ...pagesAcc,
92
+ [slug]: pageMetadata,
93
+ };
94
+ })()
95
+ );
96
+ });
97
+ await Promise.all(contentPromises);
98
+ return pagesAcc;
99
+ };
100
+
101
+ export const generateNav = async () => {
102
+ const { contentFilenames, openApiFiles } = await categorizeFiles(
103
+ CMD_EXEC_PATH
104
+ );
105
+ const [pageAcc, configObj] = await Promise.all([
106
+ createPagesAcc(CMD_EXEC_PATH, contentFilenames, openApiFiles),
107
+ getConfigObj(CMD_EXEC_PATH),
108
+ ]);
109
+ return generateNavFromPages(pageAcc, configObj?.navigation);
110
+ };
@@ -0,0 +1,169 @@
1
+ import chokidar from "chokidar";
2
+ import fse from "fs-extra";
3
+ import pathUtil from "path";
4
+ import { fileIsMdxOrMd } from "./utils/fileIsMdxOrMd.js";
5
+ import { openApiCheck } from "./utils.js";
6
+ import { updateGeneratedNav, updateOpenApiFiles } from "./update.js";
7
+ import { CLIENT_PATH, CMD_EXEC_PATH } from "../../constants.js";
8
+ import { promises as _promises } from "fs";
9
+ import createPage from "./utils/createPage.js";
10
+
11
+ const { readFile } = _promises;
12
+
13
+ const listener = () => {
14
+ chokidar
15
+ .watch(CMD_EXEC_PATH, {
16
+ ignoreInitial: true,
17
+ ignored: ["node_modules", ".git"],
18
+ cwd: CMD_EXEC_PATH,
19
+ })
20
+ .on("all", async (event, filename) => {
21
+ if (event === "unlink" || event === "unlinkDir") {
22
+ if (fileIsMdxOrMd(filename)) {
23
+ const targetPath = pathUtil.join(
24
+ CLIENT_PATH,
25
+ "src",
26
+ "_props",
27
+ filename
28
+ );
29
+ await fse.remove(targetPath);
30
+ console.log(
31
+ `${
32
+ filename.startsWith("_snippets") ? "Snippet" : "Page"
33
+ } deleted: `,
34
+ filename
35
+ );
36
+ } else if (filename === "mint.json") {
37
+ const targetPath = pathUtil.join(
38
+ CLIENT_PATH,
39
+ "src",
40
+ "_props",
41
+ "mint.json"
42
+ );
43
+ await fse.remove(targetPath);
44
+ console.log(
45
+ "⚠️ mint.json deleted. Please create a new mint.json file as it is mandatory."
46
+ );
47
+ process.exit(1);
48
+ } else {
49
+ const extension = pathUtil.parse(filename).ext.slice(1);
50
+ if (
51
+ extension &&
52
+ (extension === "json" ||
53
+ extension === "yaml" ||
54
+ extension === "yml")
55
+ ) {
56
+ await updateOpenApiFiles();
57
+ await updateGeneratedNav();
58
+ return;
59
+ }
60
+ // all other files
61
+ const targetPath = pathUtil.join(CLIENT_PATH, "public", filename);
62
+ await fse.remove(targetPath);
63
+ console.log("Static file deleted: ", filename);
64
+ }
65
+ } else {
66
+ const filePath = pathUtil.join(CMD_EXEC_PATH, filename);
67
+ let regenerateNav = false;
68
+ if (fileIsMdxOrMd(filename)) {
69
+ const targetPath = pathUtil.join(
70
+ CLIENT_PATH,
71
+ "src",
72
+ "_props",
73
+ filename
74
+ );
75
+ if (filename.startsWith("_snippets")) {
76
+ const sourcePath = pathUtil.join(CMD_EXEC_PATH, filename);
77
+ await fse.remove(targetPath);
78
+ await fse.copy(sourcePath, targetPath);
79
+ return;
80
+ }
81
+ regenerateNav = true;
82
+
83
+ const contentStr = (await readFile(filePath)).toString();
84
+ const { pageContent } = await createPage(
85
+ filename,
86
+ contentStr,
87
+ CMD_EXEC_PATH,
88
+ []
89
+ );
90
+ await fse.outputFile(targetPath, pageContent, {
91
+ flag: "w",
92
+ });
93
+ switch (event) {
94
+ case "add":
95
+ case "addDir":
96
+ console.log("New page detected: ", filename);
97
+ break;
98
+ default:
99
+ console.log("Page edited: ", filename);
100
+ break;
101
+ }
102
+ } else if (filename === "mint.json") {
103
+ regenerateNav = true;
104
+ const targetPath = pathUtil.join(
105
+ CLIENT_PATH,
106
+ "src",
107
+ "_props",
108
+ "mint.json"
109
+ );
110
+ await fse.copy(filePath, targetPath);
111
+ switch (event) {
112
+ case "add":
113
+ case "addDir":
114
+ console.log("Config added");
115
+ break;
116
+ default:
117
+ console.log("Config edited");
118
+ break;
119
+ }
120
+ } else {
121
+ const extension = pathUtil.parse(filename).ext.slice(1);
122
+ let isOpenApi = false;
123
+ if (
124
+ extension &&
125
+ (extension === "json" ||
126
+ extension === "yaml" ||
127
+ extension === "yml")
128
+ ) {
129
+ const openApiInfo = await openApiCheck(
130
+ pathUtil.join(CMD_EXEC_PATH, filename)
131
+ );
132
+ isOpenApi = openApiInfo.isOpenApi;
133
+ if (isOpenApi) {
134
+ await updateOpenApiFiles();
135
+ regenerateNav = true;
136
+ }
137
+ }
138
+ if (!isOpenApi) {
139
+ // all other files
140
+ const targetPath = pathUtil.join(CLIENT_PATH, "public", filename);
141
+ await fse.copy(filePath, targetPath);
142
+ }
143
+ switch (event) {
144
+ case "add":
145
+ case "addDir":
146
+ if (isOpenApi) {
147
+ console.log("OpenApi file added: ", filename);
148
+ } else {
149
+ console.log("Static file added: ", filename);
150
+ }
151
+ break;
152
+ default:
153
+ if (isOpenApi) {
154
+ console.log("OpenApi file edited: ", filename);
155
+ } else {
156
+ console.log("Static file edited: ", filename);
157
+ }
158
+ break;
159
+ }
160
+ }
161
+ if (regenerateNav) {
162
+ // TODO: Instead of re-generating the entire nav, optimize by just updating the specific page that changed.
163
+ await updateGeneratedNav();
164
+ }
165
+ }
166
+ });
167
+ };
168
+
169
+ export default listener;
@@ -0,0 +1,45 @@
1
+ // TODO: Add Types
2
+ import fse from "fs-extra";
3
+ import { promises as _promises } from "fs";
4
+ import { getConfigPath } from "./utils/mintConfigFile.js";
5
+ import { CLIENT_PATH, CMD_EXEC_PATH } from "../../constants.js";
6
+ import { join } from "path";
7
+ import { generateNav } from "./generate.js";
8
+ import categorizeFiles from "./categorizeFiles.js";
9
+
10
+ const { readFile } = _promises;
11
+
12
+ // TODO: Put in prebuild package
13
+
14
+ export const updateConfigFile = async (contentDirectoryPath: string) => {
15
+ const configTargetPath = join(CLIENT_PATH, "src/_props/mint.json");
16
+ await fse.remove(configTargetPath);
17
+ let configObj = null;
18
+ const configPath = await getConfigPath(contentDirectoryPath);
19
+
20
+ if (configPath) {
21
+ await fse.remove(configTargetPath);
22
+ await fse.copy(configPath, configTargetPath);
23
+ const configContents = await readFile(configPath);
24
+ configObj = JSON.parse(configContents.toString());
25
+ } else {
26
+ process.exit(1);
27
+ }
28
+ return configObj;
29
+ };
30
+
31
+ export const updateGeneratedNav = async () => {
32
+ const generatedNav = await generateNav();
33
+ const targetPath = join(CLIENT_PATH, "src", "_props", "generatedNav.json");
34
+ await fse.outputFile(targetPath, JSON.stringify(generatedNav, null, 2), {
35
+ flag: "w",
36
+ });
37
+ };
38
+
39
+ export const updateOpenApiFiles = async () => {
40
+ const { openApiFiles } = await categorizeFiles(CMD_EXEC_PATH);
41
+ const targetPath = join(CLIENT_PATH, "src", "_props", "openApiFiles.json");
42
+ await fse.outputFile(targetPath, JSON.stringify(openApiFiles, null, 2), {
43
+ flag: "w",
44
+ });
45
+ };