@lexibase/rdx-next 1.0.0-beta.2 → 1.0.0-beta.4

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/bin/rdx.mjs CHANGED
@@ -2,11 +2,14 @@
2
2
 
3
3
  import { spawn } from 'node:child_process'
4
4
  import { createRequire } from 'node:module'
5
- import { cp, mkdir } from 'node:fs/promises'
5
+ import { access, cp, mkdir } from 'node:fs/promises'
6
6
  import path from 'node:path'
7
7
  import { fileURLToPath } from 'node:url'
8
8
  import process from 'node:process'
9
9
 
10
+ import { createRdxProject } from '@lexibase/rdx-core/config'
11
+ import { createJiti } from 'jiti'
12
+
10
13
  const supportedCommands = new Set(['dev', 'build', 'start'])
11
14
  const command = process.argv[2]
12
15
  const commandArgs = process.argv.slice(3)
@@ -23,28 +26,86 @@ async function prepareRuntime() {
23
26
  await cp(runtimeTemplate, runtimeDirectory, { force: true, recursive: true })
24
27
  }
25
28
 
26
- if (command === 'prepare') {
27
- await prepareRuntime()
28
- console.log('RDX runtime prepared in .rdx/')
29
- process.exit(0)
30
- }
29
+ async function main() {
30
+ if (!command || command === 'help' || command === '--help') {
31
+ console.log('Usage: rdx <dev|build|start|prepare|plugin-command>')
32
+ console.log(
33
+ 'Plugin commands are registered through plugins in rdx.config.ts.'
34
+ )
35
+ return
36
+ }
31
37
 
32
- if (!command || !supportedCommands.has(command)) {
33
- console.error('Usage: rdx <dev|build|start|prepare>')
34
- process.exit(1)
35
- }
38
+ const configPath = path.join(projectRoot, 'rdx.config.ts')
39
+ try {
40
+ await access(configPath)
41
+ } catch {
42
+ throw new Error(
43
+ `Missing ${configPath}. Run rdx from the documentation project root.`
44
+ )
45
+ }
36
46
 
37
- await prepareRuntime()
47
+ const jiti = createJiti(import.meta.url, {
48
+ moduleCache: false,
49
+ fsCache: false,
50
+ })
51
+ let input
52
+ try {
53
+ input = await jiti.import(configPath, { default: true })
54
+ } catch (error) {
55
+ const hint =
56
+ error.code === 'MODULE_NOT_FOUND' || error.code === 'ERR_MODULE_NOT_FOUND'
57
+ ? ' If a configured plugin cannot be resolved, install its package in this project.'
58
+ : ''
59
+ throw new Error(`Could not load rdx.config.ts: ${error.message}${hint}`)
60
+ }
38
61
 
39
- const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
40
- const nextCli = projectRequire.resolve('next/dist/bin/next')
41
- const child = spawn(
42
- process.execPath,
43
- [nextCli, command, runtimeDirectory, ...commandArgs],
44
- { cwd: projectRoot, stdio: 'inherit' }
45
- )
62
+ const project = await createRdxProject(input, {
63
+ rootDir: projectRoot,
64
+ command,
65
+ })
66
+ if (command === 'prepare') {
67
+ await prepareRuntime()
68
+ console.log('RDX runtime prepared in .rdx/')
69
+ return
70
+ }
71
+ if (!supportedCommands.has(command)) {
72
+ const pluginCommand = project.commands.find(
73
+ (entry) => entry.name === command
74
+ )
75
+ if (!pluginCommand)
76
+ throw new Error(
77
+ `Unknown command "${command}". Available: dev, build, start, prepare${project.commands.map((entry) => `, ${entry.name}`).join('')}. Install and configure the plugin that provides this command.`
78
+ )
79
+ await pluginCommand.run({
80
+ rootDir: projectRoot,
81
+ config: project.config,
82
+ command,
83
+ args: commandArgs,
84
+ })
85
+ return
86
+ }
46
87
 
47
- child.on('exit', (code, signal) => {
48
- if (signal) process.kill(process.pid, signal)
49
- process.exit(code ?? 1)
50
- })
88
+ await prepareRuntime()
89
+ const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
90
+ const nextCli = projectRequire.resolve('next/dist/bin/next')
91
+ const child = spawn(
92
+ process.execPath,
93
+ [nextCli, command, runtimeDirectory, ...commandArgs],
94
+ { cwd: projectRoot, stdio: 'inherit' }
95
+ )
96
+ child.on('error', (error) => {
97
+ console.error(`[RDX] Could not start Next.js: ${error.message}`)
98
+ process.exitCode = 1
99
+ })
100
+ child.on('exit', (code, signal) => {
101
+ if (signal) process.kill(process.pid, signal)
102
+ process.exit(code ?? 1)
103
+ })
104
+ }
105
+
106
+ try {
107
+ await main()
108
+ } catch (error) {
109
+ console.error(`[RDX] ${error.message}`)
110
+ process.exitCode = 1
111
+ }
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
- export { RdxRuntimeConfig } from '@lexibase/rdx-types';
1
+ export { defineConfig } from '@lexibase/rdx-core/config';
2
+ export { RdxConfig, RdxPlugin, RdxPluginContext, RdxRuntimeConfig } from '@lexibase/rdx-types';
package/dist/index.js CHANGED
@@ -0,0 +1,5 @@
1
+ // src/index.ts
2
+ import { defineConfig } from "@lexibase/rdx-core/config";
3
+ export {
4
+ defineConfig
5
+ };
@@ -1,14 +1,15 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- export { getDocsPaths } from '@lexibase/rdx-core';
4
- import { RdxRuntimeConfig } from '@lexibase/rdx-types';
3
+ import { RdxProject, RdxRuntimeConfig } from '@lexibase/rdx-types';
4
+ export { createRdxProject, getProjectDocsPaths } from '@lexibase/rdx-core';
5
5
 
