blodemd 0.0.4 → 0.0.6

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 (185) hide show
  1. package/README.md +12 -1
  2. package/dev-server/app/[[...slug]]/page.tsx +139 -0
  3. package/dev-server/app/blodemd-dev/invalidate/route.ts +12 -0
  4. package/dev-server/app/blodemd-dev/static/[...path]/route.ts +32 -0
  5. package/dev-server/app/blodemd-dev/version/route.ts +14 -0
  6. package/dev-server/app/blodemd-internal/proxy/route.ts +86 -0
  7. package/dev-server/app/error.tsx +24 -0
  8. package/dev-server/app/globals.css +4 -0
  9. package/dev-server/app/layout.tsx +38 -0
  10. package/dev-server/app/not-found.tsx +18 -0
  11. package/dev-server/app/search/route.ts +17 -0
  12. package/dev-server/components/dev-reload-script.tsx +86 -0
  13. package/dev-server/components/providers.tsx +15 -0
  14. package/dev-server/lib/dev-state.ts +8 -0
  15. package/dev-server/lib/local-content-source.ts +103 -0
  16. package/dev-server/lib/local-runtime.tsx +558 -0
  17. package/dev-server/next.config.js +46 -0
  18. package/dev-server/package.json +57 -0
  19. package/dev-server/postcss.config.mjs +7 -0
  20. package/dev-server/public/glide-variable.woff2 +0 -0
  21. package/dev-server/tsconfig.json +49 -0
  22. package/dist/cli.mjs +299 -26
  23. package/dist/cli.mjs.map +1 -1
  24. package/docs/app/globals.css +455 -0
  25. package/docs/components/api/api-playground.tsx +295 -0
  26. package/docs/components/api/api-reference.tsx +121 -0
  27. package/docs/components/content/collection-index.tsx +114 -0
  28. package/docs/components/docs/contextual-menu.tsx +406 -0
  29. package/docs/components/docs/copy-page-menu.tsx +255 -0
  30. package/docs/components/docs/doc-header.tsx +192 -0
  31. package/docs/components/docs/doc-shell.tsx +289 -0
  32. package/docs/components/docs/doc-sidebar.tsx +206 -0
  33. package/docs/components/docs/doc-toc.tsx +45 -0
  34. package/docs/components/docs/mobile-nav.tsx +207 -0
  35. package/docs/components/mdx/accordion.tsx +83 -0
  36. package/docs/components/mdx/badge.tsx +79 -0
  37. package/docs/components/mdx/callout.tsx +88 -0
  38. package/docs/components/mdx/card.tsx +104 -0
  39. package/docs/components/mdx/code-block.tsx +75 -0
  40. package/docs/components/mdx/code-group.tsx +94 -0
  41. package/docs/components/mdx/color.tsx +87 -0
  42. package/docs/components/mdx/columns.tsx +25 -0
  43. package/docs/components/mdx/expandable.tsx +45 -0
  44. package/docs/components/mdx/field-layout.tsx +77 -0
  45. package/docs/components/mdx/frame.tsx +23 -0
  46. package/docs/components/mdx/get-text-content.ts +18 -0
  47. package/docs/components/mdx/icon.tsx +56 -0
  48. package/docs/components/mdx/index.tsx +96 -0
  49. package/docs/components/mdx/installer.tsx +20 -0
  50. package/docs/components/mdx/panel.tsx +11 -0
  51. package/docs/components/mdx/param-field.tsx +56 -0
  52. package/docs/components/mdx/preview.tsx +36 -0
  53. package/docs/components/mdx/prompt.tsx +63 -0
  54. package/docs/components/mdx/request-example.tsx +27 -0
  55. package/docs/components/mdx/response-field.tsx +42 -0
  56. package/docs/components/mdx/steps.tsx +92 -0
  57. package/docs/components/mdx/tabs.tsx +88 -0
  58. package/docs/components/mdx/tile.tsx +43 -0
  59. package/docs/components/mdx/tooltip.tsx +71 -0
  60. package/docs/components/mdx/tree.tsx +120 -0
  61. package/docs/components/mdx/type-table.tsx +71 -0
  62. package/docs/components/mdx/update.tsx +44 -0
  63. package/docs/components/mdx/video.tsx +12 -0
  64. package/docs/components/mdx/view.tsx +66 -0
  65. package/docs/components/providers.tsx +15 -0
  66. package/docs/components/ui/breadcrumb.tsx +92 -0
  67. package/docs/components/ui/button.tsx +90 -0
  68. package/docs/components/ui/card.tsx +92 -0
  69. package/docs/components/ui/command.tsx +139 -0
  70. package/docs/components/ui/dialog.tsx +97 -0
  71. package/docs/components/ui/field.tsx +237 -0
  72. package/docs/components/ui/input.tsx +105 -0
  73. package/docs/components/ui/label.tsx +22 -0
  74. package/docs/components/ui/popover.tsx +72 -0
  75. package/docs/components/ui/search.tsx +380 -0
  76. package/docs/components/ui/separator.tsx +26 -0
  77. package/docs/components/ui/sheet.tsx +104 -0
  78. package/docs/components/ui/sidebar.tsx +433 -0
  79. package/docs/components/ui/theme-toggle.tsx +62 -0
  80. package/docs/components/ui/tooltip.tsx +53 -0
  81. package/docs/lib/contextual-options.ts +193 -0
  82. package/docs/lib/docs-collection.ts +22 -0
  83. package/docs/lib/mdx.ts +90 -0
  84. package/docs/lib/navigation.ts +288 -0
  85. package/docs/lib/openapi.ts +158 -0
  86. package/docs/lib/routes.ts +10 -0
  87. package/docs/lib/server-cache.ts +83 -0
  88. package/docs/lib/shiki.ts +35 -0
  89. package/docs/lib/theme.ts +29 -0
  90. package/docs/lib/toc.ts +2 -0
  91. package/docs/lib/utils.ts +5 -0
  92. package/package.json +34 -3
  93. package/packages/@repo/common/dist/index.d.ts +9 -0
  94. package/packages/@repo/common/dist/index.d.ts.map +1 -0
  95. package/packages/@repo/common/dist/index.js +42 -0
  96. package/packages/@repo/common/package.json +34 -0
  97. package/packages/@repo/common/src/common.unit.test.ts +55 -0
  98. package/packages/@repo/common/src/index.ts +51 -0
  99. package/packages/@repo/contracts/dist/api-key.d.ts +30 -0
  100. package/packages/@repo/contracts/dist/api-key.d.ts.map +1 -0
  101. package/packages/@repo/contracts/dist/api-key.js +20 -0
  102. package/packages/@repo/contracts/dist/dates.d.ts +4 -0
  103. package/packages/@repo/contracts/dist/dates.d.ts.map +1 -0
  104. package/packages/@repo/contracts/dist/dates.js +2 -0
  105. package/packages/@repo/contracts/dist/deployment.d.ts +71 -0
  106. package/packages/@repo/contracts/dist/deployment.d.ts.map +1 -0
  107. package/packages/@repo/contracts/dist/deployment.js +46 -0
  108. package/packages/@repo/contracts/dist/domain.d.ts +94 -0
  109. package/packages/@repo/contracts/dist/domain.d.ts.map +1 -0
  110. package/packages/@repo/contracts/dist/domain.js +36 -0
  111. package/packages/@repo/contracts/dist/ids.d.ts +14 -0
  112. package/packages/@repo/contracts/dist/ids.d.ts.map +1 -0
  113. package/packages/@repo/contracts/dist/ids.js +10 -0
  114. package/packages/@repo/contracts/dist/index.d.ts +10 -0
  115. package/packages/@repo/contracts/dist/index.d.ts.map +1 -0
  116. package/packages/@repo/contracts/dist/index.js +11 -0
  117. package/packages/@repo/contracts/dist/pagination.d.ts +23 -0
  118. package/packages/@repo/contracts/dist/pagination.d.ts.map +1 -0
  119. package/packages/@repo/contracts/dist/pagination.js +15 -0
  120. package/packages/@repo/contracts/dist/project.d.ts +25 -0
  121. package/packages/@repo/contracts/dist/project.d.ts.map +1 -0
  122. package/packages/@repo/contracts/dist/project.js +23 -0
  123. package/packages/@repo/contracts/dist/tenant.d.ts +99 -0
  124. package/packages/@repo/contracts/dist/tenant.d.ts.map +1 -0
  125. package/packages/@repo/contracts/dist/tenant.js +36 -0
  126. package/packages/@repo/contracts/dist/user.d.ts +9 -0
  127. package/packages/@repo/contracts/dist/user.d.ts.map +1 -0
  128. package/packages/@repo/contracts/dist/user.js +9 -0
  129. package/packages/@repo/contracts/package.json +37 -0
  130. package/packages/@repo/contracts/src/api-key.ts +27 -0
  131. package/packages/@repo/contracts/src/dates.ts +4 -0
  132. package/packages/@repo/contracts/src/deployment.ts +73 -0
  133. package/packages/@repo/contracts/src/domain.ts +51 -0
  134. package/packages/@repo/contracts/src/ids.ts +22 -0
  135. package/packages/@repo/contracts/src/index.ts +11 -0
  136. package/packages/@repo/contracts/src/pagination.ts +21 -0
  137. package/packages/@repo/contracts/src/project.ts +30 -0
  138. package/packages/@repo/contracts/src/tenant.ts +54 -0
  139. package/packages/@repo/contracts/src/user.ts +12 -0
  140. package/packages/@repo/models/dist/docs-config.d.ts +985 -0
  141. package/packages/@repo/models/dist/docs-config.d.ts.map +1 -0
  142. package/packages/@repo/models/dist/docs-config.js +548 -0
  143. package/packages/@repo/models/dist/index.d.ts +3 -0
  144. package/packages/@repo/models/dist/index.d.ts.map +1 -0
  145. package/packages/@repo/models/dist/index.js +3 -0
  146. package/packages/@repo/models/dist/tenant.d.ts +25 -0
  147. package/packages/@repo/models/dist/tenant.d.ts.map +1 -0
  148. package/packages/@repo/models/dist/tenant.js +1 -0
  149. package/packages/@repo/models/package.json +37 -0
  150. package/packages/@repo/models/src/docs-config.ts +648 -0
  151. package/packages/@repo/models/src/index.ts +3 -0
  152. package/packages/@repo/models/src/tenant.ts +29 -0
  153. package/packages/@repo/prebuild/dist/index.d.ts +2 -0
  154. package/packages/@repo/prebuild/dist/index.d.ts.map +1 -0
  155. package/packages/@repo/prebuild/dist/index.js +2 -0
  156. package/packages/@repo/prebuild/dist/openapi.d.ts +43 -0
  157. package/packages/@repo/prebuild/dist/openapi.d.ts.map +1 -0
  158. package/packages/@repo/prebuild/dist/openapi.js +58 -0
  159. package/packages/@repo/prebuild/package.json +39 -0
  160. package/packages/@repo/prebuild/src/index.ts +2 -0
  161. package/packages/@repo/prebuild/src/openapi.ts +116 -0
  162. package/packages/@repo/previewing/dist/blob-source.d.ts +16 -0
  163. package/packages/@repo/previewing/dist/blob-source.d.ts.map +1 -0
  164. package/packages/@repo/previewing/dist/blob-source.js +110 -0
  165. package/packages/@repo/previewing/dist/content-source.d.ts +12 -0
  166. package/packages/@repo/previewing/dist/content-source.d.ts.map +1 -0
  167. package/packages/@repo/previewing/dist/content-source.js +1 -0
  168. package/packages/@repo/previewing/dist/fs-source.d.ts +11 -0
  169. package/packages/@repo/previewing/dist/fs-source.d.ts.map +1 -0
  170. package/packages/@repo/previewing/dist/fs-source.js +79 -0
  171. package/packages/@repo/previewing/dist/index.d.ts +120 -0
  172. package/packages/@repo/previewing/dist/index.d.ts.map +1 -0
  173. package/packages/@repo/previewing/dist/index.js +984 -0
  174. package/packages/@repo/previewing/package.json +41 -0
  175. package/packages/@repo/previewing/src/blob-source.ts +167 -0
  176. package/packages/@repo/previewing/src/content-source.ts +12 -0
  177. package/packages/@repo/previewing/src/fs-source.ts +111 -0
  178. package/packages/@repo/previewing/src/index.ts +1490 -0
  179. package/packages/@repo/previewing/src/index.unit.test.ts +290 -0
  180. package/packages/@repo/validation/dist/index.d.ts +12 -0
  181. package/packages/@repo/validation/dist/index.d.ts.map +1 -0
  182. package/packages/@repo/validation/dist/index.js +30 -0
  183. package/packages/@repo/validation/package.json +37 -0
  184. package/packages/@repo/validation/src/index.ts +59 -0
  185. package/packages/@repo/validation/src/mintlify-docs-schema.json +5016 -0
