mintlify 1.0.6 → 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 (286) hide show
  1. package/README.md +27 -3
  2. package/bin/browser.js +24 -0
  3. package/bin/browser.js.map +1 -0
  4. package/bin/constants.js +8 -0
  5. package/bin/constants.js.map +1 -0
  6. package/bin/dev/getOpenApiContext.js +46 -0
  7. package/bin/dev/getOpenApiContext.js.map +1 -0
  8. package/bin/dev/index.js +164 -0
  9. package/bin/dev/index.js.map +1 -0
  10. package/bin/dev/injectNav.js +97 -0
  11. package/bin/dev/injectNav.js.map +1 -0
  12. package/bin/dev/slugToTitle.js +8 -0
  13. package/bin/dev/slugToTitle.js.map +1 -0
  14. package/bin/downloadImage.js +27 -0
  15. package/bin/downloadImage.js.map +1 -0
  16. package/bin/index.js +49 -106
  17. package/bin/index.js.map +1 -1
  18. package/bin/init-command/index.js +51 -0
  19. package/bin/init-command/index.js.map +1 -0
  20. package/bin/init-command/templates.js +41 -0
  21. package/bin/init-command/templates.js.map +1 -0
  22. package/bin/local-preview/categorizeFiles.js +56 -0
  23. package/bin/local-preview/categorizeFiles.js.map +1 -0
  24. package/bin/local-preview/getOpenApiContext.js +46 -0
  25. package/bin/local-preview/getOpenApiContext.js.map +1 -0
  26. package/bin/local-preview/index.js +138 -0
  27. package/bin/local-preview/index.js.map +1 -0
  28. package/bin/local-preview/injectFavicons.js +72 -0
  29. package/bin/local-preview/injectFavicons.js.map +1 -0
  30. package/bin/local-preview/listener.js +112 -0
  31. package/bin/local-preview/listener.js.map +1 -0
  32. package/bin/local-preview/metadata.js +121 -0
  33. package/bin/local-preview/metadata.js.map +1 -0
  34. package/bin/local-preview/mintConfigFile.js +43 -0
  35. package/bin/local-preview/mintConfigFile.js.map +1 -0
  36. package/bin/local-preview/openApiCheck.js +16 -0
  37. package/bin/local-preview/openApiCheck.js.map +1 -0
  38. package/bin/local-preview/slugToTitle.js +8 -0
  39. package/bin/local-preview/slugToTitle.js.map +1 -0
  40. package/bin/mint/client/.babel-plugin-macrosrc.json +5 -0
  41. package/bin/mint/client/.babelrc +4 -0
  42. package/bin/mint/client/.editorconfig +12 -0
  43. package/bin/mint/client/.eslintrc.json +7 -0
  44. package/bin/mint/client/.prettierignore +4 -0
  45. package/bin/mint/client/.prettierrc +14 -0
  46. package/bin/mint/client/.vscode/launch.json +28 -0
  47. package/bin/mint/client/README.md +46 -0
  48. package/bin/mint/client/jest.config.ts +195 -0
  49. package/bin/mint/client/next-env.d.ts +4 -0
  50. package/bin/mint/client/next.config.js +152 -0
  51. package/bin/mint/client/package.json +140 -0
  52. package/bin/mint/client/postcss.config.cjs +9 -0
  53. package/bin/mint/client/prebuild/faviconConfig.js +35 -0
  54. package/bin/mint/client/prebuild/getOpenApiContext.js +53 -0
  55. package/bin/mint/client/prebuild/index.js +117 -0
  56. package/bin/mint/client/prebuild/injectNav.js +115 -0
  57. package/bin/mint/client/prebuild/slugToTitle.js +7 -0
  58. package/bin/mint/client/rehype/withApiComponents.js +60 -0
  59. package/bin/mint/client/rehype/withCodeBlocks.js +54 -0
  60. package/bin/mint/client/rehype/withLayouts.js +113 -0
  61. package/bin/mint/client/rehype/withLinkRoles.js +13 -0
  62. package/bin/mint/client/rehype/withRawComponents.js +13 -0
  63. package/bin/mint/client/rehype/withStaticProps.js +25 -0
  64. package/bin/mint/client/rehype/withSyntaxHighlighting.js +60 -0
  65. package/bin/mint/client/remark/utils.js +369 -0
  66. package/bin/mint/client/remark/withFrames.js +55 -0
  67. package/bin/mint/client/remark/withImportsInjected.js +36 -0
  68. package/bin/mint/client/remark/withNextLinks.js +37 -0
  69. package/bin/mint/client/remark/withTableOfContents.js +71 -0
  70. package/bin/mint/client/scripts/local-to-docs.js +72 -0
  71. package/bin/mint/client/scripts/local.js +177 -0
  72. package/bin/mint/client/sentry.client.config.js +15 -0
  73. package/bin/mint/client/sentry.properties +4 -0
  74. package/bin/mint/client/sentry.server.config.js +15 -0
  75. package/bin/mint/client/src/analytics/AbstractAnalyticsImplementation.ts +50 -0
  76. package/bin/mint/client/src/analytics/AnalyticsContext.ts +5 -0
  77. package/bin/mint/client/src/analytics/AnalyticsMediator.ts +101 -0
  78. package/bin/mint/client/src/analytics/FakeAnalyticsMediator.ts +9 -0
  79. package/bin/mint/client/src/analytics/GA4Script.tsx +33 -0
  80. package/bin/mint/client/src/analytics/implementations/amplitude.ts +26 -0
  81. package/bin/mint/client/src/analytics/implementations/fathom.ts +38 -0
  82. package/bin/mint/client/src/analytics/implementations/ga4.ts +33 -0
  83. package/bin/mint/client/src/analytics/implementations/hotjar.ts +53 -0
  84. package/bin/mint/client/src/analytics/implementations/mixpanel-browser.d.ts +1 -0
  85. package/bin/mint/client/src/analytics/implementations/mixpanel.ts +52 -0
  86. package/bin/mint/client/src/analytics/implementations/posthog.ts +37 -0
  87. package/bin/mint/client/src/components/Accordion/Accordion.tsx +43 -0
  88. package/bin/mint/client/src/components/Accordion/index.ts +4 -0
  89. package/bin/mint/client/src/components/ApiExample.tsx +9 -0
  90. package/bin/mint/client/src/components/Card.tsx +51 -0
  91. package/bin/mint/client/src/components/CodeGroup.tsx +132 -0
  92. package/bin/mint/client/src/components/Editor.tsx +12 -0
  93. package/bin/mint/client/src/components/Expandable.tsx +40 -0
  94. package/bin/mint/client/src/components/Heading.tsx +84 -0
  95. package/bin/mint/client/src/components/Param.tsx +56 -0
  96. package/bin/mint/client/src/components/Request.tsx +19 -0
  97. package/bin/mint/client/src/components/ResponseField.tsx +33 -0
  98. package/bin/mint/client/src/components/TabBar.tsx +61 -0
  99. package/bin/mint/client/src/config.ts +115 -0
  100. package/bin/mint/client/src/css/bar-of-progress.css +10 -0
  101. package/bin/mint/client/src/css/base.css +29 -0
  102. package/bin/mint/client/src/css/font-awesome.css +7 -0
  103. package/bin/mint/client/src/css/fonts.css +44 -0
  104. package/bin/mint/client/src/css/main.css +11 -0
  105. package/bin/mint/client/src/css/prism.css +270 -0
  106. package/bin/mint/client/src/css/utilities.css +43 -0
  107. package/bin/mint/client/src/enums/components.ts +8 -0
  108. package/bin/mint/client/src/fonts/FiraCode-VF.woff +0 -0
  109. package/bin/mint/client/src/fonts/FiraCode-VF.woff2 +0 -0
  110. package/bin/mint/client/src/fonts/IBMPlexMono-Regular.ttf +0 -0
  111. package/bin/mint/client/src/fonts/IBMPlexMono-SemiBold.ttf +0 -0
  112. package/bin/mint/client/src/fonts/Inter-italic-latin.var.woff2 +0 -0
  113. package/bin/mint/client/src/fonts/Inter-roman-latin.var.woff2 +0 -0
  114. package/bin/mint/client/src/fonts/Pally-Variable.ttf +0 -0
  115. package/bin/mint/client/src/fonts/SourceSansPro-Regular.otf +0 -0
  116. package/bin/mint/client/src/fonts/SourceSerifPro-Regular.ttf +0 -0
  117. package/bin/mint/client/src/fonts/Synonym-Variable.ttf +0 -0
  118. package/bin/mint/client/src/fonts/Ubuntu-Mono-bold.woff2 +0 -0
  119. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.woff2 +0 -0
  120. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.zopfli.woff +0 -0
  121. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular.module.css +11 -0
  122. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.woff2 +0 -0
  123. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.zopfli.woff +0 -0
  124. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold.module.css +11 -0
  125. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.woff2 +0 -0
  126. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.zopfli.woff +0 -0
  127. package/bin/mint/client/src/fonts/generated/Pally-Variable.module.css +11 -0
  128. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.woff2 +0 -0
  129. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.zopfli.woff +0 -0
  130. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular.module.css +11 -0
  131. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.woff2 +0 -0
  132. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.zopfli.woff +0 -0
  133. package/bin/mint/client/src/fonts/generated/Synonym-Variable.module.css +11 -0
  134. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.woff2 +0 -0
  135. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.zopfli.woff +0 -0
  136. package/bin/mint/client/src/fonts/generated/TenorSans-Regular.module.css +11 -0
  137. package/bin/mint/client/src/hooks/useActionKey.ts +20 -0
  138. package/bin/mint/client/src/hooks/useIsomorphicLayoutEffect.ts +3 -0
  139. package/bin/mint/client/src/hooks/useMedia.ts +27 -0
  140. package/bin/mint/client/src/hooks/usePrevNext.ts +34 -0
  141. package/bin/mint/client/src/hooks/useTop.ts +15 -0
  142. package/bin/mint/client/src/icons/CopyToClipboard.tsx +33 -0
  143. package/bin/mint/client/src/index.d.ts +1 -0
  144. package/bin/mint/client/src/layouts/ApiSupplemental.tsx +173 -0
  145. package/bin/mint/client/src/layouts/ContentsLayout.tsx +256 -0
  146. package/bin/mint/client/src/layouts/DocumentationLayout.tsx +44 -0
  147. package/bin/mint/client/src/layouts/OpenApiContent.tsx +301 -0
  148. package/bin/mint/client/src/layouts/SidebarLayout.tsx +412 -0
  149. package/bin/mint/client/src/layouts/UserFeedback.tsx +73 -0
  150. package/bin/mint/client/src/layouts/getGroupsInDivision.ts +25 -0
  151. package/bin/mint/client/src/layouts/isPathInGroupPages.ts +10 -0
  152. package/bin/mint/client/src/metadata.ts +58 -0
  153. package/bin/mint/client/src/openapi.ts +3 -0
  154. package/bin/mint/client/src/pages/404.tsx +73 -0
  155. package/bin/mint/client/src/pages/_app.tsx +138 -0
  156. package/bin/mint/client/src/pages/_document.tsx +57 -0
  157. package/bin/mint/client/src/pages/api/issue.ts +10 -0
  158. package/bin/mint/client/src/pages/api/name.ts +8 -0
  159. package/bin/mint/client/src/pages/api/request.ts +31 -0
  160. package/bin/mint/client/src/pages/api/suggest.ts +10 -0
  161. package/bin/mint/client/src/pages/api/syntax-highlighted-json.ts +13 -0
  162. package/bin/mint/client/src/pages/api/utils.ts +6 -0
  163. package/bin/mint/client/src/pages/index.tsx +31 -0
  164. package/bin/mint/client/src/ui/Api.tsx +359 -0
  165. package/bin/mint/client/src/ui/Footer.tsx +124 -0
  166. package/bin/mint/client/src/ui/Header.tsx +370 -0
  167. package/bin/mint/client/src/ui/Logo.tsx +55 -0
  168. package/bin/mint/client/src/ui/PageHeader.tsx +51 -0
  169. package/bin/mint/client/src/ui/Search.tsx +386 -0
  170. package/bin/mint/client/src/ui/ThemeToggle.tsx +285 -0
  171. package/bin/mint/client/src/ui/Title.tsx +22 -0
  172. package/bin/mint/client/src/ui/TopLevelLink.tsx +122 -0
  173. package/bin/mint/client/src/utils/api.ts +252 -0
  174. package/bin/mint/client/src/utils/brands.ts +217 -0
  175. package/bin/mint/client/src/utils/castArray.ts +3 -0
  176. package/bin/mint/client/src/utils/childrenArray.ts +3 -0
  177. package/bin/mint/client/src/utils/fit.ts +27 -0
  178. package/bin/mint/client/src/utils/fontAwesome.ts +577 -0
  179. package/bin/mint/client/src/utils/getAnalyticsConfig.ts +14 -0
  180. package/bin/mint/client/src/utils/getLogoHref.ts +9 -0
  181. package/bin/mint/client/src/utils/getOpenApiContext.ts +26 -0
  182. package/bin/mint/client/src/utils/importAll.ts +6 -0
  183. package/bin/mint/client/src/utils/isObject.ts +3 -0
  184. package/bin/mint/client/src/utils/kebabToTitleCase.ts +3 -0
  185. package/bin/mint/client/src/utils/loadImage.ts +8 -0
  186. package/bin/mint/client/src/utils/slugToTitle.ts +7 -0
  187. package/bin/mint/client/src/utils/wait.ts +5 -0
  188. package/bin/mint/client/tailwind.config.cjs +323 -0
  189. package/bin/mint/client/test/test.test.ts +5 -0
  190. package/bin/mint/client/tsconfig.json +36 -0
  191. package/bin/mint/client/yarn.lock +9702 -0
  192. package/bin/navigation.js +4 -0
  193. package/bin/navigation.js.map +1 -0
  194. package/bin/pageTemplate.js +30 -0
  195. package/bin/pageTemplate.js.map +1 -0
  196. package/bin/scraping/combineNavWithEmptyGroupTitles.js +20 -0
  197. package/bin/scraping/combineNavWithEmptyGroupTitles.js.map +1 -0
  198. package/bin/scraping/detectFramework.js +25 -0
  199. package/bin/scraping/detectFramework.js.map +1 -0
  200. package/bin/scraping/downloadAllImages.js +57 -0
  201. package/bin/scraping/downloadAllImages.js.map +1 -0
  202. package/bin/scraping/getSitemapLinks.js +18 -0
  203. package/bin/scraping/getSitemapLinks.js.map +1 -0
  204. package/bin/scraping/replaceImagePaths.js +17 -0
  205. package/bin/scraping/replaceImagePaths.js.map +1 -0
  206. package/bin/scraping/scrapeFileGettingFileNameFromUrl.js +43 -0
  207. package/bin/scraping/scrapeFileGettingFileNameFromUrl.js.map +1 -0
  208. package/bin/scraping/scrapeGettingFileNameFromUrl.js +14 -0
  209. package/bin/scraping/scrapeGettingFileNameFromUrl.js.map +1 -0
  210. package/bin/scraping/scrapePage.js +9 -0
  211. package/bin/scraping/scrapePage.js.map +1 -0
  212. package/bin/scraping/scrapePageCommands.js +48 -0
  213. package/bin/scraping/scrapePageCommands.js.map +1 -0
  214. package/bin/scraping/scrapeSection.js +9 -0
  215. package/bin/scraping/scrapeSection.js.map +1 -0
  216. package/bin/scraping/scrapeSectionCommands.js +90 -0
  217. package/bin/scraping/scrapeSectionCommands.js.map +1 -0
  218. package/bin/scraping/site-scrapers/getLinksRecursively.js +33 -0
  219. package/bin/scraping/site-scrapers/getLinksRecursively.js.map +1 -0
  220. package/bin/scraping/site-scrapers/scrapeDocusaurusPage.js +43 -0
  221. package/bin/scraping/site-scrapers/scrapeDocusaurusPage.js.map +1 -0
  222. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js +52 -0
  223. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js.map +1 -0
  224. package/bin/{scrapeGitBookPage.js → scraping/site-scrapers/scrapeGitBookPage.js} +10 -5
  225. package/bin/scraping/site-scrapers/scrapeGitBookPage.js.map +1 -0
  226. package/bin/scraping/site-scrapers/scrapeGitBookSection.js +51 -0
  227. package/bin/scraping/site-scrapers/scrapeGitBookSection.js.map +1 -0
  228. package/bin/scraping/site-scrapers/scrapeReadMePage.js +35 -0
  229. package/bin/scraping/site-scrapers/scrapeReadMePage.js.map +1 -0
  230. package/bin/scraping/site-scrapers/scrapeReadMeSection.js +38 -0
  231. package/bin/scraping/site-scrapers/scrapeReadMeSection.js.map +1 -0
  232. package/bin/util.js +47 -8
  233. package/bin/util.js.map +1 -1
  234. package/bin/validation/isValidLink.js +11 -0
  235. package/bin/validation/isValidLink.js.map +1 -0
  236. package/bin/validation/stopIfInvalidLink.js +9 -0
  237. package/bin/validation/stopIfInvalidLink.js.map +1 -0
  238. package/package.json +21 -4
  239. package/src/browser.ts +24 -0
  240. package/src/constants.ts +10 -0
  241. package/src/downloadImage.ts +35 -0
  242. package/src/index.ts +111 -122
  243. package/src/init-command/index.ts +59 -0
  244. package/src/{templates.ts → init-command/templates.ts} +0 -0
  245. package/src/local-preview/categorizeFiles.ts +74 -0
  246. package/src/local-preview/getOpenApiContext.ts +61 -0
  247. package/src/local-preview/index.ts +164 -0
  248. package/src/local-preview/injectFavicons.ts +76 -0
  249. package/src/local-preview/listener.ts +116 -0
  250. package/src/local-preview/metadata.ts +154 -0
  251. package/src/local-preview/mintConfigFile.ts +48 -0
  252. package/src/local-preview/openApiCheck.ts +19 -0
  253. package/src/local-preview/slugToTitle.ts +7 -0
  254. package/src/navigation.ts +12 -0
  255. package/src/pageTemplate.ts +32 -0
  256. package/src/scraping/combineNavWithEmptyGroupTitles.ts +21 -0
  257. package/src/scraping/detectFramework.ts +31 -0
  258. package/src/scraping/downloadAllImages.ts +79 -0
  259. package/src/scraping/getSitemapLinks.ts +18 -0
  260. package/src/scraping/replaceImagePaths.ts +21 -0
  261. package/src/scraping/scrapeFileGettingFileNameFromUrl.ts +81 -0
  262. package/src/scraping/scrapeGettingFileNameFromUrl.ts +50 -0
  263. package/src/scraping/scrapePage.ts +24 -0
  264. package/src/scraping/scrapePageCommands.ts +52 -0
  265. package/src/scraping/scrapeSection.ts +16 -0
  266. package/src/scraping/scrapeSectionCommands.ts +110 -0
  267. package/src/scraping/site-scrapers/getLinksRecursively.ts +40 -0
  268. package/src/scraping/site-scrapers/scrapeDocusaurusPage.ts +67 -0
  269. package/src/scraping/site-scrapers/scrapeDocusaurusSection.ts +80 -0
  270. package/src/{scrapeGitBookPage.ts → scraping/site-scrapers/scrapeGitBookPage.ts} +25 -5
  271. package/src/scraping/site-scrapers/scrapeGitBookSection.ts +77 -0
  272. package/src/scraping/site-scrapers/scrapeReadMePage.ts +57 -0
  273. package/src/scraping/site-scrapers/scrapeReadMeSection.ts +60 -0
  274. package/src/util.ts +53 -7
  275. package/src/validation/isValidLink.ts +9 -0
  276. package/src/validation/stopIfInvalidLink.ts +9 -0
  277. package/tsconfig.json +1 -1
  278. package/bin/scrapeGitBook.js +0 -28
  279. package/bin/scrapeGitBook.js.map +0 -1
  280. package/bin/scrapeGitBookPage.js.map +0 -1
  281. package/bin/scrapeReadMe.js +0 -60
  282. package/bin/scrapeReadMe.js.map +0 -1
  283. package/bin/scrapeReadMePage.js +0 -28
  284. package/bin/scrapeReadMePage.js.map +0 -1
  285. package/src/scrapeReadMe.ts +0 -79
  286. package/src/scrapeReadMePage.ts +0 -37