6
6
  declare function RdxLayout({ children, config, }: {
7
7
  children: ReactNode;
8
8
  config: RdxRuntimeConfig;
9
9
  }): react_jsx_runtime.JSX.Element;
10
- declare function DocsPage({ slug }: {
10
+ declare function DocsPage({ slug, project, }: {
11
11
  slug?: string[];
12
+ project: RdxProject;
12
13
  }): Promise<react_jsx_runtime.JSX.Element>;
13
14
 
14
15
  export { DocsPage, RdxLayout };
@@ -1,9 +1,14 @@
1
1
  // src/runtime/index.tsx
2
- import { getDocument, getDocsIndex, getDocsPaths } from "@lexibase/rdx-core";
3
- import { getDocsPaths as getDocsPaths2 } from "@lexibase/rdx-core";
2
+ import {
3
+ getDocument,
4
+ getDocsPaths,
5
+ getSourceOptions,
6
+ resolveDocsRoute
7
+ } from "@lexibase/rdx-core";
4
8
  import { compileMDX } from "next-mdx-remote/rsc";
5
9
  import Link from "next/link";
6
10
  import { notFound } from "next/navigation";
11
+ import { createRdxProject, getProjectDocsPaths } from "@lexibase/rdx-core";
7
12
  import { jsx, jsxs } from "react/jsx-runtime";
8
13
  var mdxComponents = {
9
14
  h1: (props) => /* @__PURE__ */ jsx("h1", { ...props }),
@@ -33,34 +38,47 @@ function RdxLayout({
33
38
  children,
34
39
  config
35
40
  }) {
36
- const brand = config.navbar?.title || config.title;
37
- return /* @__PURE__ */ jsx("html", { lang: "en", children: /* @__PURE__ */ jsxs("body", { children: [
38
- /* @__PURE__ */ jsxs("header", { className: "rdx-header", children: [
39
- /* @__PURE__ */ jsx(Link, { className: "rdx-brand", href: "/docs", children: brand }),
40
- config.navbar?.actions?.github?.visible && config.navbar.actions.github.url && /* @__PURE__ */ jsx(
41
- "a",
42
- {
43
- className: "rdx-github-link",
44
- href: config.navbar.actions.github.url,
45
- rel: "noreferrer",
46
- target: "_blank",
47
- children: "GitHub"
48
- }
49
- )
50
- ] }),
51
- children
52
- ] }) });
41
+ const brand = config.navbar?.title ?? config.title;
42
+ return /* @__PURE__ */ jsx(
43
+ "html",
44
+ {
45
+ lang: config.lang ?? "en",
46
+ "data-theme": config.theme?.defaultTheme ?? "system",
47
+ children: /* @__PURE__ */ jsxs("body", { children: [
48
+ /* @__PURE__ */ jsxs("header", { className: "rdx-header", children: [
49
+ /* @__PURE__ */ jsx(Link, { className: "rdx-brand", href: "/docs", "aria-label": config.title, children: brand }),
50
+ config.navbar?.actions?.github?.visible && config.navbar.actions.github.url && /* @__PURE__ */ jsx(
51
+ "a",
52
+ {
53
+ className: "rdx-github-link",
54
+ href: config.navbar.actions.github.url,
55
+ rel: "noreferrer",
56
+ target: "_blank",
57
+ children: "GitHub"
58
+ }
59
+ )
60
+ ] }),
61
+ children
62
+ ] })
63
+ }
64
+ );
53
65
  }
54
- async function DocsPage({ slug }) {
55
- const categories = getDocsIndex();
56
- const currentSlug = slug?.join("/") || getDocsPaths()[0];
66
+ async function DocsPage({
67
+ slug,
68
+ project
69
+ }) {
70
+ const {
71
+ source,
72
+ slug: currentSlug,
73
+ document,
74
+ categories
75
+ } = resolveDocsRoute(project, slug);
57
76
  if (!currentSlug) {
58
77
  return /* @__PURE__ */ jsxs("main", { className: "rdx-empty-state", children: [
59
78
  /* @__PURE__ */ jsx("h1", { children: "Your documentation is ready." }),
60
79
  /* @__PURE__ */ jsx("p", { children: "Add an `.mdx` file inside `docs/` to create your first page." })
61
80
  ] });
62
81
  }
63
- const document = getDocument(currentSlug);
64
82
  if (!document) notFound();
65
83
  const { content } = await compileMDX({
66
84
  source: document.content,
@@ -69,24 +87,44 @@ async function DocsPage({ slug }) {
69
87
  const title = typeof document.frontmatter.title === "string" ? document.frontmatter.title : currentSlug;
70
88
  const description = typeof document.frontmatter.description === "string" ? document.frontmatter.description : null;
71
89
  return /* @__PURE__ */ jsxs("div", { className: "rdx-docs-layout", children: [
72
- /* @__PURE__ */ jsx("aside", { className: "rdx-sidebar", "aria-label": "Documentation navigation", children: categories.map((category) => /* @__PURE__ */ jsxs("section", { className: "rdx-sidebar-category", children: [
73
- /* @__PURE__ */ jsx("h2", { children: category.title }),
74
- /* @__PURE__ */ jsx("ul", { children: category.pages.map((page) => {
75
- const href = `/docs/${page.slug}`;
76
- const isCurrentPage = page.slug === currentSlug;
77
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
90
+ /* @__PURE__ */ jsxs("aside", { className: "rdx-sidebar", "aria-label": "Documentation navigation", children: [
91
+ project.sources.length > 1 && /* @__PURE__ */ jsx("nav", { className: "rdx-editions", "aria-label": "Documentation editions", children: project.sources.map((edition) => {
92
+ const options = getSourceOptions(project, edition);
93
+ const destination = getDocument(currentSlug, options) ? currentSlug : getDocsPaths(options)[0];
94
+ const href = ["/docs", edition.routePrefix, destination].filter(Boolean).join("/");
95
+ return /* @__PURE__ */ jsxs(
78
96
  Link,
79
97
  {
80
- "aria-current": isCurrentPage ? "page" : void 0,
81
- className: isCurrentPage ? "is-active" : void 0,
82
98
  href,
83
- children: page.title
84
- }
85
- ) }, page.slug);
86
- }) })
87
- ] }, category.id)) }),
99
+ "aria-current": edition.id === source.id ? "page" : void 0,
100
+ children: [
101
+ edition.label,
102
+ edition.badge ? ` (${edition.badge})` : ""
103
+ ]
104
+ },
105
+ edition.id
106
+ );
107
+ }) }),
108
+ categories.map((category) => /* @__PURE__ */ jsxs("section", { className: "rdx-sidebar-category", children: [
109
+ /* @__PURE__ */ jsx("h2", { children: category.title }),
110
+ /* @__PURE__ */ jsx("ul", { children: category.pages.map((page) => {
111
+ const href = ["/docs", source.routePrefix, page.slug].filter(Boolean).join("/");
112
+ const isCurrentPage = page.slug === currentSlug;
113
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
114
+ Link,
115
+ {
116
+ "aria-current": isCurrentPage ? "page" : void 0,
117
+ className: isCurrentPage ? "is-active" : void 0,
118
+ href,
119
+ children: page.title
120
+ }
121
+ ) }, page.slug);
122
+ }) })
123
+ ] }, category.id))
124
+ ] }),
88
125
  /* @__PURE__ */ jsxs("main", { className: "rdx-document", children: [
89
126
  /* @__PURE__ */ jsxs("header", { className: "rdx-document-header", children: [
127
+ source.badge && /* @__PURE__ */ jsx("p", { className: "rdx-source-badge", children: source.badge }),
90
128
  /* @__PURE__ */ jsx("p", { className: "rdx-breadcrumb", children: currentSlug }),
91
129
  /* @__PURE__ */ jsx("h1", { children: title }),
92
130
  description && /* @__PURE__ */ jsx("p", { className: "rdx-description", children: description })
@@ -98,5 +136,6 @@ async function DocsPage({ slug }) {
98
136
  export {
99
137
  DocsPage,
100
138
  RdxLayout,
101
- getDocsPaths2 as getDocsPaths
139
+ createRdxProject,
140
+ getProjectDocsPaths
102
141
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexibase/rdx-next",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "The Next.js runtime for RDX documentation projects.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,9 +24,10 @@
24
24
  "README.md"
25
25
  ],
26
26
  "dependencies": {
27
+ "jiti": "^2.6.1",
27
28
  "next-mdx-remote": "^5.0.0",
28
- "@lexibase/rdx-types": "1.0.0-beta.0",
29
- "@lexibase/rdx-core": "1.0.0-beta.0"
29
+ "@lexibase/rdx-types": "1.0.0-beta.2",
30
+ "@lexibase/rdx-core": "1.0.0-beta.2"
30
31
  },
31
32
  "peerDependencies": {
32
33
  "next": "^15.5.0",
@@ -54,12 +55,13 @@
54
55
  "react": "19.1.0",
55
56
  "react-dom": "19.1.0",
56
57
  "typescript": "5.9.2",
57
- "@rdx/eslint-config": "1.0.0",
58
- "@rdx/typescript-config": "1.0.0"
58
+ "@rdx/typescript-config": "1.0.0",
59
+ "@rdx/eslint-config": "1.0.0"
59
60
  },
60
61
  "scripts": {
61
62
  "build": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --clean --external @lexibase/rdx-core --external @lexibase/rdx-types --external next --external react --external react-dom --external next-mdx-remote",
62
63
  "lint": "eslint . --max-warnings 0",
63
- "check-types": "tsc --noEmit"
64
+ "check-types": "tsc --noEmit",
65
+ "test": "node --test tests/*.test.mjs"
64
66
  }
65
67
  }
@@ -1,7 +1,11 @@
1
- import { DocsPage, getDocsPaths } from '@lexibase/rdx-next/runtime'
1
+ import { DocsPage, getProjectDocsPaths } from '@lexibase/rdx-next/runtime'
2
2
 
3
- export function generateStaticParams() {
4
- return getDocsPaths().map((slug) => ({ slug: slug.split('/') }))
3
+ import { getProject } from '../../../rdx-project'
4
+
5
+ export async function generateStaticParams() {
6
+ return getProjectDocsPaths(await getProject()).map((slug) => ({
7
+ slug: slug.split('/'),
8
+ }))
5
9
  }
6
10
 
7
11
  export default async function DocumentationPage({
@@ -11,5 +15,5 @@ export default async function DocumentationPage({
11
15
  }) {
12
16
  const { slug } = await params
13
17
 
14
- return <DocsPage slug={slug} />
18
+ return <DocsPage slug={slug} project={await getProject()} />
15
19
  }
@@ -8,7 +8,7 @@
8
8
  }
9
9
 
10
10
  @media (prefers-color-scheme: dark) {
11
- :root {
11
+ :root:not([data-theme='light']) {
12
12
  --rdx-background: #121212;
13
13
  --rdx-foreground: #f4f4f5;
14
14
  --rdx-muted: #a1a1aa;
@@ -18,6 +18,26 @@
18
18
  }
19
19
  }
20
20
 
21
+ :root[data-theme='dark'] {
22
+ --rdx-background: #121212;
23
+ --rdx-foreground: #f4f4f5;
24
+ --rdx-muted: #a1a1aa;
25
+ --rdx-border: #303033;
26
+ --rdx-accent: #202022;
27
+ --rdx-link: #7bb0ff;
28
+ }
29
+
30
+ .rdx-editions {
31
+ border-bottom: 1px solid var(--rdx-border);
32
+ margin-bottom: 20px;
33
+ padding-bottom: 20px;
34
+ }
35
+
36
+ .rdx-source-badge {
37
+ color: var(--rdx-muted);
38
+ font-size: 0.85rem;
39
+ }
40
+
21
41
  * {
22
42
  box-sizing: border-box;
23
43
  }
@@ -2,20 +2,21 @@ import type { Metadata } from 'next'
2
2
 
3
3
  import { RdxLayout } from '@lexibase/rdx-next/runtime'
4
4
 
5
- import config from '../../rdx.config'
5
+ import { getProject } from '../rdx-project'
6
6
 
7
7
  import './globals.css'
8
8
 
9
- export const metadata: Metadata = {
10
- title: {
11
- default: config.title,
12
- template: `%s | ${config.title}`,
13
- },
14
- description: config.description,
9
+ export async function generateMetadata(): Promise<Metadata> {
10
+ const { config } = await getProject()
11
+ return {
12
+ title: { default: config.title, template: `%s | ${config.title}` },
13
+ description: config.description,
14
+ }
15
15
  }
16
16
 
17
- export default function RootLayout({
17
+ export default async function RootLayout({
18
18
  children,
19
19
  }: Readonly<{ children: React.ReactNode }>) {
20
+ const { config } = await getProject()
20
21
  return <RdxLayout config={config}>{children}</RdxLayout>
21
22
  }
@@ -0,0 +1,7 @@
1
+ import { createRdxProject } from '@lexibase/rdx-next/runtime'
2
+
3
+ import config from '../rdx.config'
4
+
5
+ export function getProject() {
6
+ return createRdxProject(config)
7
+ }
@@ -2,6 +2,8 @@
2
2
  "compilerOptions": {
3
3
  "allowJs": true,
4
4
  "esModuleInterop": true,
5
+ "incremental": true,
6
+ "isolatedModules": true,
5
7
  "jsx": "preserve",
6
8
  "lib": ["dom", "dom.iterable", "esnext"],
7
9
  "module": "esnext",
@@ -9,6 +11,7 @@
9
11
  "noEmit": true,
10
12
  "plugins": [{ "name": "next" }],
11
13
  "resolveJsonModule": true,
14
+ "skipLibCheck": true,
12
15
  "strict": true,
13
16
  "target": "esnext"
14
17
  },