mintlify 1.0.7 → 1.0.8

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 (249) hide show
  1. package/README.md +21 -5
  2. package/bin/constants.js +8 -0
  3. package/bin/constants.js.map +1 -0
  4. package/bin/dev/getOpenApiContext.js +46 -0
  5. package/bin/dev/getOpenApiContext.js.map +1 -0
  6. package/bin/dev/index.js +164 -0
  7. package/bin/dev/index.js.map +1 -0
  8. package/bin/dev/injectNav.js +97 -0
  9. package/bin/dev/injectNav.js.map +1 -0
  10. package/bin/dev/slugToTitle.js +8 -0
  11. package/bin/dev/slugToTitle.js.map +1 -0
  12. package/bin/index.js +45 -224
  13. package/bin/index.js.map +1 -1
  14. package/bin/init-command/index.js +51 -0
  15. package/bin/init-command/index.js.map +1 -0
  16. package/bin/init-command/templates.js +41 -0
  17. package/bin/init-command/templates.js.map +1 -0
  18. package/bin/local-preview/categorizeFiles.js +56 -0
  19. package/bin/local-preview/categorizeFiles.js.map +1 -0
  20. package/bin/local-preview/getOpenApiContext.js +46 -0
  21. package/bin/local-preview/getOpenApiContext.js.map +1 -0
  22. package/bin/local-preview/index.js +138 -0
  23. package/bin/local-preview/index.js.map +1 -0
  24. package/bin/local-preview/injectFavicons.js +72 -0
  25. package/bin/local-preview/injectFavicons.js.map +1 -0
  26. package/bin/local-preview/listener.js +112 -0
  27. package/bin/local-preview/listener.js.map +1 -0
  28. package/bin/local-preview/metadata.js +121 -0
  29. package/bin/local-preview/metadata.js.map +1 -0
  30. package/bin/local-preview/mintConfigFile.js +43 -0
  31. package/bin/local-preview/mintConfigFile.js.map +1 -0
  32. package/bin/local-preview/openApiCheck.js +16 -0
  33. package/bin/local-preview/openApiCheck.js.map +1 -0
  34. package/bin/local-preview/slugToTitle.js +8 -0
  35. package/bin/local-preview/slugToTitle.js.map +1 -0
  36. package/bin/mint/client/.babel-plugin-macrosrc.json +5 -0
  37. package/bin/mint/client/.babelrc +4 -0
  38. package/bin/mint/client/.editorconfig +12 -0
  39. package/bin/mint/client/.eslintrc.json +7 -0
  40. package/bin/mint/client/.prettierignore +4 -0
  41. package/bin/mint/client/.prettierrc +14 -0
  42. package/bin/mint/client/.vscode/launch.json +28 -0
  43. package/bin/mint/client/README.md +46 -0
  44. package/bin/mint/client/jest.config.ts +195 -0
  45. package/bin/mint/client/next-env.d.ts +4 -0
  46. package/bin/mint/client/next.config.js +152 -0
  47. package/bin/mint/client/package.json +140 -0
  48. package/bin/mint/client/postcss.config.cjs +9 -0
  49. package/bin/mint/client/prebuild/faviconConfig.js +35 -0
  50. package/bin/mint/client/prebuild/getOpenApiContext.js +53 -0
  51. package/bin/mint/client/prebuild/index.js +117 -0
  52. package/bin/mint/client/prebuild/injectNav.js +115 -0
  53. package/bin/mint/client/prebuild/slugToTitle.js +7 -0
  54. package/bin/mint/client/rehype/withApiComponents.js +60 -0
  55. package/bin/mint/client/rehype/withCodeBlocks.js +54 -0
  56. package/bin/mint/client/rehype/withLayouts.js +113 -0
  57. package/bin/mint/client/rehype/withLinkRoles.js +13 -0
  58. package/bin/mint/client/rehype/withRawComponents.js +13 -0
  59. package/bin/mint/client/rehype/withStaticProps.js +25 -0
  60. package/bin/mint/client/rehype/withSyntaxHighlighting.js +60 -0
  61. package/bin/mint/client/remark/utils.js +369 -0
  62. package/bin/mint/client/remark/withFrames.js +55 -0
  63. package/bin/mint/client/remark/withImportsInjected.js +36 -0
  64. package/bin/mint/client/remark/withNextLinks.js +37 -0
  65. package/bin/mint/client/remark/withTableOfContents.js +71 -0
  66. package/bin/mint/client/scripts/local-to-docs.js +72 -0
  67. package/bin/mint/client/scripts/local.js +177 -0
  68. package/bin/mint/client/sentry.client.config.js +15 -0
  69. package/bin/mint/client/sentry.properties +4 -0
  70. package/bin/mint/client/sentry.server.config.js +15 -0
  71. package/bin/mint/client/src/analytics/AbstractAnalyticsImplementation.ts +50 -0
  72. package/bin/mint/client/src/analytics/AnalyticsContext.ts +5 -0
  73. package/bin/mint/client/src/analytics/AnalyticsMediator.ts +101 -0
  74. package/bin/mint/client/src/analytics/FakeAnalyticsMediator.ts +9 -0
  75. package/bin/mint/client/src/analytics/GA4Script.tsx +33 -0
  76. package/bin/mint/client/src/analytics/implementations/amplitude.ts +26 -0
  77. package/bin/mint/client/src/analytics/implementations/fathom.ts +38 -0
  78. package/bin/mint/client/src/analytics/implementations/ga4.ts +33 -0
  79. package/bin/mint/client/src/analytics/implementations/hotjar.ts +53 -0
  80. package/bin/mint/client/src/analytics/implementations/mixpanel-browser.d.ts +1 -0
  81. package/bin/mint/client/src/analytics/implementations/mixpanel.ts +52 -0
  82. package/bin/mint/client/src/analytics/implementations/posthog.ts +37 -0
  83. package/bin/mint/client/src/components/Accordion/Accordion.tsx +43 -0
  84. package/bin/mint/client/src/components/Accordion/index.ts +4 -0
  85. package/bin/mint/client/src/components/ApiExample.tsx +9 -0
  86. package/bin/mint/client/src/components/Card.tsx +51 -0
  87. package/bin/mint/client/src/components/CodeGroup.tsx +132 -0
  88. package/bin/mint/client/src/components/Editor.tsx +12 -0
  89. package/bin/mint/client/src/components/Expandable.tsx +40 -0
  90. package/bin/mint/client/src/components/Heading.tsx +84 -0
  91. package/bin/mint/client/src/components/Param.tsx +56 -0
  92. package/bin/mint/client/src/components/Request.tsx +19 -0
  93. package/bin/mint/client/src/components/ResponseField.tsx +33 -0
  94. package/bin/mint/client/src/components/TabBar.tsx +61 -0
  95. package/bin/mint/client/src/config.ts +115 -0
  96. package/bin/mint/client/src/css/bar-of-progress.css +10 -0
  97. package/bin/mint/client/src/css/base.css +29 -0
  98. package/bin/mint/client/src/css/font-awesome.css +7 -0
  99. package/bin/mint/client/src/css/fonts.css +44 -0
  100. package/bin/mint/client/src/css/main.css +11 -0
  101. package/bin/mint/client/src/css/prism.css +270 -0
  102. package/bin/mint/client/src/css/utilities.css +43 -0
  103. package/bin/mint/client/src/enums/components.ts +8 -0
  104. package/bin/mint/client/src/fonts/FiraCode-VF.woff +0 -0
  105. package/bin/mint/client/src/fonts/FiraCode-VF.woff2 +0 -0
  106. package/bin/mint/client/src/fonts/IBMPlexMono-Regular.ttf +0 -0
  107. package/bin/mint/client/src/fonts/IBMPlexMono-SemiBold.ttf +0 -0
  108. package/bin/mint/client/src/fonts/Inter-italic-latin.var.woff2 +0 -0
  109. package/bin/mint/client/src/fonts/Inter-roman-latin.var.woff2 +0 -0
  110. package/bin/mint/client/src/fonts/Pally-Variable.ttf +0 -0
  111. package/bin/mint/client/src/fonts/SourceSansPro-Regular.otf +0 -0
  112. package/bin/mint/client/src/fonts/SourceSerifPro-Regular.ttf +0 -0
  113. package/bin/mint/client/src/fonts/Synonym-Variable.ttf +0 -0
  114. package/bin/mint/client/src/fonts/Ubuntu-Mono-bold.woff2 +0 -0
  115. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.woff2 +0 -0
  116. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.zopfli.woff +0 -0
  117. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular.module.css +11 -0
  118. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.woff2 +0 -0
  119. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.zopfli.woff +0 -0
  120. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold.module.css +11 -0
  121. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.woff2 +0 -0
  122. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.zopfli.woff +0 -0
  123. package/bin/mint/client/src/fonts/generated/Pally-Variable.module.css +11 -0
  124. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.woff2 +0 -0
  125. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.zopfli.woff +0 -0
  126. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular.module.css +11 -0
  127. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.woff2 +0 -0
  128. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.zopfli.woff +0 -0
  129. package/bin/mint/client/src/fonts/generated/Synonym-Variable.module.css +11 -0
  130. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.woff2 +0 -0
  131. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.zopfli.woff +0 -0
  132. package/bin/mint/client/src/fonts/generated/TenorSans-Regular.module.css +11 -0
  133. package/bin/mint/client/src/hooks/useActionKey.ts +20 -0
  134. package/bin/mint/client/src/hooks/useIsomorphicLayoutEffect.ts +3 -0
  135. package/bin/mint/client/src/hooks/useMedia.ts +27 -0
  136. package/bin/mint/client/src/hooks/usePrevNext.ts +34 -0
  137. package/bin/mint/client/src/hooks/useTop.ts +15 -0
  138. package/bin/mint/client/src/icons/CopyToClipboard.tsx +33 -0
  139. package/bin/mint/client/src/index.d.ts +1 -0
  140. package/bin/mint/client/src/layouts/ApiSupplemental.tsx +173 -0
  141. package/bin/mint/client/src/layouts/ContentsLayout.tsx +256 -0
  142. package/bin/mint/client/src/layouts/DocumentationLayout.tsx +44 -0
  143. package/bin/mint/client/src/layouts/OpenApiContent.tsx +301 -0
  144. package/bin/mint/client/src/layouts/SidebarLayout.tsx +412 -0
  145. package/bin/mint/client/src/layouts/UserFeedback.tsx +73 -0
  146. package/bin/mint/client/src/layouts/getGroupsInDivision.ts +25 -0
  147. package/bin/mint/client/src/layouts/isPathInGroupPages.ts +10 -0
  148. package/bin/mint/client/src/metadata.ts +58 -0
  149. package/bin/mint/client/src/openapi.ts +3 -0
  150. package/bin/mint/client/src/pages/404.tsx +73 -0
  151. package/bin/mint/client/src/pages/_app.tsx +138 -0
  152. package/bin/mint/client/src/pages/_document.tsx +57 -0
  153. package/bin/mint/client/src/pages/api/issue.ts +10 -0
  154. package/bin/mint/client/src/pages/api/name.ts +8 -0
  155. package/bin/mint/client/src/pages/api/request.ts +31 -0
  156. package/bin/mint/client/src/pages/api/suggest.ts +10 -0
  157. package/bin/mint/client/src/pages/api/syntax-highlighted-json.ts +13 -0
  158. package/bin/mint/client/src/pages/api/utils.ts +6 -0
  159. package/bin/mint/client/src/pages/index.tsx +31 -0
  160. package/bin/mint/client/src/ui/Api.tsx +359 -0
  161. package/bin/mint/client/src/ui/Footer.tsx +124 -0
  162. package/bin/mint/client/src/ui/Header.tsx +370 -0
  163. package/bin/mint/client/src/ui/Logo.tsx +55 -0
  164. package/bin/mint/client/src/ui/PageHeader.tsx +51 -0
  165. package/bin/mint/client/src/ui/Search.tsx +386 -0
  166. package/bin/mint/client/src/ui/ThemeToggle.tsx +285 -0
  167. package/bin/mint/client/src/ui/Title.tsx +22 -0
  168. package/bin/mint/client/src/ui/TopLevelLink.tsx +122 -0
  169. package/bin/mint/client/src/utils/api.ts +252 -0
  170. package/bin/mint/client/src/utils/brands.ts +217 -0
  171. package/bin/mint/client/src/utils/castArray.ts +3 -0
  172. package/bin/mint/client/src/utils/childrenArray.ts +3 -0
  173. package/bin/mint/client/src/utils/fit.ts +27 -0
  174. package/bin/mint/client/src/utils/fontAwesome.ts +577 -0
  175. package/bin/mint/client/src/utils/getAnalyticsConfig.ts +14 -0
  176. package/bin/mint/client/src/utils/getLogoHref.ts +9 -0
  177. package/bin/mint/client/src/utils/getOpenApiContext.ts +26 -0
  178. package/bin/mint/client/src/utils/importAll.ts +6 -0
  179. package/bin/mint/client/src/utils/isObject.ts +3 -0
  180. package/bin/mint/client/src/utils/kebabToTitleCase.ts +3 -0
  181. package/bin/mint/client/src/utils/loadImage.ts +8 -0
  182. package/bin/mint/client/src/utils/slugToTitle.ts +7 -0
  183. package/bin/mint/client/src/utils/wait.ts +5 -0
  184. package/bin/mint/client/tailwind.config.cjs +323 -0
  185. package/bin/mint/client/test/test.test.ts +5 -0
  186. package/bin/mint/client/tsconfig.json +36 -0
  187. package/bin/mint/client/yarn.lock +9702 -0
  188. package/bin/navigation.js +4 -0
  189. package/bin/navigation.js.map +1 -0
  190. package/bin/pageTemplate.js +30 -0
  191. package/bin/pageTemplate.js.map +1 -0
  192. package/bin/scraping/combineNavWithEmptyGroupTitles.js +20 -0
  193. package/bin/scraping/combineNavWithEmptyGroupTitles.js.map +1 -0
  194. package/bin/scraping/getSitemapLinks.js +2 -0
  195. package/bin/scraping/getSitemapLinks.js.map +1 -1
  196. package/bin/scraping/scrapeFileGettingFileNameFromUrl.js +43 -0
  197. package/bin/scraping/scrapeFileGettingFileNameFromUrl.js.map +1 -0
  198. package/bin/scraping/scrapeGettingFileNameFromUrl.js +12 -41
  199. package/bin/scraping/scrapeGettingFileNameFromUrl.js.map +1 -1
  200. package/bin/scraping/scrapePageCommands.js +48 -0
  201. package/bin/scraping/scrapePageCommands.js.map +1 -0
  202. package/bin/scraping/scrapeSectionCommands.js +90 -0
  203. package/bin/scraping/scrapeSectionCommands.js.map +1 -0
  204. package/bin/scraping/site-scrapers/getLinksRecursively.js +33 -0
  205. package/bin/scraping/site-scrapers/getLinksRecursively.js.map +1 -0
  206. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js +1 -1
  207. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js.map +1 -1
  208. package/bin/scraping/site-scrapers/scrapeGitBookSection.js +25 -48
  209. package/bin/scraping/site-scrapers/scrapeGitBookSection.js.map +1 -1
  210. package/bin/scraping/site-scrapers/scrapeReadMePage.js +2 -1
  211. package/bin/scraping/site-scrapers/scrapeReadMePage.js.map +1 -1
  212. package/bin/scraping/site-scrapers/scrapeReadMeSection.js +10 -20
  213. package/bin/scraping/site-scrapers/scrapeReadMeSection.js.map +1 -1
  214. package/bin/util.js +21 -1
  215. package/bin/util.js.map +1 -1
  216. package/bin/validation/isValidLink.js +11 -0
  217. package/bin/validation/isValidLink.js.map +1 -0
  218. package/bin/validation/stopIfInvalidLink.js +9 -0
  219. package/bin/validation/stopIfInvalidLink.js.map +1 -0
  220. package/package.json +20 -4
  221. package/src/constants.ts +10 -0
  222. package/src/index.ts +110 -272
  223. package/src/init-command/index.ts +59 -0
  224. package/src/{templates.ts → init-command/templates.ts} +0 -0
  225. package/src/local-preview/categorizeFiles.ts +74 -0
  226. package/src/local-preview/getOpenApiContext.ts +61 -0
  227. package/src/local-preview/index.ts +164 -0
  228. package/src/local-preview/injectFavicons.ts +76 -0
  229. package/src/local-preview/listener.ts +116 -0
  230. package/src/local-preview/metadata.ts +154 -0
  231. package/src/local-preview/mintConfigFile.ts +48 -0
  232. package/src/local-preview/openApiCheck.ts +19 -0
  233. package/src/local-preview/slugToTitle.ts +7 -0
  234. package/src/navigation.ts +12 -0
  235. package/src/pageTemplate.ts +32 -0
  236. package/src/scraping/combineNavWithEmptyGroupTitles.ts +21 -0
  237. package/src/scraping/getSitemapLinks.ts +2 -0
  238. package/src/scraping/scrapeFileGettingFileNameFromUrl.ts +81 -0
  239. package/src/scraping/scrapeGettingFileNameFromUrl.ts +27 -58
  240. package/src/scraping/scrapePageCommands.ts +52 -0
  241. package/src/scraping/scrapeSectionCommands.ts +110 -0
  242. package/src/scraping/site-scrapers/getLinksRecursively.ts +40 -0
  243. package/src/scraping/site-scrapers/scrapeDocusaurusSection.ts +1 -1
  244. package/src/scraping/site-scrapers/scrapeGitBookSection.ts +31 -70
  245. package/src/scraping/site-scrapers/scrapeReadMePage.ts +3 -1
  246. package/src/scraping/site-scrapers/scrapeReadMeSection.ts +21 -38
  247. package/src/util.ts +29 -1
  248. package/src/validation/isValidLink.ts +9 -0
  249. package/src/validation/stopIfInvalidLink.ts +9 -0