@@ -0,0 +1,290 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+
5
+ import { afterEach, describe, expect, it } from "vitest";
6
+
7
+ import {
8
+ buildUtilityArtifacts,
9
+ buildSearchIndex,
10
+ buildContentIndex,
11
+ buildUtilityIndex,
12
+ createFsSource,
13
+ getPrebuiltUtilityLlmPagePath,
14
+ loadPrebuiltUtilityIndex,
15
+ loadSiteConfig,
16
+ PREBUILT_UTILITY_LLMS_FULL_PATH,
17
+ PREBUILT_UTILITY_LLMS_PATH,
18
+ PREBUILT_UTILITY_INDEX_PATH,
19
+ PREBUILT_UTILITY_SITEMAP_PATH,
20
+ UTILITY_DOCS_ROOT_TOKEN,
21
+ serializeUtilityIndex,
22
+ } from "./index";
23
+
24
+ const tempRoots: string[] = [];
25
+
26
+ const createTempContentRoot = async (files: Record<string, string>) => {
27
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), "previewing-"));
28
+ tempRoots.push(root);
29
+
30
+ for (const [relativePath, content] of Object.entries(files)) {
31
+ const absolutePath = path.join(root, relativePath);
32
+ await fs.mkdir(path.dirname(absolutePath), { recursive: true });
33
+ await fs.writeFile(absolutePath, content);
34
+ }
35
+
36
+ return root;
37
+ };
38
+
39
+ afterEach(async () => {
40
+ await Promise.all(
41
+ tempRoots.splice(0).map(async (root) => {
42
+ await fs.rm(root, { force: true, recursive: true });
43
+ })
44
+ );
45
+ });
46
+
47
+ describe("loadSiteConfig", () => {
48
+ it("loads docs.json as the only supported config file", async () => {
49
+ const root = await createTempContentRoot({
50
+ "config/navigation.json": JSON.stringify(
51
+ {
52
+ groups: [{ group: "Getting Started", pages: ["index"] }],
53
+ },
54
+ null,
55
+ 2
56
+ ),
57
+ "docs.json": JSON.stringify(
58
+ {
59
+ $schema: "https://mintlify.com/docs.json",
60
+ api: {
61
+ openapi: "openapi.yaml",
62
+ playground: {
63
+ proxy: true,
64
+ },
65
+ },
66
+ appearance: {
67
+ strict: true,
68
+ },
69
+ colors: {
70
+ primary: "#171717",
71
+ },
72
+ fonts: {
73
+ family: "Inter",
74
+ },
75
+ name: "Example Docs",
76
+ navbar: {
77
+ links: [{ href: "https://example.com", label: "Website" }],
78
+ },
79
+ navigation: {
80
+ $ref: "./config/navigation.json",
81
+ },
82
+ theme: "mint",
83
+ },
84
+ null,
85
+ 2
86
+ ),
87
+ "index.mdx": "---\ntitle: Welcome\n---\n",
88
+ });
89
+
90
+ const result = await loadSiteConfig(createFsSource(root));
91
+
92
+ expect(result.ok).toBe(true);
93
+ if (!result.ok) {
94
+ return;
95
+ }
96
+
97
+ expect(result.warnings).toEqual([]);
98
+ expect(result.config.name).toBe("Example Docs");
99
+ expect(result.config.collections).toHaveLength(1);
100
+ expect(result.config.collections[0]?.openapi).toBe("openapi.yaml");
101
+ expect(result.config.navigation?.groups).toEqual([
102
+ { group: "Getting Started", pages: ["index"] },
103
+ ]);
104
+ expect(result.config.navigation?.global?.links).toEqual([
105
+ { href: "https://example.com", label: "Website" },
106
+ ]);
107
+ expect(result.config.features?.themeToggle).toBe(false);
108
+ expect(result.config.openapiProxy?.enabled).toBe(true);
109
+ expect(result.config.fonts?.cssUrl).toContain("Inter");
110
+ });
111
+
112
+ it("errors when docs.json is missing", async () => {
113
+ const root = await createTempContentRoot({
114
+ "site.json": JSON.stringify({ name: "Old config" }, null, 2),
115
+ });
116
+
117
+ const result = await loadSiteConfig(createFsSource(root));
118
+
119
+ expect(result.ok).toBe(false);
120
+ if (result.ok) {
121
+ return;
122
+ }
123
+
124
+ expect(result.errors).toEqual(["docs.json not found."]);
125
+ });
126
+
127
+ it("loads the shipped tenant docs roots", async () => {
128
+ const exampleResult = await loadSiteConfig(
129
+ createFsSource(path.resolve(process.cwd(), "apps/docs/content/example"))
130
+ );
131
+ const blodeResult = await loadSiteConfig(
132
+ createFsSource(path.resolve(process.cwd(), "apps/docs/content/blode"))
133
+ );
134
+
135
+ expect(exampleResult.ok).toBe(true);
136
+ expect(blodeResult.ok).toBe(true);
137
+
138
+ if (!exampleResult.ok || !blodeResult.ok) {
139
+ return;
140
+ }
141
+
142
+ expect(exampleResult.config.collections[0]?.openapi).toEqual({
143
+ directory: "api",
144
+ source: "openapi.yaml",
145
+ });
146
+ expect(exampleResult.config.openapiProxy?.enabled).toBe(true);
147
+ expect(blodeResult.config.navigation?.groups).toMatchObject([
148
+ {
149
+ group: "Getting Started",
150
+ pages: ["index", "installation"],
151
+ },
152
+ {
153
+ group: "Customization",
154
+ pages: ["typography", "theming"],
155
+ },
156
+ {
157
+ group: "Components",
158
+ pages: ["components/breadcrumb"],
159
+ },
160
+ ]);
161
+ expect(blodeResult.config.navigation?.groups).toHaveLength(3);
162
+ });
163
+ });
164
+
165
+ describe("buildUtilityIndex", () => {
166
+ it("prebuilds content and OpenAPI utility pages", async () => {
167
+ const root = await createTempContentRoot({
168
+ "docs.json": JSON.stringify(
169
+ {
170
+ $schema: "https://mintlify.com/docs.json",
171
+ api: {
172
+ openapi: "openapi.yaml",
173
+ },
174
+ appearance: {
175
+ strict: true,
176
+ },
177
+ colors: {
178
+ primary: "#171717",
179
+ },
180
+ fonts: {
181
+ family: "Inter",
182
+ },
183
+ name: "Example Docs",
184
+ navbar: {
185
+ links: [{ href: "https://example.com", label: "Website" }],
186
+ },
187
+ navigation: {
188
+ groups: [{ group: "Docs", pages: ["index", "guide"] }],
189
+ },
190
+ theme: "mint",
191
+ },
192
+ null,
193
+ 2
194
+ ),
195
+ "guide.mdx": "---\ntitle: Guide\n---\n# Guide\n\nShip it.\n",
196
+ "hidden.mdx": "---\ntitle: Hidden\nhidden: true\n---\n# Hidden\n",
197
+ "index.mdx": "---\ntitle: Welcome\n---\n# Welcome\n\nHello there.\n",
198
+ "openapi.yaml": [
199
+ "openapi: 3.0.0",
200
+ "paths:",
201
+ " /projects:",
202
+ " get:",
203
+ " summary: List projects",
204
+ " description: Return every project.",
205
+ " tags:",
206
+ " - Projects",
207
+ " responses:",
208
+ " '200':",
209
+ " description: OK",
210
+ ].join("\n"),
211
+ });
212
+ const source = createFsSource(root);
213
+ const configResult = await loadSiteConfig(source);
214
+
215
+ expect(configResult.ok).toBe(true);
216
+ if (!configResult.ok) {
217
+ return;
218
+ }
219
+
220
+ const contentIndex = await buildContentIndex(source, configResult.config);
221
+ const utilityIndex = await buildUtilityIndex(
222
+ contentIndex,
223
+ source,
224
+ configResult.config
225
+ );
226
+
227
+ expect(utilityIndex.name).toBe("Example Docs");
228
+ expect(utilityIndex.pages.map((page) => page.slug)).toEqual([
229
+ "api/get-projects",
230
+ "guide",
231
+ "index",
232
+ ]);
233
+ expect(utilityIndex.pages.find((page) => page.slug === "hidden")).toBe(
234
+ undefined
235
+ );
236
+ expect(
237
+ utilityIndex.pages.find((page) => page.slug === "api/get-projects")
238
+ ?.content
239
+ ).toContain("Method: GET");
240
+
241
+ expect(
242
+ buildSearchIndex(contentIndex, configResult.config, utilityIndex)
243
+ ).toEqual(
244
+ expect.arrayContaining([
245
+ expect.objectContaining({
246
+ path: "api/get-projects",
247
+ title: "List projects",
248
+ }),
249
+ ])
250
+ );
251
+
252
+ const artifacts = buildUtilityArtifacts(utilityIndex);
253
+ expect(artifacts.map((artifact) => artifact.path)).toContain(
254
+ PREBUILT_UTILITY_SITEMAP_PATH
255
+ );
256
+ expect(artifacts.map((artifact) => artifact.path)).toContain(
257
+ PREBUILT_UTILITY_LLMS_PATH
258
+ );
259
+ expect(artifacts.map((artifact) => artifact.path)).toContain(
260
+ PREBUILT_UTILITY_LLMS_FULL_PATH
261
+ );
262
+ expect(artifacts.map((artifact) => artifact.path)).toContain(
263
+ getPrebuiltUtilityLlmPagePath("guide")
264
+ );
265
+ expect(
266
+ artifacts.find(
267
+ (artifact) => artifact.path === PREBUILT_UTILITY_SITEMAP_PATH
268
+ )?.content
269
+ ).toContain(`${UTILITY_DOCS_ROOT_TOKEN}/api/get-projects`);
270
+ expect(
271
+ artifacts.find(
272
+ (artifact) => artifact.path === PREBUILT_UTILITY_LLMS_FULL_PATH
273
+ )?.content
274
+ ).toContain("# Guide (__BLODEMD_DOCS_ROOT__/guide)\n\nShip it.");
275
+ expect(
276
+ artifacts.find(
277
+ (artifact) => artifact.path === getPrebuiltUtilityLlmPagePath("guide")
278
+ )?.content
279
+ ).toBe("# Guide\n\nShip it.");
280
+
281
+ await fs.writeFile(
282
+ path.join(root, PREBUILT_UTILITY_INDEX_PATH),
283
+ serializeUtilityIndex(utilityIndex)
284
+ );
285
+
286
+ await expect(loadPrebuiltUtilityIndex(source)).resolves.toEqual(
287
+ utilityIndex
288
+ );
289
+ });
290
+ });
@@ -0,0 +1,12 @@
1
+ import type { ContentType, FrontmatterByType, MintlifyDocsConfig, SiteConfig } from "@repo/models";
2
+ export type ValidationResult<T> = {
3
+ success: true;
4
+ data: T;
5
+ } | {
6
+ success: false;
7
+ errors: string[];
8
+ };
9
+ export declare const validateSiteConfig: (input: unknown) => ValidationResult<SiteConfig>;
10
+ export declare const validateDocsConfig: (input: unknown) => ValidationResult<MintlifyDocsConfig>;
11
+ export declare const validateFrontmatter: <Type extends ContentType>(type: Type, input: unknown) => ValidationResult<FrontmatterByType[Type]>;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACX,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC1B;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC1B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAQzC,eAAO,MAAM,kBAAkB,GAC7B,OAAO,OAAO,KACb,gBAAgB,CAAC,UAAU,CAQ7B,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,OAAO,OAAO,KACb,gBAAgB,CAAC,kBAAkB,CAQrC,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,IAAI,SAAS,WAAW,EAC1D,MAAM,IAAI,EACV,OAAO,OAAO,KACb,gBAAgB,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAS1C,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { FrontmatterSchemaByType, MintlifyDocsConfigSchema, SiteConfigSchema, } from "@repo/models";
2
+ const formatIssues = (issues) => issues.map((issue) => {
3
+ const path = issue.path.length ? issue.path.map(String).join(".") : "root";
4
+ return `${path}: ${issue.message}`;
5
+ });
6
+ export const validateSiteConfig = (input) => {
7
+ const result = SiteConfigSchema.safeParse(input);
8
+ if (result.success) {
9
+ return { data: result.data, success: true };
10
+ }
11
+ const issues = formatIssues(result.error.issues);
12
+ return { errors: issues, success: false };
13
+ };
14
+ export const validateDocsConfig = (input) => {
15
+ const result = MintlifyDocsConfigSchema.safeParse(input);
16
+ if (result.success) {
17
+ return { data: result.data, success: true };
18
+ }
19
+ const issues = formatIssues(result.error.issues);
20
+ return { errors: issues, success: false };
21
+ };
22
+ export const validateFrontmatter = (type, input) => {
23
+ const schema = FrontmatterSchemaByType[type];
24
+ const result = schema.safeParse(input);
25
+ if (result.success) {
26
+ return { data: result.data, success: true };
27
+ }
28
+ const issues = formatIssues(result.error.issues);
29
+ return { errors: issues, success: false };
30
+ };
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@repo/validation",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./src/index.ts",
9
+ "import": "./dist/index.js",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./*": {
13
+ "types": "./src/*.ts",
14
+ "import": "./dist/*.js",
15
+ "default": "./dist/*.js"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "build": "rm -rf dist && tsc",
20
+ "check-types": "tsc --noEmit",
21
+ "lint": "oxlint .",
22
+ "lint:fix": "oxlint --fix .",
23
+ "format": "oxfmt --write .",
24
+ "format:check": "oxfmt ."
25
+ },
26
+ "dependencies": {
27
+ "@repo/models": "*"
28
+ },
29
+ "devDependencies": {
30
+ "@repo/typescript-config": "*",
31
+ "@types/node": "^22.19.15",
32
+ "oxfmt": "^0.42.0",
33
+ "oxlint": "^1.57.0",
34
+ "typescript": "6.0.2",
35
+ "ultracite": "^7.3.2"
36
+ }
37
+ }
@@ -0,0 +1,59 @@
1
+ import {
2
+ FrontmatterSchemaByType,
3
+ MintlifyDocsConfigSchema,
4
+ SiteConfigSchema,
5
+ } from "@repo/models";
6
+ import type {
7
+ ContentType,
8
+ FrontmatterByType,
9
+ MintlifyDocsConfig,
10
+ SiteConfig,
11
+ } from "@repo/models";
12
+
13
+ export type ValidationResult<T> =
14
+ | { success: true; data: T }
15
+ | { success: false; errors: string[] };
16
+
17
+ const formatIssues = (issues: { path: PropertyKey[]; message: string }[]) =>
18
+ issues.map((issue) => {
19
+ const path = issue.path.length ? issue.path.map(String).join(".") : "root";
20
+ return `${path}: ${issue.message}`;
21
+ });
22
+
23
+ export const validateSiteConfig = (
24
+ input: unknown
25
+ ): ValidationResult<SiteConfig> => {
26
+ const result = SiteConfigSchema.safeParse(input);
27
+ if (result.success) {
28
+ return { data: result.data, success: true };
29
+ }
30
+
31
+ const issues = formatIssues(result.error.issues);
32
+ return { errors: issues, success: false };
33
+ };
34
+
35
+ export const validateDocsConfig = (
36
+ input: unknown
37
+ ): ValidationResult<MintlifyDocsConfig> => {
38
+ const result = MintlifyDocsConfigSchema.safeParse(input);
39
+ if (result.success) {
40
+ return { data: result.data, success: true };
41
+ }
42
+
43
+ const issues = formatIssues(result.error.issues);
44
+ return { errors: issues, success: false };
45
+ };
46
+
47
+ export const validateFrontmatter = <Type extends ContentType>(
48
+ type: Type,
49
+ input: unknown
50
+ ): ValidationResult<FrontmatterByType[Type]> => {
51
+ const schema = FrontmatterSchemaByType[type];
52
+ const result = schema.safeParse(input);
53
+ if (result.success) {
54
+ return { data: result.data as FrontmatterByType[Type], success: true };
55
+ }
56
+
57
+ const issues = formatIssues(result.error.issues);
58
+ return { errors: issues, success: false };
59
+ };