@callstack/rspress-preset 0.4.0
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/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/index.cjs +193 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +147 -0
- package/dist/options.d.ts +83 -0
- package/dist/preset.d.ts +3 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Callstack
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Callstack Rspress Preset
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
To install the `@callstack/rspress-preset` package, use your package manager of choice.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @callstack/rspress-preset
|
|
9
|
+
# or
|
|
10
|
+
yarn add @callstack/rspress-preset
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @callstack/rspress-preset
|
|
13
|
+
# or
|
|
14
|
+
bun add @callstack/rspress-preset
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Use the preset helper `withCallstackPreset` to generate a complete Rspress config from a small set of options, and then merge it with your own overrides if needed.
|
|
20
|
+
|
|
21
|
+
> The preset wires up the Callstack theme, sensible defaults, sitemap and open-graph plugins, search, clean URLs, and common theme config.
|
|
22
|
+
|
|
23
|
+
Update your `rspress.config.ts`:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { defineConfig } from '@rspress/core';
|
|
27
|
+
import { withCallstackPreset } from '@callstack/rspress-preset';
|
|
28
|
+
|
|
29
|
+
export default withCallstackPreset(
|
|
30
|
+
{
|
|
31
|
+
context: __dirname,
|
|
32
|
+
docs: {
|
|
33
|
+
title: 'My Project',
|
|
34
|
+
description: 'Awesome docs powered by Rspress',
|
|
35
|
+
editUrl: 'https://github.com/org/repo/edit/main',
|
|
36
|
+
rootUrl: 'https://docs.example.com',
|
|
37
|
+
icon: 'icon.ico',
|
|
38
|
+
logoLight: 'logo-light.png',
|
|
39
|
+
logoDark: 'logo-dark.png',
|
|
40
|
+
ogImage: 'og-image.png',
|
|
41
|
+
// Optional: defaults to 'docs'
|
|
42
|
+
rootDir: 'docs',
|
|
43
|
+
// Optional: social links; keys follow Rspress theme icons
|
|
44
|
+
socials: {
|
|
45
|
+
github: 'https://github.com/org/repo',
|
|
46
|
+
x: 'https://x.com/my_profile',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
// Optional: forwarded to @callstack/rspress-theme/plugin
|
|
50
|
+
theme: {
|
|
51
|
+
// theme settings
|
|
52
|
+
},
|
|
53
|
+
// Optional: boolean or config for rspress-plugin-vercel-analytics.
|
|
54
|
+
vercelAnalytics: true,
|
|
55
|
+
},
|
|
56
|
+
defineConfig({
|
|
57
|
+
// Your extra/override Rspress config if needed
|
|
58
|
+
})
|
|
59
|
+
);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Required/expected public assets
|
|
63
|
+
|
|
64
|
+
All graphical assets are optional but recommended. Place files in `<docs.rootDir>/public/` (default `docs/public/`), and set their filenames via theme options (`docs.icon`, `docs.logoLight`, `docs.logoDark`, `docs.ogImage`). Defaults are used if omitted.
|
|
65
|
+
|
|
66
|
+
- **Favicon**: default `icon.png` (supports `png|svg|jpg|jpeg|webp|avif|ico`)
|
|
67
|
+
- **Logo (light)**: default `logo-light.png` (supports `png|svg|jpg|jpeg|webp|avif`)
|
|
68
|
+
- **Logo (dark)**: default `logo-dark.png` (supports `png|svg|jpg|jpeg|webp|avif`)
|
|
69
|
+
- **Open Graph image**: default `og.png` (supports `png|svg|jpg|jpeg|webp|avif`)
|
|
70
|
+
|
|
71
|
+
If only one of `logoLight` or `logoDark` is provided, it will be used for both modes.
|
|
72
|
+
|
|
73
|
+
## Options Reference
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
withCallstackPreset(options, userConfig)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- **options** (object, required): Preset options.
|
|
80
|
+
- **options.context** (string, required): Absolute path to your project root (e.g. `__dirname`).
|
|
81
|
+
- **options.docs** (object, required):
|
|
82
|
+
- **title** (string, required): Docs site title.
|
|
83
|
+
- **description** (string, required): Site description.
|
|
84
|
+
- **editUrl** (url string, required): Base repo URL used to build “Edit this page” links.
|
|
85
|
+
- **icon** (string, optional): Filename from docs public directory for site icon.
|
|
86
|
+
- **logoLight** (string, optional): Filename from docs public for light logo.
|
|
87
|
+
- **logoDark** (string, optional): Filename from docs public for dark logo.
|
|
88
|
+
- **ogImage** (string, optional): Filename from docs public for Open Graph image.
|
|
89
|
+
- **rootDir** (string, optional): Directory containing markdown docs. Default: `docs`.
|
|
90
|
+
- **rootUrl** (url string, required): Absolute site origin, e.g. `https://docs.example.com`.
|
|
91
|
+
- **socials** (record, optional): Map of social icon name → URL. Keys must match Rspress theme `socialLinks` icons (e.g. `github`, `x`, `discord`, …).
|
|
92
|
+
- **options.theme** (object, optional): Passed through to `@callstack/rspress-theme/plugin`. See that package for available settings.
|
|
93
|
+
- **options.vercelAnalytics** (boolean | object, optional): Enable/disable Vercel Analytics or pass its config. If omitted, it auto-enables when a `vercel.json` exists at the project root.
|
|
94
|
+
|
|
95
|
+
- **userConfig** (Rspress `UserConfig`, optional): Your additional config merged after the preset config via `mergeDocConfig`.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.n = (module)=>{
|
|
5
|
+
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
+
__webpack_require__.d(getter, {
|
|
7
|
+
a: getter
|
|
8
|
+
});
|
|
9
|
+
return getter;
|
|
10
|
+
};
|
|
11
|
+
})();
|
|
12
|
+
(()=>{
|
|
13
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
14
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: definition[key]
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
})();
|
|
20
|
+
(()=>{
|
|
21
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
22
|
+
})();
|
|
23
|
+
(()=>{
|
|
24
|
+
__webpack_require__.r = (exports1)=>{
|
|
25
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
26
|
+
value: 'Module'
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
29
|
+
value: true
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
})();
|
|
33
|
+
var __webpack_exports__ = {};
|
|
34
|
+
__webpack_require__.r(__webpack_exports__);
|
|
35
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
36
|
+
withCallstackPreset: ()=>withCallstackPreset
|
|
37
|
+
});
|
|
38
|
+
const external_node_fs_namespaceObject = require("node:fs");
|
|
39
|
+
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
40
|
+
const external_node_path_namespaceObject = require("node:path");
|
|
41
|
+
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
42
|
+
const plugin_namespaceObject = require("@callstack/rspress-theme/plugin");
|
|
43
|
+
const core_namespaceObject = require("@rspress/core");
|
|
44
|
+
const plugin_llms_namespaceObject = require("@rspress/plugin-llms");
|
|
45
|
+
const plugin_sitemap_namespaceObject = require("@rspress/plugin-sitemap");
|
|
46
|
+
const external_rsbuild_plugin_open_graph_namespaceObject = require("rsbuild-plugin-open-graph");
|
|
47
|
+
const external_rspress_plugin_vercel_analytics_namespaceObject = require("rspress-plugin-vercel-analytics");
|
|
48
|
+
var external_rspress_plugin_vercel_analytics_default = /*#__PURE__*/ __webpack_require__.n(external_rspress_plugin_vercel_analytics_namespaceObject);
|
|
49
|
+
const external_node_util_namespaceObject = require("node:util");
|
|
50
|
+
const external_zod_namespaceObject = require("zod");
|
|
51
|
+
const nonEmptyString = external_zod_namespaceObject.z.string().trim().min(1, {
|
|
52
|
+
message: 'must be a non-empty string'
|
|
53
|
+
});
|
|
54
|
+
const presetOptionsSchema = external_zod_namespaceObject.z.object({
|
|
55
|
+
context: nonEmptyString.refine((value)=>external_node_path_default().isAbsolute(value), {
|
|
56
|
+
message: 'must be an absolute path'
|
|
57
|
+
}).describe('Absolute path to the project root'),
|
|
58
|
+
docs: external_zod_namespaceObject.z.object({
|
|
59
|
+
title: nonEmptyString.describe('Title of the docs'),
|
|
60
|
+
description: nonEmptyString.describe("Description of the docs"),
|
|
61
|
+
editUrl: external_zod_namespaceObject.z.string().trim().url({
|
|
62
|
+
message: 'must be a valid URL'
|
|
63
|
+
}).describe('Base URL to repository for edit links'),
|
|
64
|
+
logoLight: nonEmptyString.optional().describe('Filename from docs public directory for light mode logo (default: logo-light.png)'),
|
|
65
|
+
logoDark: nonEmptyString.optional().describe('Filename from docs public directory for dark mode logo (default: logo-dark.png)'),
|
|
66
|
+
icon: nonEmptyString.optional().describe('Filename from docs public directory for site icon (default: icon.png)'),
|
|
67
|
+
ogImage: nonEmptyString.optional().describe('Filename from docs public directory for Open Graph image (default: og.png)'),
|
|
68
|
+
rootDir: nonEmptyString.optional().describe('Root directory containing markdown docs'),
|
|
69
|
+
rootUrl: external_zod_namespaceObject.z.string().trim().url({
|
|
70
|
+
message: 'must be a valid URL'
|
|
71
|
+
}).describe('Absolute public site origin (e.g. https://example.com)'),
|
|
72
|
+
socials: external_zod_namespaceObject.z.record(external_zod_namespaceObject.z.string().url()).optional().describe('Map of social icon name to profile URL')
|
|
73
|
+
}),
|
|
74
|
+
theme: external_zod_namespaceObject.z.unknown().optional(),
|
|
75
|
+
vercelAnalytics: external_zod_namespaceObject.z.union([
|
|
76
|
+
external_zod_namespaceObject.z.boolean(),
|
|
77
|
+
external_zod_namespaceObject.z.record(external_zod_namespaceObject.z.unknown())
|
|
78
|
+
]).optional().describe('Enable/disable Vercel Analytics or pass its config (overrides auto-detect)')
|
|
79
|
+
});
|
|
80
|
+
function error(...message) {
|
|
81
|
+
for (const msg of message)console.error((0, external_node_util_namespaceObject.styleText)('red', msg));
|
|
82
|
+
}
|
|
83
|
+
function validatePresetOptions(options) {
|
|
84
|
+
const result = presetOptionsSchema.safeParse(options);
|
|
85
|
+
if (!result.success) {
|
|
86
|
+
const bullets = result.error.issues.map((issue)=>{
|
|
87
|
+
var _current__def;
|
|
88
|
+
const pathSegments = issue.path;
|
|
89
|
+
const pathLabel = pathSegments.length > 0 ? pathSegments.join('.') : 'root';
|
|
90
|
+
let current = presetOptionsSchema;
|
|
91
|
+
for (const segment of pathSegments)if (current instanceof external_zod_namespaceObject.z.ZodObject) {
|
|
92
|
+
const objectSchema = current;
|
|
93
|
+
const shape = objectSchema.shape;
|
|
94
|
+
current = shape[String(segment)];
|
|
95
|
+
} else if (current instanceof external_zod_namespaceObject.z.ZodRecord) current = current._def.valueType;
|
|
96
|
+
else break;
|
|
97
|
+
const description = null == current ? void 0 : null == (_current__def = current._def) ? void 0 : _current__def.description;
|
|
98
|
+
const received = issue.received;
|
|
99
|
+
const details = received ? `${issue.message} \u{2014} received ${received}` : issue.message;
|
|
100
|
+
const withDesc = description ? `${details} (${description})` : details;
|
|
101
|
+
return `- ${pathLabel}: ${withDesc}`;
|
|
102
|
+
}).join('\n');
|
|
103
|
+
error('Invalid @callstack/rspress-preset configuration:');
|
|
104
|
+
error(bullets);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
return result.data;
|
|
108
|
+
}
|
|
109
|
+
function createSocialLinks(socials) {
|
|
110
|
+
return Object.entries(socials ?? {}).map(([key, value])=>({
|
|
111
|
+
icon: key,
|
|
112
|
+
mode: 'link',
|
|
113
|
+
content: value
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
const createPreset = (config)=>{
|
|
117
|
+
var _docs_socials, _docs_socials1;
|
|
118
|
+
const { context, docs, theme, vercelAnalytics } = config;
|
|
119
|
+
const rootDir = external_node_path_default().join(context, docs.rootDir ?? 'docs');
|
|
120
|
+
const enableVercel = void 0 === vercelAnalytics ? external_node_fs_default().existsSync(external_node_path_default().join(context, 'vercel.json')) : Boolean(vercelAnalytics);
|
|
121
|
+
const vercelOptions = 'object' == typeof vercelAnalytics ? vercelAnalytics : {};
|
|
122
|
+
return (0, core_namespaceObject.defineConfig)({
|
|
123
|
+
root: rootDir,
|
|
124
|
+
title: docs.title,
|
|
125
|
+
description: docs.description,
|
|
126
|
+
icon: docs.icon,
|
|
127
|
+
globalStyles: external_node_path_default().join(context, 'theme/styles.css'),
|
|
128
|
+
logo: docs.logoLight || docs.logoDark ? {
|
|
129
|
+
light: docs.logoLight ?? docs.logoDark,
|
|
130
|
+
dark: docs.logoDark ?? docs.logoLight
|
|
131
|
+
} : void 0,
|
|
132
|
+
markdown: {
|
|
133
|
+
link: {
|
|
134
|
+
checkDeadLinks: true
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
route: {
|
|
138
|
+
cleanUrls: true
|
|
139
|
+
},
|
|
140
|
+
search: {
|
|
141
|
+
versioned: true,
|
|
142
|
+
codeBlocks: true
|
|
143
|
+
},
|
|
144
|
+
themeConfig: {
|
|
145
|
+
enableContentAnimation: true,
|
|
146
|
+
enableScrollToTop: false,
|
|
147
|
+
footer: {
|
|
148
|
+
message: `Copyright \xa9 ${new Date().getFullYear()} Callstack Open Source`
|
|
149
|
+
},
|
|
150
|
+
editLink: {
|
|
151
|
+
docRepoBaseUrl: docs.editUrl,
|
|
152
|
+
text: 'Edit this page on GitHub'
|
|
153
|
+
},
|
|
154
|
+
socialLinks: createSocialLinks(docs.socials)
|
|
155
|
+
},
|
|
156
|
+
builderConfig: {
|
|
157
|
+
plugins: [
|
|
158
|
+
(0, external_rsbuild_plugin_open_graph_namespaceObject.pluginOpenGraph)({
|
|
159
|
+
title: docs.title,
|
|
160
|
+
type: 'website',
|
|
161
|
+
url: docs.rootUrl,
|
|
162
|
+
image: `${docs.rootUrl}/${docs.ogImage}`,
|
|
163
|
+
description: docs.description,
|
|
164
|
+
twitter: (null == (_docs_socials = docs.socials) ? void 0 : _docs_socials.x) ? {
|
|
165
|
+
site: null == (_docs_socials1 = docs.socials) ? void 0 : _docs_socials1.x,
|
|
166
|
+
card: 'summary_large_image'
|
|
167
|
+
} : void 0
|
|
168
|
+
})
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
plugins: [
|
|
172
|
+
(0, plugin_namespaceObject.pluginCallstackTheme)(theme),
|
|
173
|
+
(0, plugin_sitemap_namespaceObject.pluginSitemap)({
|
|
174
|
+
siteUrl: docs.rootUrl
|
|
175
|
+
}),
|
|
176
|
+
(0, plugin_llms_namespaceObject.pluginLlms)({
|
|
177
|
+
exclude: ({ page })=>page.routePath.includes('404')
|
|
178
|
+
}),
|
|
179
|
+
enableVercel && external_rspress_plugin_vercel_analytics_default()(vercelOptions)
|
|
180
|
+
].filter(Boolean)
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
function withCallstackPreset(options, userConfig) {
|
|
184
|
+
const parsed = validatePresetOptions(options);
|
|
185
|
+
return (0, core_namespaceObject.mergeDocConfig)(createPreset(parsed), userConfig);
|
|
186
|
+
}
|
|
187
|
+
exports.withCallstackPreset = __webpack_exports__.withCallstackPreset;
|
|
188
|
+
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
189
|
+
"withCallstackPreset"
|
|
190
|
+
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
191
|
+
Object.defineProperty(exports, '__esModule', {
|
|
192
|
+
value: true
|
|
193
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { withCallstackPreset } from './preset';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import node_fs from "node:fs";
|
|
2
|
+
import node_path from "node:path";
|
|
3
|
+
import { pluginCallstackTheme } from "@callstack/rspress-theme/plugin";
|
|
4
|
+
import { defineConfig, mergeDocConfig } from "@rspress/core";
|
|
5
|
+
import { pluginLlms } from "@rspress/plugin-llms";
|
|
6
|
+
import { pluginSitemap } from "@rspress/plugin-sitemap";
|
|
7
|
+
import { pluginOpenGraph } from "rsbuild-plugin-open-graph";
|
|
8
|
+
import rspress_plugin_vercel_analytics from "rspress-plugin-vercel-analytics";
|
|
9
|
+
import { styleText } from "node:util";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
const nonEmptyString = z.string().trim().min(1, {
|
|
12
|
+
message: 'must be a non-empty string'
|
|
13
|
+
});
|
|
14
|
+
const presetOptionsSchema = z.object({
|
|
15
|
+
context: nonEmptyString.refine((value)=>node_path.isAbsolute(value), {
|
|
16
|
+
message: 'must be an absolute path'
|
|
17
|
+
}).describe('Absolute path to the project root'),
|
|
18
|
+
docs: z.object({
|
|
19
|
+
title: nonEmptyString.describe('Title of the docs'),
|
|
20
|
+
description: nonEmptyString.describe("Description of the docs"),
|
|
21
|
+
editUrl: z.string().trim().url({
|
|
22
|
+
message: 'must be a valid URL'
|
|
23
|
+
}).describe('Base URL to repository for edit links'),
|
|
24
|
+
logoLight: nonEmptyString.optional().describe('Filename from docs public directory for light mode logo (default: logo-light.png)'),
|
|
25
|
+
logoDark: nonEmptyString.optional().describe('Filename from docs public directory for dark mode logo (default: logo-dark.png)'),
|
|
26
|
+
icon: nonEmptyString.optional().describe('Filename from docs public directory for site icon (default: icon.png)'),
|
|
27
|
+
ogImage: nonEmptyString.optional().describe('Filename from docs public directory for Open Graph image (default: og.png)'),
|
|
28
|
+
rootDir: nonEmptyString.optional().describe('Root directory containing markdown docs'),
|
|
29
|
+
rootUrl: z.string().trim().url({
|
|
30
|
+
message: 'must be a valid URL'
|
|
31
|
+
}).describe('Absolute public site origin (e.g. https://example.com)'),
|
|
32
|
+
socials: z.record(z.string().url()).optional().describe('Map of social icon name to profile URL')
|
|
33
|
+
}),
|
|
34
|
+
theme: z.unknown().optional(),
|
|
35
|
+
vercelAnalytics: z.union([
|
|
36
|
+
z.boolean(),
|
|
37
|
+
z.record(z.unknown())
|
|
38
|
+
]).optional().describe('Enable/disable Vercel Analytics or pass its config (overrides auto-detect)')
|
|
39
|
+
});
|
|
40
|
+
function error(...message) {
|
|
41
|
+
for (const msg of message)console.error(styleText('red', msg));
|
|
42
|
+
}
|
|
43
|
+
function validatePresetOptions(options) {
|
|
44
|
+
const result = presetOptionsSchema.safeParse(options);
|
|
45
|
+
if (!result.success) {
|
|
46
|
+
const bullets = result.error.issues.map((issue)=>{
|
|
47
|
+
var _current__def;
|
|
48
|
+
const pathSegments = issue.path;
|
|
49
|
+
const pathLabel = pathSegments.length > 0 ? pathSegments.join('.') : 'root';
|
|
50
|
+
let current = presetOptionsSchema;
|
|
51
|
+
for (const segment of pathSegments)if (current instanceof z.ZodObject) {
|
|
52
|
+
const objectSchema = current;
|
|
53
|
+
const shape = objectSchema.shape;
|
|
54
|
+
current = shape[String(segment)];
|
|
55
|
+
} else if (current instanceof z.ZodRecord) current = current._def.valueType;
|
|
56
|
+
else break;
|
|
57
|
+
const description = null == current ? void 0 : null == (_current__def = current._def) ? void 0 : _current__def.description;
|
|
58
|
+
const received = issue.received;
|
|
59
|
+
const details = received ? `${issue.message} \u{2014} received ${received}` : issue.message;
|
|
60
|
+
const withDesc = description ? `${details} (${description})` : details;
|
|
61
|
+
return `- ${pathLabel}: ${withDesc}`;
|
|
62
|
+
}).join('\n');
|
|
63
|
+
error('Invalid @callstack/rspress-preset configuration:');
|
|
64
|
+
error(bullets);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
return result.data;
|
|
68
|
+
}
|
|
69
|
+
function createSocialLinks(socials) {
|
|
70
|
+
return Object.entries(socials ?? {}).map(([key, value])=>({
|
|
71
|
+
icon: key,
|
|
72
|
+
mode: 'link',
|
|
73
|
+
content: value
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
const createPreset = (config)=>{
|
|
77
|
+
var _docs_socials, _docs_socials1;
|
|
78
|
+
const { context, docs, theme, vercelAnalytics } = config;
|
|
79
|
+
const rootDir = node_path.join(context, docs.rootDir ?? 'docs');
|
|
80
|
+
const enableVercel = void 0 === vercelAnalytics ? node_fs.existsSync(node_path.join(context, 'vercel.json')) : Boolean(vercelAnalytics);
|
|
81
|
+
const vercelOptions = 'object' == typeof vercelAnalytics ? vercelAnalytics : {};
|
|
82
|
+
return defineConfig({
|
|
83
|
+
root: rootDir,
|
|
84
|
+
title: docs.title,
|
|
85
|
+
description: docs.description,
|
|
86
|
+
icon: docs.icon,
|
|
87
|
+
globalStyles: node_path.join(context, 'theme/styles.css'),
|
|
88
|
+
logo: docs.logoLight || docs.logoDark ? {
|
|
89
|
+
light: docs.logoLight ?? docs.logoDark,
|
|
90
|
+
dark: docs.logoDark ?? docs.logoLight
|
|
91
|
+
} : void 0,
|
|
92
|
+
markdown: {
|
|
93
|
+
link: {
|
|
94
|
+
checkDeadLinks: true
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
route: {
|
|
98
|
+
cleanUrls: true
|
|
99
|
+
},
|
|
100
|
+
search: {
|
|
101
|
+
versioned: true,
|
|
102
|
+
codeBlocks: true
|
|
103
|
+
},
|
|
104
|
+
themeConfig: {
|
|
105
|
+
enableContentAnimation: true,
|
|
106
|
+
enableScrollToTop: false,
|
|
107
|
+
footer: {
|
|
108
|
+
message: `Copyright \xa9 ${new Date().getFullYear()} Callstack Open Source`
|
|
109
|
+
},
|
|
110
|
+
editLink: {
|
|
111
|
+
docRepoBaseUrl: docs.editUrl,
|
|
112
|
+
text: 'Edit this page on GitHub'
|
|
113
|
+
},
|
|
114
|
+
socialLinks: createSocialLinks(docs.socials)
|
|
115
|
+
},
|
|
116
|
+
builderConfig: {
|
|
117
|
+
plugins: [
|
|
118
|
+
pluginOpenGraph({
|
|
119
|
+
title: docs.title,
|
|
120
|
+
type: 'website',
|
|
121
|
+
url: docs.rootUrl,
|
|
122
|
+
image: `${docs.rootUrl}/${docs.ogImage}`,
|
|
123
|
+
description: docs.description,
|
|
124
|
+
twitter: (null == (_docs_socials = docs.socials) ? void 0 : _docs_socials.x) ? {
|
|
125
|
+
site: null == (_docs_socials1 = docs.socials) ? void 0 : _docs_socials1.x,
|
|
126
|
+
card: 'summary_large_image'
|
|
127
|
+
} : void 0
|
|
128
|
+
})
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
plugins: [
|
|
132
|
+
pluginCallstackTheme(theme),
|
|
133
|
+
pluginSitemap({
|
|
134
|
+
siteUrl: docs.rootUrl
|
|
135
|
+
}),
|
|
136
|
+
pluginLlms({
|
|
137
|
+
exclude: ({ page })=>page.routePath.includes('404')
|
|
138
|
+
}),
|
|
139
|
+
enableVercel && rspress_plugin_vercel_analytics(vercelOptions)
|
|
140
|
+
].filter(Boolean)
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
function withCallstackPreset(options, userConfig) {
|
|
144
|
+
const parsed = validatePresetOptions(options);
|
|
145
|
+
return mergeDocConfig(createPreset(parsed), userConfig);
|
|
146
|
+
}
|
|
147
|
+
export { withCallstackPreset };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { pluginCallstackTheme } from '@callstack/rspress-theme/plugin';
|
|
2
|
+
import type pluginVercelAnalytics from 'rspress-plugin-vercel-analytics';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export declare const presetOptionsSchema: z.ZodObject<{
|
|
5
|
+
context: z.ZodEffects<z.ZodString, string, string>;
|
|
6
|
+
docs: z.ZodObject<{
|
|
7
|
+
title: z.ZodString;
|
|
8
|
+
description: z.ZodString;
|
|
9
|
+
editUrl: z.ZodString;
|
|
10
|
+
logoLight: z.ZodOptional<z.ZodString>;
|
|
11
|
+
logoDark: z.ZodOptional<z.ZodString>;
|
|
12
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
13
|
+
ogImage: z.ZodOptional<z.ZodString>;
|
|
14
|
+
rootDir: z.ZodOptional<z.ZodString>;
|
|
15
|
+
rootUrl: z.ZodString;
|
|
16
|
+
socials: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
editUrl: string;
|
|
21
|
+
rootUrl: string;
|
|
22
|
+
logoLight?: string | undefined;
|
|
23
|
+
logoDark?: string | undefined;
|
|
24
|
+
icon?: string | undefined;
|
|
25
|
+
ogImage?: string | undefined;
|
|
26
|
+
rootDir?: string | undefined;
|
|
27
|
+
socials?: Record<string, string> | undefined;
|
|
28
|
+
}, {
|
|
29
|
+
title: string;
|
|
30
|
+
description: string;
|
|
31
|
+
editUrl: string;
|
|
32
|
+
rootUrl: string;
|
|
33
|
+
logoLight?: string | undefined;
|
|
34
|
+
logoDark?: string | undefined;
|
|
35
|
+
icon?: string | undefined;
|
|
36
|
+
ogImage?: string | undefined;
|
|
37
|
+
rootDir?: string | undefined;
|
|
38
|
+
socials?: Record<string, string> | undefined;
|
|
39
|
+
}>;
|
|
40
|
+
theme: z.ZodOptional<z.ZodUnknown>;
|
|
41
|
+
vercelAnalytics: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
42
|
+
}, "strip", z.ZodTypeAny, {
|
|
43
|
+
context: string;
|
|
44
|
+
docs: {
|
|
45
|
+
title: string;
|
|
46
|
+
description: string;
|
|
47
|
+
editUrl: string;
|
|
48
|
+
rootUrl: string;
|
|
49
|
+
logoLight?: string | undefined;
|
|
50
|
+
logoDark?: string | undefined;
|
|
51
|
+
icon?: string | undefined;
|
|
52
|
+
ogImage?: string | undefined;
|
|
53
|
+
rootDir?: string | undefined;
|
|
54
|
+
socials?: Record<string, string> | undefined;
|
|
55
|
+
};
|
|
56
|
+
theme?: unknown;
|
|
57
|
+
vercelAnalytics?: boolean | Record<string, unknown> | undefined;
|
|
58
|
+
}, {
|
|
59
|
+
context: string;
|
|
60
|
+
docs: {
|
|
61
|
+
title: string;
|
|
62
|
+
description: string;
|
|
63
|
+
editUrl: string;
|
|
64
|
+
rootUrl: string;
|
|
65
|
+
logoLight?: string | undefined;
|
|
66
|
+
logoDark?: string | undefined;
|
|
67
|
+
icon?: string | undefined;
|
|
68
|
+
ogImage?: string | undefined;
|
|
69
|
+
rootDir?: string | undefined;
|
|
70
|
+
socials?: Record<string, string> | undefined;
|
|
71
|
+
};
|
|
72
|
+
theme?: unknown;
|
|
73
|
+
vercelAnalytics?: boolean | Record<string, unknown> | undefined;
|
|
74
|
+
}>;
|
|
75
|
+
type ThemeConfig = Parameters<typeof pluginCallstackTheme>[0];
|
|
76
|
+
type VercelAnalyticsConfig = Parameters<typeof pluginVercelAnalytics>[0];
|
|
77
|
+
type PresetSchema = z.infer<typeof presetOptionsSchema>;
|
|
78
|
+
export type PresetConfig = Omit<PresetSchema, 'theme' | 'vercelAnalytics'> & {
|
|
79
|
+
theme?: ThemeConfig;
|
|
80
|
+
vercelAnalytics?: boolean | VercelAnalyticsConfig;
|
|
81
|
+
};
|
|
82
|
+
export declare function validatePresetOptions(options: unknown): PresetConfig;
|
|
83
|
+
export {};
|
package/dist/preset.d.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@callstack/rspress-preset",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Callstack preset for Rspress docs",
|
|
5
|
+
"author": "Jakub Romańczyk <jakub.romanczyk@callstack.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public",
|
|
23
|
+
"registry": "https://registry.npmjs.org/"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/callstack/rspress-theme/tree/main/packages/preset#readme",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/callstack/rspress-theme.git",
|
|
29
|
+
"directory": "packages/preset"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"rspress",
|
|
33
|
+
"theme",
|
|
34
|
+
"preset",
|
|
35
|
+
"callstack",
|
|
36
|
+
"documentation",
|
|
37
|
+
"react",
|
|
38
|
+
"typescript"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@rspress/plugin-llms": "2.0.0-beta.32",
|
|
42
|
+
"@rspress/plugin-sitemap": "2.0.0-beta.32",
|
|
43
|
+
"rsbuild-plugin-open-graph": "^1.0.2",
|
|
44
|
+
"rspress-plugin-vercel-analytics": "^0.3.0",
|
|
45
|
+
"zod": "^3.23.8",
|
|
46
|
+
"@callstack/rspress-theme": "0.4.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@rspress/core": "2.0.0-beta.32"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@microsoft/api-extractor": "^7.52.8",
|
|
53
|
+
"@rslib/core": "^0.10.5",
|
|
54
|
+
"@rspress/core": "2.0.0-beta.32",
|
|
55
|
+
"@types/node": "^22",
|
|
56
|
+
"typescript": "^5.8.3"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "rslib build",
|
|
60
|
+
"dev": "rslib build --watch",
|
|
61
|
+
"typecheck": "tsc --noEmit"
|
|
62
|
+
}
|
|
63
|
+
}
|