@@ -0,0 +1,61 @@
1
+ export const extractMethodAndEndpoint = (api) => {
2
+ const methodRegex = /^get|post|put|delete|patch/i;
3
+ const trimmed = api.trim();
4
+ const foundMethod = trimmed.match(methodRegex);
5
+
6
+ const endIndexOfMethod = foundMethod
7
+ ? api.indexOf(foundMethod[0]) + foundMethod[0].length
8
+ : 0;
9
+
10
+ return {
11
+ method: foundMethod ? foundMethod[0].toUpperCase() : undefined,
12
+ endpoint: api.substring(endIndexOfMethod).trim(),
13
+ };
14
+ };
15
+
16
+ export const getOpenApiOperationMethodAndEndpoint = (
17
+ openApiObj,
18
+ openApiMetaField
19
+ ) => {
20
+ const { endpoint, method } = extractMethodAndEndpoint(openApiMetaField);
21
+
22
+ const path = openApiObj?.paths && openApiObj.paths[endpoint];
23
+
24
+ if (path == null) {
25
+ return {};
26
+ }
27
+
28
+ let operation;
29
+ if (method) {
30
+ operation = path[method.toLowerCase()];
31
+ } else {
32
+ const firstOperationKey = Object.keys(path)[0];
33
+ operation = path[firstOperationKey];
34
+ }
35
+
36
+ return {
37
+ operation,
38
+ method,
39
+ endpoint,
40
+ };
41
+ };
42
+
43
+ export const getOpenApiTitleAndDescription = (openApiObj, openApiMetaField) => {
44
+ if (openApiObj == null || !openApiMetaField || openApiMetaField == null) {
45
+ return {};
46
+ }
47
+
48
+ const { operation } = getOpenApiOperationMethodAndEndpoint(
49
+ openApiObj,
50
+ openApiMetaField
51
+ );
52
+
53
+ if (operation == null) {
54
+ return {};
55
+ }
56
+
57
+ return {
58
+ title: operation.summary,
59
+ description: operation.description,
60
+ };
61
+ };
@@ -0,0 +1,164 @@
1
+ import Chalk from "chalk";
2
+ import open from "open";
3
+ import { promises as _promises } from "fs";
4
+ import fse, { pathExists } from "fs-extra";
5
+ import { isInternetAvailable } from "is-internet-available";
6
+ import path from "path";
7
+ import shell from "shelljs";
8
+ import categorizeFiles from "./categorizeFiles.js";
9
+
10
+ import { CMD_EXEC_PATH, CLIENT_PATH, INSTALL_PATH } from "../constants.js";
11
+ import { injectFavicons } from "./injectFavicons.js";
12
+ import listener from "./listener.js";
13
+ import { createPage, createMetadataFileFromPages } from "./metadata.js";
14
+ import { updateConfigFile } from "./mintConfigFile.js";
15
+ import { buildLogger } from "../util.js";
16
+
17
+ const { readFile } = _promises;
18
+
19
+ const copyFiles = async (logger: any) => {
20
+ logger.start("Syncing doc files...");
21
+ shell.cd(CMD_EXEC_PATH);
22
+ const { markdownFiles, staticFiles, openApiBuffer } = await categorizeFiles();
23
+
24
+ const configObj = await updateConfigFile(logger);
25
+
26
+ const openApiTargetPath = path.join(CLIENT_PATH, "src", "openapi.json");
27
+ let openApiObj = null;
28
+ if (openApiBuffer) {
29
+ logger.succeed("OpenApi file synced");
30
+ await fse.outputFile(openApiTargetPath, Buffer.from(openApiBuffer), {
31
+ flag: "w",
32
+ });
33
+ openApiObj = JSON.parse(openApiBuffer.toString());
34
+ } else {
35
+ await fse.outputFile(openApiTargetPath, "{}", { flag: "w" });
36
+ }
37
+ let pages = {};
38
+ const mdPromises = [];
39
+ markdownFiles.forEach((filename) => {
40
+ mdPromises.push(
41
+ (async () => {
42
+ const sourcePath = path.join(CMD_EXEC_PATH, filename);
43
+ const pagesDir = path.join(CLIENT_PATH, "src", "pages");
44
+ const targetPath = path.join(pagesDir, filename);
45
+
46
+ await fse.remove(targetPath);
47
+ await fse.copy(sourcePath, targetPath);
48
+
49
+ const fileContent = await readFile(sourcePath);
50
+ const contentStr = fileContent.toString();
51
+ const page = createPage(filename, contentStr, openApiObj);
52
+ pages = {
53
+ ...pages,
54
+ ...page,
55
+ };
56
+ })()
57
+ );
58
+ });
59
+ const staticFilePromises = [];
60
+ staticFiles.forEach((filename) => {
61
+ staticFilePromises.push(
62
+ (async () => {
63
+ const sourcePath = path.join(CMD_EXEC_PATH, filename);
64
+ const publicDir = path.join(CLIENT_PATH, "public");
65
+ const targetPath = path.join(publicDir, filename);
66
+
67
+ await fse.remove(targetPath);
68
+ await fse.copy(sourcePath, targetPath);
69
+ })()
70
+ );
71
+ });
72
+ await Promise.all([
73
+ ...mdPromises,
74
+ ...staticFilePromises,
75
+ await injectFavicons(configObj, logger),
76
+ ]);
77
+ createMetadataFileFromPages(pages, configObj);
78
+ logger.succeed("All files synced");
79
+ };
80
+
81
+ const gitExists = () => {
82
+ let doesGitExist = true;
83
+ try {
84
+ shell.exec("git --version", { silent: true });
85
+ } catch (e) {
86
+ doesGitExist = false;
87
+ }
88
+ return doesGitExist;
89
+ };
90
+
91
+ const dev = async () => {
92
+ shell.cd(INSTALL_PATH);
93
+ const logger = buildLogger("Starting a local Mintlify instance...");
94
+ if (!(await pathExists(path.join(INSTALL_PATH, "mint")))) {
95
+ shell.exec("mkdir mint");
96
+ }
97
+ shell.cd("mint");
98
+ let runYarn = true;
99
+ const gitInstalled = gitExists();
100
+ let firstInstallation = false;
101
+ if (!(await pathExists(path.join(INSTALL_PATH, "mint", ".git")))) {
102
+ firstInstallation = true;
103
+ if (gitInstalled) {
104
+ logger.start("Initializing local Mintlify instance...");
105
+ shell.exec("git init", { silent: true });
106
+ shell.exec(
107
+ "git remote add -f mint-origin https://github.com/mintlify/mint.git",
108
+ { silent: true }
109
+ );
110
+ } else {
111
+ logger.fail(
112
+ "git must be installed (https://github.com/git-guides/install-git)"
113
+ );
114
+ process.exit(1);
115
+ }
116
+ }
117
+
118
+ const internet = await isInternetAvailable();
119
+ let pullOutput = null;
120
+ if (internet && gitInstalled) {
121
+ shell.exec("git config core.sparseCheckout true", { silent: true });
122
+ shell.exec('echo "client/" >> .git/info/sparse-checkout', { silent: true });
123
+ pullOutput = shell.exec("git pull mint-origin main", {
124
+ silent: true,
125
+ }).stdout;
126
+ shell.exec("git config core.sparseCheckout false", { silent: true });
127
+ shell.exec("rm .git/info/sparse-checkout", { silent: true });
128
+ }
129
+ if (pullOutput === "Already up to date.\n") {
130
+ runYarn = false;
131
+ }
132
+ shell.cd(CLIENT_PATH);
133
+ if (internet && runYarn) {
134
+ if (firstInstallation) {
135
+ logger.succeed("Local Mintlify instance initialized");
136
+ }
137
+ logger.start("Updating dependencies...");
138
+
139
+ shell.exec("yarn", { silent: true });
140
+ if (firstInstallation) {
141
+ logger.succeed("Installation complete");
142
+ } else {
143
+ logger.succeed("Dependencies updated");
144
+ }
145
+ }
146
+
147
+ // TODO check for mint.json before copying over files
148
+ await copyFiles(logger);
149
+ run();
150
+ };
151
+
152
+ const run = () => {
153
+ shell.cd(CLIENT_PATH);
154
+ console.log(
155
+ `🌿 ${Chalk.green(
156
+ "Navigate to your local preview at https://localhost:3000"
157
+ )}`
158
+ );
159
+ shell.exec("npm run dev", { async: true });
160
+ open("http://localhost:3000");
161
+ listener();
162
+ };
163
+
164
+ export default dev;
@@ -0,0 +1,76 @@
1
+ import favicons from "favicons";
2
+ import { promises as _promises } from "fs";
3
+ import { outputFile } from "fs-extra";
4
+ import { join } from "path";
5
+ import { CLIENT_PATH, CMD_EXEC_PATH } from "../constants.js";
6
+
7
+ const { readFile } = _promises;
8
+
9
+ export const injectFavicons = async (configObj, logger) => {
10
+ if (configObj?.favicon == null) return;
11
+
12
+ const desiredPath = join(CMD_EXEC_PATH, configObj.favicon);
13
+ const favicon = await readFile(desiredPath);
14
+ if (favicon == null) return;
15
+ logger.start("Generating favicons...");
16
+ const promises = [];
17
+ try {
18
+ const response = await favicons(favicon, faviconConfig(configObj?.name));
19
+ response.images.forEach((img) => {
20
+ promises.push(
21
+ (async () => {
22
+ const targetPath = join(CLIENT_PATH, "public", "favicons", img.name);
23
+ await outputFile(targetPath, Buffer.from(img.contents), {
24
+ flag: "w",
25
+ });
26
+ })()
27
+ );
28
+ });
29
+ response.files.forEach((file) => {
30
+ promises.push(
31
+ (async () => {
32
+ const targetPath = join(CLIENT_PATH, "public", "favicons", file.name);
33
+ await outputFile(targetPath, file.contents, { flag: "w" });
34
+ })()
35
+ );
36
+ });
37
+ await Promise.all(promises);
38
+ logger.succeed("Favicons generated");
39
+ } catch (err) {
40
+ console.log(err.message); // Error description e.g. "An unknown error has occurred"
41
+ }
42
+ };
43
+
44
+ const faviconConfig = (name) => ({
45
+ path: "/favicons", // Path for overriding default icons path. `string`
46
+ appName: name, // Your application's name. `string`
47
+ appShortName: name, // Your application's short_name. `string`. Optional. If not set, appName will be used
48
+ appDescription: null, // Your application's description. `string`
49
+ developerName: null, // Your (or your developer's) name. `string`
50
+ developerURL: null, // Your (or your developer's) URL. `string`
51
+ dir: "auto", // Primary text direction for name, short_name, and description
52
+ lang: "en-US", // Primary language for name and short_name
53
+ background: "#fff", // Background colour for flattened icons. `string`
54
+ theme_color: "#fff", // Theme color user for example in Android's task switcher. `string`
55
+ appleStatusBarStyle: "black-translucent", // Style for Apple status bar: "black-translucent", "default", "black". `string`
56
+ display: "standalone", // Preferred display mode: "fullscreen", "standalone", "minimal-ui" or "browser". `string`
57
+ orientation: "any", // Default orientation: "any", "natural", "portrait" or "landscape". `string`
58
+ scope: "/", // set of URLs that the browser considers within your app
59
+ start_url: "/?homescreen=1", // Start URL when launching the application from a device. `string`
60
+ preferRelatedApplications: false, // Should the browser prompt the user to install the native companion app. `boolean`
61
+ relatedApplications: undefined, // Information about the native companion apps. This will only be used if `preferRelatedApplications` is `true`. `Array<{ id: string, url: string, platform: string }>`
62
+ version: "1.0", // Your application's version string. `string`
63
+ logging: false, // Print logs to console? `boolean`
64
+ pixel_art: false, // Keeps pixels "sharp" when scaling up, for pixel art. Only supported in offline mode.
65
+ loadManifestWithCredentials: true, // Browsers don't send cookies when fetching a manifest, enable this to fix that. `boolean`
66
+ manifestMaskable: false, // Maskable source image(s) for manifest.json. "true" to use default source. More information at https://web.dev/maskable-icon/. `boolean`, `string`, `buffer` or array of `string`
67
+ icons: {
68
+ android: ["android-chrome-192x192.png", "android-chrome-256x256.png"],
69
+ appleIcon: ["apple-touch-icon.png"],
70
+ appleStartup: false,
71
+ favicons: true,
72
+ windows: ["mstile-150x150.png"],
73
+ yandex: false,
74
+ firefox: false,
75
+ },
76
+ });
@@ -0,0 +1,116 @@
1
+ import chokidar from "chokidar";
2
+ import fse from "fs-extra";
3
+ import path from "path";
4
+ import { CLIENT_PATH, CMD_EXEC_PATH } from "../constants.js";
5
+ import { fileBelongsInPagesFolder, getFileExtension } from "../util.js";
6
+ import { createMetadataFile } from "./metadata.js";
7
+ import openApiCheck from "./openApiCheck.js";
8
+
9
+ const listener = () => {
10
+ chokidar
11
+ .watch(CMD_EXEC_PATH, {
12
+ ignoreInitial: true,
13
+ ignored: "node_modules",
14
+ cwd: CMD_EXEC_PATH,
15
+ })
16
+ .on("all", async (event, filename) => {
17
+ if (event === "unlink" || event === "unlinkDir") {
18
+ if (fileBelongsInPagesFolder(filename)) {
19
+ const targetPath = path.join(CLIENT_PATH, "src", "pages", filename);
20
+ await fse.remove(targetPath);
21
+ console.log("Page deleted: ", filename);
22
+ } else if (
23
+ filename === "mint.config.json" ||
24
+ filename === "mint.json"
25
+ ) {
26
+ const targetPath = path.join(CLIENT_PATH, "src", "mint.json");
27
+ await fse.remove(targetPath);
28
+ console.log(
29
+ "⚠️ mint.json deleted. Please create a new mint.json file as it is mandatory."
30
+ );
31
+ process.exit(1);
32
+ } else {
33
+ // all other files
34
+ const targetPath = path.join(CLIENT_PATH, "public", filename);
35
+ await fse.remove(targetPath);
36
+ console.log("Static file deleted: ", filename);
37
+ }
38
+ } else {
39
+ const filePath = path.join(CMD_EXEC_PATH, filename);
40
+ let updateMetadata = false;
41
+ if (fileBelongsInPagesFolder(filename)) {
42
+ updateMetadata = true;
43
+ const targetPath = path.join(CLIENT_PATH, "src", "pages", filename);
44
+ await fse.copy(filePath, targetPath);
45
+ switch (event) {
46
+ case "add":
47
+ case "addDir":
48
+ console.log("New page detected: ", filename);
49
+ break;
50
+ default:
51
+ console.log("Page edited: ", filename);
52
+ break;
53
+ }
54
+ } else if (
55
+ filename === "mint.config.json" ||
56
+ filename === "mint.json"
57
+ ) {
58
+ updateMetadata = true;
59
+ const targetPath = path.join(CLIENT_PATH, "src", "mint.json");
60
+ await fse.copy(filePath, targetPath);
61
+ switch (event) {
62
+ case "add":
63
+ case "addDir":
64
+ console.log("Config added");
65
+ break;
66
+ default:
67
+ console.log("Config edited");
68
+ break;
69
+ }
70
+ } else {
71
+ const extension = getFileExtension(filename);
72
+ let isOpenApi = false;
73
+ if (
74
+ extension &&
75
+ (extension === "json" ||
76
+ extension === "yaml" ||
77
+ extension === "yml")
78
+ ) {
79
+ const openApiInfo = await openApiCheck(
80
+ path.join(CMD_EXEC_PATH, filename)
81
+ );
82
+ isOpenApi = openApiInfo.isOpenApi;
83
+ }
84
+ let targetPath = path.join(CLIENT_PATH, "public", filename);
85
+ if (isOpenApi) {
86
+ targetPath = path.join(CLIENT_PATH, "src", "openapi.json");
87
+ updateMetadata = true;
88
+ }
89
+ // all other files
90
+ await fse.copy(filePath, targetPath);
91
+ switch (event) {
92
+ case "add":
93
+ case "addDir":
94
+ if (isOpenApi) {
95
+ console.log("OpenApi file added: ", filename);
96
+ } else {
97
+ console.log("Static file added: ", filename);
98
+ }
99
+ break;
100
+ default:
101
+ if (isOpenApi) {
102
+ console.log("OpenApi file edited: ", filename);
103
+ } else {
104
+ console.log("Static file edited: ", filename);
105
+ }
106
+ break;
107
+ }
108
+ }
109
+ if (updateMetadata) {
110
+ await createMetadataFile();
111
+ }
112
+ }
113
+ });
114
+ };
115
+
116
+ export default listener;
@@ -0,0 +1,154 @@
1
+ // TODO - add types
2
+ import fse from "fs-extra";
3
+ import { promises as _promises } from "fs";
4
+ import matter from "gray-matter";
5
+ import path from "path";
6
+
7
+ import categorizeFiles from "./categorizeFiles.js";
8
+ import { getConfigObj } from "./mintConfigFile.js";
9
+ import { getOpenApiTitleAndDescription } from "./getOpenApiContext.js";
10
+ import { slugToTitle } from "./slugToTitle.js";
11
+ import { CLIENT_PATH, CMD_EXEC_PATH } from "../constants.js";
12
+
13
+ const { readFile } = _promises;
14
+
15
+ // End matter is front matter, but at the end
16
+ const getIndexOfEndMatter = (fileContents: string) => {
17
+ const frontMatters = fileContents.match(
18
+ /---\n(title:.+\n|description:.+\n|sidebarTitle:.+\n|api:.+\n|openapi:.+\n)+---$/m
19
+ );
20
+ if (frontMatters) {
21
+ return fileContents.indexOf(frontMatters[0]);
22
+ }
23
+
24
+ return -1;
25
+ };
26
+
27
+ export const potentiallyRemoveEndMatter = (fileContents: string) => {
28
+ const endMatterIndex = getIndexOfEndMatter(fileContents);
29
+
30
+ if (endMatterIndex === -1) {
31
+ return fileContents;
32
+ }
33
+
34
+ return fileContents.substring(0, endMatterIndex);
35
+ };
36
+
37
+ const getMetadata = (fileContents: string) => {
38
+ const { data } = matter(fileContents);
39
+
40
+ if (Object.keys(data).length > 0) {
41
+ return data;
42
+ }
43
+
44
+ const startIndex = getIndexOfEndMatter(fileContents);
45
+ if (startIndex === -1) {
46
+ return {};
47
+ }
48
+
49
+ const fileContentFromFrontMatter = fileContents.substring(startIndex);
50
+ const { data: nonTopFrontMatter } = matter(fileContentFromFrontMatter);
51
+ return nonTopFrontMatter;
52
+ };
53
+
54
+ export const createPage = (
55
+ path: string,
56
+ content: string,
57
+ openApiObj: object | null
58
+ ) => {
59
+ const slug = path.replace(/\.mdx?$/, "").substring(1);
60
+ let defaultTitle = slugToTitle(slug);
61
+ const metadata = getMetadata(content);
62
+ // Append data from OpenAPI if it exists
63
+ const { title, description } = getOpenApiTitleAndDescription(
64
+ openApiObj,
65
+ metadata?.openapi
66
+ );
67
+ if (title) {
68
+ defaultTitle = title;
69
+ }
70
+ return {
71
+ [slug]: { title: defaultTitle, description, ...metadata, href: `/${slug}` },
72
+ };
73
+ };
74
+
75
+ export const createMetadataFileFromPages = (pages: any, configObj: any) => {
76
+ const targetPath = path.join(CLIENT_PATH, "src", "metadata.json");
77
+ const createNav = (nav) => {
78
+ return {
79
+ group: nav.group,
80
+ pages: nav.pages.map((page) => {
81
+ if (typeof page === "string") {
82
+ return pages[page];
83
+ }
84
+
85
+ return createNav(page);
86
+ }),
87
+ };
88
+ };
89
+
90
+ if (configObj?.navigation == null) {
91
+ return;
92
+ }
93
+
94
+ let navFile = configObj.navigation.map((nav) => createNav(nav));
95
+ const filterOutNullInPages = (pages) => {
96
+ const newPages = [];
97
+ pages.forEach((page) => {
98
+ if (page == null) {
99
+ return;
100
+ }
101
+ if (page?.pages) {
102
+ const newGroup = filterOutNullInGroup(page);
103
+ newPages.push(newGroup);
104
+ } else {
105
+ newPages.push(page);
106
+ }
107
+ });
108
+
109
+ return newPages;
110
+ };
111
+ const filterOutNullInGroup = (group) => {
112
+ const newPages = filterOutNullInPages(group.pages);
113
+ const newGroup = {
114
+ ...group,
115
+ pages: newPages,
116
+ };
117
+ return newGroup;
118
+ };
119
+ const newNavFile = navFile.map((group) => {
120
+ return filterOutNullInGroup(group);
121
+ });
122
+ fse.outputFileSync(targetPath, JSON.stringify(newNavFile, null, 2), {
123
+ flag: "w",
124
+ });
125
+ };
126
+
127
+ export const createMetadataFile = async () => {
128
+ // create pages
129
+ const { markdownFiles, openApiBuffer } = await categorizeFiles();
130
+ let openApiObj = null;
131
+ if (openApiBuffer) {
132
+ openApiObj = JSON.parse(openApiBuffer.toString());
133
+ }
134
+ // create config object
135
+ const configObj = await getConfigObj();
136
+ let pages = {};
137
+ const mdPromises = [];
138
+ markdownFiles.forEach((filename) => {
139
+ mdPromises.push(
140
+ (async () => {
141
+ const sourcePath = path.join(CMD_EXEC_PATH, filename);
142
+ const fileContent = await readFile(sourcePath);
143
+ const contentStr = fileContent.toString();
144
+ const page = createPage(filename, contentStr, openApiObj);
145
+ pages = {
146
+ ...pages,
147
+ ...page,
148
+ };
149
+ })()
150
+ );
151
+ });
152
+ await Promise.all(mdPromises);
153
+ createMetadataFileFromPages(pages, configObj);
154
+ };
@@ -0,0 +1,48 @@
1
+ import { promises as _promises } from "fs";
2
+ import fse, { pathExists } from "fs-extra";
3
+ import path from "path";
4
+
5
+ import { CLIENT_PATH, CMD_EXEC_PATH } from "../constants.js";
6
+
7
+ const { readFile } = _promises;
8
+
9
+ const getConfigPath = async (): Promise<string | null> => {
10
+ let configPath = null;
11
+ if (await pathExists(path.join(CMD_EXEC_PATH, "mint.config.json"))) {
12
+ configPath = path.join(CMD_EXEC_PATH, "mint.config.json");
13
+ }
14
+
15
+ if (await pathExists(path.join(CMD_EXEC_PATH, "mint.json"))) {
16
+ configPath = path.join(CMD_EXEC_PATH, "mint.json");
17
+ }
18
+ return configPath;
19
+ };
20
+
21
+ export const getConfigObj = async (): Promise<object | null> => {
22
+ const configPath = await getConfigPath();
23
+ let configObj = null;
24
+ if (configPath) {
25
+ const configContents = await readFile(configPath);
26
+ configObj = JSON.parse(configContents.toString());
27
+ }
28
+ return configObj;
29
+ };
30
+
31
+ export const updateConfigFile = async (logger: any) => {
32
+ const configTargetPath = path.join(CLIENT_PATH, "src", "mint.json");
33
+ await fse.remove(configTargetPath);
34
+ let configObj = null;
35
+ const configPath = await getConfigPath();
36
+
37
+ if (configPath) {
38
+ await fse.remove(configTargetPath);
39
+ await fse.copy(configPath, configTargetPath);
40
+ logger.succeed("mint config file synced");
41
+ const configContents = await readFile(configPath);
42
+ configObj = JSON.parse(configContents.toString());
43
+ } else {
44
+ logger.fail("Must be ran in a directory where a mint.json file exists.");
45
+ process.exit(1);
46
+ }
47
+ return configObj;
48
+ };
@@ -0,0 +1,19 @@
1
+ import SwaggerParser from "@apidevtools/swagger-parser";
2
+ import { promises as _promises } from "fs";
3
+
4
+ const openApiCheck = async (
5
+ path: string
6
+ ): Promise<{ buffer: Buffer | undefined; isOpenApi: boolean }> => {
7
+ let buffer = undefined;
8
+ let isOpenApi = false;
9
+ try {
10
+ const api = await SwaggerParser.validate(path);
11
+ buffer = Buffer.from(JSON.stringify(api, null, 2), "utf-8");
12
+ isOpenApi = true;
13
+ } catch {
14
+ // not valid openApi
15
+ }
16
+ return { buffer, isOpenApi };
17
+ };
18
+
19
+ export default openApiCheck;
@@ -0,0 +1,7 @@
1
+ export const slugToTitle = (slug) => {
2
+ const slugArr = slug.split("/");
3
+ let defaultTitle = slugArr[slugArr.length - 1].split("-").join(" "); //replace all dashes
4
+ defaultTitle = defaultTitle.split("_").join(" "); //replace all underscores
5
+ defaultTitle = defaultTitle.charAt(0).toUpperCase() + defaultTitle.slice(1); //capitalize first letter
6
+ return defaultTitle;
7
+ };
@@ -0,0 +1,12 @@
1
+ export type NavigationEntry = string | Navigation;
2
+
3
+ export type Navigation = {
4
+ group: string;
5
+ pages: NavigationEntry[];
6
+ };
7
+
8
+ export function isNavigation(
9
+ navEntry: NavigationEntry
10
+ ): navEntry is Navigation {
11
+ return typeof navEntry !== "string";
12
+ }
@@ -0,0 +1,32 @@
1
+ import inquirer from "inquirer";
2
+ import { createPage } from "./util.js";
3
+
4
+ const generatePageTemplate = () => {
5
+ inquirer
6
+ .prompt([
7
+ {
8
+ type: "input",
9
+ name: "title",
10
+ message: "What is the title of the new page?",
11
+ },
12
+ {
13
+ type: "input",
14
+ name: "description",
15
+ message: "What is the description?",
16
+ default: "",
17
+ },
18
+ ])
19
+ .then((answers) => {
20
+ const { title, description } = answers;
21
+
22
+ createPage(title, description);
23
+ console.log("🌱 Created initial files for Mintlify docs");
24
+ process.exit(0);
25
+ })
26
+ .catch((error) => {
27
+ console.error(error);
28
+ process.exit(1);
29
+ });
30
+ };
31
+
32
+ export default generatePageTemplate;