radiant-docs 0.1.56 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -76
- package/package.json +2 -4
- package/template/astro.config.mjs +16 -26
- package/template/package-lock.json +18 -0
- package/template/package.json +1 -1
- package/template/src/components/Footer.astro +13 -4
- package/template/src/components/Header.astro +26 -6
- package/template/src/components/SidebarLink.astro +3 -2
- package/template/src/components/SidebarSubgroup.astro +14 -13
- package/template/src/components/sidebar/SidebarEndpointLink.astro +13 -3
- package/template/src/components/sidebar/SidebarOpenApi.astro +2 -0
- package/template/src/components/sidebar/SidebarOpenApiPageLink.astro +1 -0
- package/template/src/components/user/Accordion.astro +0 -13
- package/template/src/components/user/Callout.astro +0 -29
- package/template/src/components/user/Card.astro +31 -204
- package/template/src/components/user/CardGradient.astro +8 -1
- package/template/src/components/user/Column.astro +0 -17
- package/template/src/components/user/Columns.astro +4 -153
- package/template/src/components/user/Image.astro +0 -28
- package/template/src/components/user/Step.astro +0 -10
- package/template/src/components/user/Tab.astro +0 -12
- package/template/src/components/user/Tabs.astro +2 -9
- package/template/src/content.config.ts +1 -1
- package/template/src/lib/code/code-block.ts +1 -1
- package/template/src/lib/mdx/remark-code-block-component.ts +1 -20
- package/template/src/lib/mdx/remark-resolve-internal-links.ts +150 -204
- package/template/src/lib/routes.ts +150 -29
- package/template/src/lib/utils.ts +127 -12
- package/template/src/lib/validation.ts +5 -2826
- package/template/src/pages/[...slug].astro +16 -0
- package/template/src/lib/code/shiki-theme-config.ts +0 -16
- package/template/src/lib/component-error.ts +0 -202
- package/template/src/lib/frontmatter-schema.ts +0 -10
|
@@ -99,6 +99,8 @@ export async function getStaticPaths(): Promise<GetStaticPathsResult> {
|
|
|
99
99
|
const homeRoute: Route = {
|
|
100
100
|
type: "mdx",
|
|
101
101
|
slug: "/",
|
|
102
|
+
preferredSlug: "/",
|
|
103
|
+
routeIdentity: `mdx:${config.home}`,
|
|
102
104
|
filePath: config.home,
|
|
103
105
|
title:
|
|
104
106
|
existingHomeRoute?.title ??
|
|
@@ -122,6 +124,20 @@ export async function getStaticPaths(): Promise<GetStaticPathsResult> {
|
|
|
122
124
|
homePath: config.home,
|
|
123
125
|
},
|
|
124
126
|
});
|
|
127
|
+
} else {
|
|
128
|
+
const firstVisibleRoute = visibleRoutes[0];
|
|
129
|
+
if (firstVisibleRoute) {
|
|
130
|
+
paths.push({
|
|
131
|
+
params: { slug: "/" },
|
|
132
|
+
props: {
|
|
133
|
+
route: {
|
|
134
|
+
...firstVisibleRoute,
|
|
135
|
+
slug: "/",
|
|
136
|
+
preferredSlug: "/",
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
125
141
|
}
|
|
126
142
|
|
|
127
143
|
return paths;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { bundledThemes } from "shiki";
|
|
2
|
-
|
|
3
|
-
export const DEFAULT_SHIKI_LIGHT_THEME = "github-light";
|
|
4
|
-
export const DEFAULT_SHIKI_DARK_THEME = "github-dark";
|
|
5
|
-
|
|
6
|
-
export type CodeSyntaxThemeByMode = {
|
|
7
|
-
light: string;
|
|
8
|
-
dark: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const SHIKI_BUNDLED_THEME_NAMES = Object.keys(bundledThemes).sort();
|
|
12
|
-
const SHIKI_BUNDLED_THEME_NAME_SET = new Set(SHIKI_BUNDLED_THEME_NAMES);
|
|
13
|
-
|
|
14
|
-
export function isBundledShikiThemeName(value: string): boolean {
|
|
15
|
-
return SHIKI_BUNDLED_THEME_NAME_SET.has(value);
|
|
16
|
-
}
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Component validation utilities for user-facing MDX components.
|
|
3
|
-
* All errors are tagged with [USER_ERROR] for proper error handling in runner.ts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Derives the source MDX file path from an Astro URL pathname
|
|
8
|
-
*/
|
|
9
|
-
function getSourceFile(pathname: string): string {
|
|
10
|
-
const pagePath = pathname
|
|
11
|
-
.replace(/^\/documentation\//, "") // Remove base path
|
|
12
|
-
.replace(/\/$/, ""); // Remove trailing slash
|
|
13
|
-
return `${pagePath}.mdx`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Formats a user-friendly error message with file location
|
|
18
|
-
*/
|
|
19
|
-
function formatError(
|
|
20
|
-
componentName: string,
|
|
21
|
-
message: string,
|
|
22
|
-
sourceFile: string
|
|
23
|
-
): string {
|
|
24
|
-
return `[USER_ERROR]: <${componentName}>: ${message} (in ${sourceFile})`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Validates that a prop value is one of the allowed values
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* validateEnum("Callout", "type", type, ["warning", "info", "tip"], Astro.url.pathname);
|
|
32
|
-
*/
|
|
33
|
-
export function validateEnum<T extends string>(
|
|
34
|
-
componentName: string,
|
|
35
|
-
propName: string,
|
|
36
|
-
value: T,
|
|
37
|
-
validValues: readonly T[],
|
|
38
|
-
pathname: string
|
|
39
|
-
): void {
|
|
40
|
-
if (!validValues.includes(value)) {
|
|
41
|
-
const sourceFile = getSourceFile(pathname);
|
|
42
|
-
throw new Error(
|
|
43
|
-
formatError(
|
|
44
|
-
componentName,
|
|
45
|
-
`Invalid prop ${propName}="${value}". Expected one of: ${validValues.join(
|
|
46
|
-
", "
|
|
47
|
-
)}`,
|
|
48
|
-
sourceFile
|
|
49
|
-
)
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Validates that a required prop is provided and not empty
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* validateRequired("Step", "title", title, Astro.url.pathname);
|
|
59
|
-
*/
|
|
60
|
-
export function validateRequired(
|
|
61
|
-
componentName: string,
|
|
62
|
-
propName: string,
|
|
63
|
-
value: unknown,
|
|
64
|
-
pathname: string
|
|
65
|
-
): void {
|
|
66
|
-
if (value === undefined || value === null || value === "") {
|
|
67
|
-
const sourceFile = getSourceFile(pathname);
|
|
68
|
-
throw new Error(
|
|
69
|
-
formatError(
|
|
70
|
-
componentName,
|
|
71
|
-
`Missing required prop "${propName}"`,
|
|
72
|
-
sourceFile
|
|
73
|
-
)
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Validates that a prop is of the expected type
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* validateType("Accordion", "defaultOpen", defaultOpen, "boolean", Astro.url.pathname);
|
|
83
|
-
*/
|
|
84
|
-
export function validateType(
|
|
85
|
-
componentName: string,
|
|
86
|
-
propName: string,
|
|
87
|
-
value: unknown,
|
|
88
|
-
expectedType:
|
|
89
|
-
| "string"
|
|
90
|
-
| "number"
|
|
91
|
-
| "boolean"
|
|
92
|
-
| "object"
|
|
93
|
-
| "array"
|
|
94
|
-
| readonly ("string" | "number" | "boolean" | "object" | "array")[],
|
|
95
|
-
pathname: string
|
|
96
|
-
): void {
|
|
97
|
-
// Skip if undefined (optional props)
|
|
98
|
-
if (value === undefined) return;
|
|
99
|
-
|
|
100
|
-
const expectedTypes = Array.isArray(expectedType)
|
|
101
|
-
? expectedType
|
|
102
|
-
: [expectedType];
|
|
103
|
-
const isValid = expectedTypes.some((type) =>
|
|
104
|
-
type === "array" ? Array.isArray(value) : typeof value === type
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
if (!isValid) {
|
|
108
|
-
const sourceFile = getSourceFile(pathname);
|
|
109
|
-
const actualType = Array.isArray(value) ? "array" : typeof value;
|
|
110
|
-
const expectedTypeLabel = expectedTypes.join(" or ");
|
|
111
|
-
throw new Error(
|
|
112
|
-
formatError(
|
|
113
|
-
componentName,
|
|
114
|
-
`Invalid prop "${propName}": expected ${expectedTypeLabel}, got ${actualType}`,
|
|
115
|
-
sourceFile
|
|
116
|
-
)
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Validates multiple props at once using a schema object
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* validateProps("Callout", Astro.props, {
|
|
126
|
-
* type: { enum: ["warning", "info", "tip", "danger", "success"] },
|
|
127
|
-
* title: { type: "string" },
|
|
128
|
-
* }, Astro.url.pathname);
|
|
129
|
-
*/
|
|
130
|
-
export type PropSchema = {
|
|
131
|
-
required?: boolean;
|
|
132
|
-
type?:
|
|
133
|
-
| "string"
|
|
134
|
-
| "number"
|
|
135
|
-
| "boolean"
|
|
136
|
-
| "object"
|
|
137
|
-
| "array"
|
|
138
|
-
| readonly ("string" | "number" | "boolean" | "object" | "array")[];
|
|
139
|
-
enum?: readonly string[];
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Validates that no unsupported props are passed to a component.
|
|
144
|
-
*/
|
|
145
|
-
export function validateNoUnknownProps(
|
|
146
|
-
componentName: string,
|
|
147
|
-
props: Record<string, unknown>,
|
|
148
|
-
allowedProps: readonly string[],
|
|
149
|
-
pathname: string
|
|
150
|
-
): void {
|
|
151
|
-
const allowed = new Set(allowedProps);
|
|
152
|
-
const unknownProps = Object.keys(props).filter((key) => !allowed.has(key));
|
|
153
|
-
|
|
154
|
-
if (unknownProps.length === 0) return;
|
|
155
|
-
|
|
156
|
-
const sourceFile = getSourceFile(pathname);
|
|
157
|
-
const unknownLabel = unknownProps.map((name) => `"${name}"`).join(", ");
|
|
158
|
-
const allowedLabel = allowedProps.map((name) => `"${name}"`).join(", ");
|
|
159
|
-
const propLabel = unknownProps.length === 1 ? "prop" : "props";
|
|
160
|
-
throw new Error(
|
|
161
|
-
formatError(
|
|
162
|
-
componentName,
|
|
163
|
-
`Unsupported ${propLabel}: ${unknownLabel}. Allowed props: ${allowedLabel}`,
|
|
164
|
-
sourceFile
|
|
165
|
-
)
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function validateProps(
|
|
170
|
-
componentName: string,
|
|
171
|
-
props: Record<string, unknown>,
|
|
172
|
-
schema: Record<string, PropSchema>,
|
|
173
|
-
pathname: string
|
|
174
|
-
): void {
|
|
175
|
-
for (const [propName, rules] of Object.entries(schema)) {
|
|
176
|
-
const value = props[propName];
|
|
177
|
-
|
|
178
|
-
// Check required
|
|
179
|
-
if (rules.required) {
|
|
180
|
-
validateRequired(componentName, propName, value, pathname);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Skip further checks if value is undefined (optional)
|
|
184
|
-
if (value === undefined) continue;
|
|
185
|
-
|
|
186
|
-
// Check type
|
|
187
|
-
if (rules.type) {
|
|
188
|
-
validateType(componentName, propName, value, rules.type, pathname);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Check enum
|
|
192
|
-
if (rules.enum) {
|
|
193
|
-
validateEnum(
|
|
194
|
-
componentName,
|
|
195
|
-
propName,
|
|
196
|
-
value as string,
|
|
197
|
-
rules.enum,
|
|
198
|
-
pathname
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
// Frontmatter schema for MDX files.
|
|
4
|
-
// `title` controls the rendered page title (not navigation labels).
|
|
5
|
-
export const docsSchema = z
|
|
6
|
-
.object({
|
|
7
|
-
title: z.string().optional(),
|
|
8
|
-
description: z.string().optional(),
|
|
9
|
-
})
|
|
10
|
-
.passthrough();
|