@@ -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;
@@ -0,0 +1,21 @@
1
+ import { Navigation } from "../navigation.js";
2
+
3
+ export default function combineNavWithEmptyGroupTitles(navArray: Navigation[]) {
4
+ let newNavArray = [];
5
+
6
+ navArray.forEach((nav: Navigation) => {
7
+ // The first run through the loop will always have -1 as the index.
8
+ // JavaScript returns undefined when we look for an index outside the size of the array.
9
+ const prev = newNavArray[newNavArray.length - 1];
10
+ if (prev == null) {
11
+ newNavArray.push(nav);
12
+ } else if (!nav.group && !prev.group) {
13
+ // Joins multiple groups without a title together IF they occur side by side
14
+ prev.pages = prev.pages.concat(nav.pages);
15
+ } else {
16
+ newNavArray.push(nav);
17
+ }
18
+ });
19
+
20
+ return newNavArray;
21
+ }
@@ -0,0 +1,31 @@
1
+ import cheerio from "cheerio";
2
+
3
+ export enum Frameworks {
4
+ DOCUSAURUS = "DOCUSAURUS",
5
+ GITBOOK = "GITBOOK",
6
+ README = "README",
7
+ }
8
+
9
+ export function detectFramework(html) {
10
+ const $ = cheerio.load(html);
11
+ const docusaurusMeta = $('meta[name="generator"]');
12
+
13
+ if (
14
+ docusaurusMeta.length > 0 &&
15
+ docusaurusMeta.attr("content").includes("Docusaurus")
16
+ ) {
17
+ return Frameworks.DOCUSAURUS;
18
+ }
19
+
20
+ const isGitBook = $(".gitbook-root").length > 0;
21
+ if (isGitBook) {
22
+ return Frameworks.GITBOOK;
23
+ }
24
+
25
+ const isReadMe = $('meta[name="readme-deploy"]').length > 0;
26
+ if (isReadMe) {
27
+ return Frameworks.README;
28
+ }
29
+
30
+ return undefined;
31
+ }
@@ -0,0 +1,79 @@
1
+ import path from "path";
2
+ import downloadImage from "../downloadImage.js";
3
+
4
+ // To Do: Use CheerioElement instead of any when we bump the cheerio version
5
+ export default async function downloadAllImages(
6
+ $: any,
7
+ content: any,
8
+ origin: string,
9
+ baseDir: string,
10
+ modifyFileName?: any
11
+ ) {
12
+ if (!baseDir) {
13
+ console.debug("Skipping image downloading");
14
+ return;
15
+ }
16
+
17
+ // We remove duplicates because some frameworks duplicate img tags
18
+ // to show the image larger when clicked on.
19
+ const imageSrcs = [
20
+ ...new Set(
21
+ content
22
+ .find("img[src]")
23
+ .map((i, image) => $(image).attr("src"))
24
+ .toArray()
25
+ ),
26
+ ];
27
+
28
+ // Wait to all images to download before continuing
29
+ const origToNewArray = await Promise.all(
30
+ imageSrcs.map(async (origImageSrc: string) => {
31
+ // Add origin if the image tags are using relative sources
32
+ const imageHref = origImageSrc.startsWith("http")
33
+ ? origImageSrc
34
+ : new URL(origImageSrc, origin).href;
35
+
36
+ let fileName = removeMetadataFromExtension(path.basename(imageHref));
37
+ if (modifyFileName) {
38
+ fileName = modifyFileName(fileName);
39
+ }
40
+
41
+ if (!fileName) {
42
+ console.error("Invalid image path " + imageHref);
43
+ return;
44
+ }
45
+
46
+ const writePath = path.join(baseDir, fileName);
47
+
48
+ await downloadImage(imageHref, writePath)
49
+ .then(() => {
50
+ console.log("🖼️ - " + writePath);
51
+ })
52
+ .catch((e) => {
53
+ if (e.code === "EEXIST") {
54
+ console.log(`❌ Skipping existing image ${writePath}`);
55
+ } else {
56
+ console.error(e);
57
+ }
58
+ });
59
+
60
+ return { [origImageSrc]: writePath };
61
+ })
62
+ );
63
+
64
+ return origToNewArray.reduce(
65
+ (result, current) => Object.assign(result, current),
66
+ {}
67
+ );
68
+ }
69
+
70
+ function removeMetadataFromExtension(src: string) {
71
+ // Part of the URL standard
72
+ const metadataSymbols = ["?", "#"];
73
+
74
+ metadataSymbols.forEach((dividerSymbol) => {
75
+ // Some frameworks add metadata after the file extension, we need to remove that.
76
+ src = src.split(dividerSymbol)[0];
77
+ });
78
+ return src;
79
+ }
@@ -0,0 +1,18 @@
1
+ import axios from "axios";
2
+
3
+ // Not in use.
4
+ // Gets all links in a sitemap.
5
+ export const getSitemapLinks = async (url: URL) => {
6
+ const hostname = url.hostname.replace(".", "\\.");
7
+ const regex = new RegExp(`https?:\/\/${hostname}.+?(?=<\/loc>)`, "gmi");
8
+
9
+ try {
10
+ const indexData = (await axios.default.get(url.href)).data as string;
11
+ const array = indexData.match(regex) as string[] | null;
12
+ return array || [];
13
+ } catch (err) {
14
+ console.error(err);
15
+ console.log("Skipping sitemap links because we encountered an error.");
16
+ return [];
17
+ }
18
+ };
@@ -0,0 +1,21 @@
1
+ export default function replaceImagePaths(
2
+ origToWritePath: object,
3
+ cliDir: string,
4
+ markdown: string
5
+ ) {
6
+ if (origToWritePath == null) {
7
+ return markdown;
8
+ }
9
+
10
+ // Change image paths to use the downloaded locations
11
+ for (const [origHref, writePath] of Object.entries(origToWritePath)) {
12
+ // Use relative paths within the folder we are in
13
+ if (writePath.startsWith(cliDir)) {
14
+ markdown = markdown.replaceAll(origHref, writePath.slice(cliDir.length));
15
+ } else {
16
+ markdown = markdown.replaceAll(origHref, writePath);
17
+ }
18
+ }
19
+
20
+ return markdown;
21
+ }
@@ -0,0 +1,81 @@
1
+ import path from "path";
2
+ import axios from "axios";
3
+ import { getHtmlWithPuppeteer } from "../browser.js";
4
+ import { createPage } from "../util.js";
5
+
6
+ export async function scrapeFileGettingFileNameFromUrl(
7
+ pathname: string,
8
+ cliDir: string,
9
+ origin: string,
10
+ overwrite: boolean,
11
+ scrapePageFunc: (
12
+ html: string,
13
+ origin: string,
14
+ cliDir: string,
15
+ imageBaseDir: string
16
+ ) => Promise<{
17
+ title?: string;
18
+ description?: string;
19
+ markdown?: string;
20
+ }>,
21
+ puppeteer = false,
22
+ baseToRemove?: string
23
+ ) {
24
+ // Skip scraping external links
25
+ if (pathname.startsWith("https://") || pathname.startsWith("http://")) {
26
+ return pathname;
27
+ }
28
+
29
+ // Removes file name from the end
30
+ const splitSubpath = pathname.split("/");
31
+ let folders = splitSubpath.slice(0, splitSubpath.length - 1).join("/");
32
+
33
+ // Remove base dir if passed in
34
+ if (baseToRemove && folders.startsWith(baseToRemove)) {
35
+ folders = folders.replace(baseToRemove, "");
36
+ }
37
+
38
+ // TO DO: Improve this by putting each page's images in a separate
39
+ // folder named after the title of the page.
40
+ const imageBaseDir = path.join(cliDir, "images", folders);
41
+
42
+ // Scrape each page separately
43
+ const href = new URL(pathname, origin).href;
44
+ let html: string;
45
+ if (puppeteer) {
46
+ html = await getHtmlWithPuppeteer(href);
47
+ } else {
48
+ const res = await axios.default.get(href);
49
+ html = res.data;
50
+ }
51
+
52
+ const { title, description, markdown } = await scrapePageFunc(
53
+ html,
54
+ origin,
55
+ cliDir,
56
+ imageBaseDir
57
+ );
58
+
59
+ // Check if page didn't have content
60
+ if (!title && !markdown) {
61
+ return undefined;
62
+ }
63
+
64
+ const newFileLocation = folders ? path.join(cliDir, folders) : cliDir;
65
+
66
+ // Default to introduction.mdx if we encountered index.html
67
+ const fileName = splitSubpath[splitSubpath.length - 1] || "introduction";
68
+
69
+ // Will create subfolders as needed
70
+ createPage(
71
+ title,
72
+ description,
73
+ markdown,
74
+ overwrite,
75
+ newFileLocation,
76
+ fileName
77
+ );
78
+
79
+ // Removes first slash if we are in a folder, Mintlify doesn't need it
80
+ return folders ? path.join(folders, fileName).substring(1) : fileName;
81
+ }
@@ -0,0 +1,50 @@
1
+ import { NavigationEntry, isNavigation } from "../navigation.js";
2
+ import { scrapeFileGettingFileNameFromUrl } from "./scrapeFileGettingFileNameFromUrl.js";
3
+
4
+ export async function scrapeGettingFileNameFromUrl(
5
+ navEntry: NavigationEntry,
6
+ cliDir: string,
7
+ origin: string,
8
+ overwrite: boolean,
9
+ scrapePageFunc: (
10
+ html: string,
11
+ origin: string,
12
+ cliDir: string,
13
+ imageBaseDir: string
14
+ ) => Promise<{
15
+ title?: string;
16
+ description?: string;
17
+ markdown?: string;
18
+ }>,
19
+ puppeteer = false,
20
+ baseToRemove?: string
21
+ ): Promise<NavigationEntry> {
22
+ if (isNavigation(navEntry)) {
23
+ const newPages = [];
24
+ for (const nestedNavEntry of navEntry.pages) {
25
+ newPages.push(
26
+ await scrapeGettingFileNameFromUrl(
27
+ nestedNavEntry,
28
+ cliDir,
29
+ origin,
30
+ overwrite,
31
+ scrapePageFunc,
32
+ puppeteer,
33
+ baseToRemove
34
+ )
35
+ );
36
+ }
37
+ navEntry.pages = newPages;
38
+ return navEntry;
39
+ }
40
+
41
+ return await scrapeFileGettingFileNameFromUrl(
42
+ navEntry,
43
+ cliDir,
44
+ origin,
45
+ overwrite,
46
+ scrapePageFunc,
47
+ puppeteer,
48
+ baseToRemove
49
+ );
50
+ }
@@ -0,0 +1,24 @@
1
+ import path from "path";
2
+ import { createPage, getOrigin } from "../util.js";
3
+
4
+ export async function scrapePage(
5
+ scrapeFunc: (
6
+ html: string,
7
+ origin: string,
8
+ cliDir: string,
9
+ imageBaseDir: string
10
+ ) => Promise<any>,
11
+ href: string,
12
+ html: string,
13
+ overwrite: boolean
14
+ ) {
15
+ const origin = getOrigin(href);
16
+ const imageBaseDir = path.join(process.cwd(), "images");
17
+ const { title, description, markdown } = await scrapeFunc(
18
+ html,
19
+ origin,
20
+ process.cwd(),
21
+ imageBaseDir
22
+ );
23
+ createPage(title, description, markdown, overwrite, process.cwd());
24
+ }
@@ -0,0 +1,52 @@
1
+ import axios from "axios";
2
+ import { scrapePage } from "./scrapePage.js";
3
+ import { scrapeDocusaurusPage } from "./site-scrapers/scrapeDocusaurusPage.js";
4
+ import { scrapeGitBookPage } from "./site-scrapers/scrapeGitBookPage.js";
5
+ import { scrapeReadMePage } from "./site-scrapers/scrapeReadMePage.js";
6
+ import { detectFramework, Frameworks } from "./detectFramework.js";
7
+ import { getHrefFromArgs } from "../util.js";
8
+ import { getHtmlWithPuppeteer } from "../browser.js";
9
+
10
+ function validateFramework(framework) {
11
+ if (!framework) {
12
+ console.log(
13
+ "Could not detect the framework automatically. Please use one of:"
14
+ );
15
+ console.log("scrape-page-docusaurus");
16
+ console.log("scrape-page-gitbook");
17
+ console.log("scrape-page-readme");
18
+ return process.exit(1);
19
+ }
20
+ }
21
+
22
+ export async function scrapePageWrapper(argv, scrapeFunc, puppeteer = false) {
23
+ const href = getHrefFromArgs(argv);
24
+ let html: string;
25
+ if (puppeteer) {
26
+ html = await getHtmlWithPuppeteer(href);
27
+ } else {
28
+ const res = await axios.default.get(href);
29
+ html = res.data;
30
+ }
31
+ await scrapePage(scrapeFunc, href, html, argv.overwrite);
32
+ process.exit(0);
33
+ }
34
+
35
+ export async function scrapePageAutomatically(argv: any) {
36
+ const href = getHrefFromArgs(argv);
37
+ const res = await axios.default.get(href);
38
+ const html = res.data;
39
+ const framework = detectFramework(html);
40
+
41
+ validateFramework(framework);
42
+
43
+ console.log("Detected framework: " + framework);
44
+
45
+ if (framework === Frameworks.DOCUSAURUS) {
46
+ await scrapePageWrapper(argv, scrapeDocusaurusPage);
47
+ } else if (framework === Frameworks.GITBOOK) {
48
+ await scrapePageWrapper(argv, scrapeGitBookPage, true);
49
+ } else if (framework === Frameworks.README) {
50
+ await scrapePageWrapper(argv, scrapeReadMePage);
51
+ }
52
+ }
@@ -0,0 +1,16 @@
1
+ import { objToReadableString } from "../util.js";
2
+
3
+ export async function scrapeSection(
4
+ scrapeFunc: any,
5
+ html: string,
6
+ origin: string,
7
+ overwrite: boolean
8
+ ) {
9
+ console.log(
10
+ `Started scraping${overwrite ? ", overwrite mode is on" : ""}...`
11
+ );
12
+ const groupsConfig = await scrapeFunc(html, origin, process.cwd(), overwrite);
13
+ console.log("Finished scraping.");
14
+ console.log("Add the following to your navigation in mint.json:");
15
+ console.log(objToReadableString(groupsConfig));
16
+ }