@lexibase/create-rdx 1.0.0-beta.9 → 1.0.1
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/README.md +49 -0
- package/bin/index.js +119 -81
- package/bin/options.mjs +30 -0
- package/package.json +2 -2
- package/templates/default/README.md +7 -1
- package/templates/default/docs/examples/accordion.mdx +3 -3
- package/templates/default/docs/examples/tabs.mdx +1 -1
- package/templates/default/package.json +3 -3
- package/templates/default/rdx.config.ts +25 -2
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @lexibase/create-rdx
|
|
2
|
+
|
|
3
|
+
Create a documentation project using Next.js, Tailwind CSS and shadcn/ui Base UI.
|
|
4
|
+
|
|
5
|
+
Requires Node.js 22.18+ (22.x) or 24.11+ (24.x), preferably the latest patch.
|
|
6
|
+
See the repository's SUPPORT.md for the automated platform/package-manager matrix.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm create @lexibase/rdx@latest
|
|
12
|
+
# Or: pnpm create @lexibase/rdx@latest
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The prompt asks for the project name, which becomes a new directory inside
|
|
16
|
+
the current directory. You can also pass it directly:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm create @lexibase/rdx@latest my-docs
|
|
20
|
+
pnpm create @lexibase/rdx@latest my-docs
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use a short name starting with a letter or number, followed by letters, numbers,
|
|
24
|
+
dots, dashes or underscores. Paths, spaces, trailing dots and Windows/npm reserved
|
|
25
|
+
names are rejected. The folder keeps its capitalization; the npm package name
|
|
26
|
+
is lowercased. Existing paths are never reused or overwritten.
|
|
27
|
+
|
|
28
|
+
## Options
|
|
29
|
+
|
|
30
|
+
Forward options after `--` when using npm create:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npm create @lexibase/rdx@latest -- --help
|
|
34
|
+
npm create @lexibase/rdx@latest -- --version
|
|
35
|
+
npm create @lexibase/rdx@latest my-docs -- --skip-install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`--skip-install` creates source files without installing dependencies or preparing
|
|
39
|
+
`.rdx/`. Otherwise the creator uses the invoking package manager and prepares
|
|
40
|
+
the runtime. Follow the commands printed by the generator.
|
|
41
|
+
|
|
42
|
+
## Recovery
|
|
43
|
+
|
|
44
|
+
If installation or preparation fails, the command exits with an error and keeps
|
|
45
|
+
the generated files. Fix the reported issue, enter the created folder and retry
|
|
46
|
+
installation/development using the same package manager. Do not rerun creation
|
|
47
|
+
over that directory, delete lockfiles or disable security policies automatically.
|
|
48
|
+
|
|
49
|
+
See the generated README for development, public files and optional versioning.
|
package/bin/index.js
CHANGED
|
@@ -7,12 +7,7 @@ import spawn from 'cross-spawn'
|
|
|
7
7
|
import fs from 'fs-extra'
|
|
8
8
|
import prompts from 'prompts'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const argumentsFromCli = process.argv.slice(2)
|
|
12
|
-
const skipInstall = argumentsFromCli.includes('--skip-install')
|
|
13
|
-
const nameFromCli = argumentsFromCli.find(
|
|
14
|
-
(argument) => !argument.startsWith('-')
|
|
15
|
-
)
|
|
10
|
+
import { parseArguments, validateProjectName } from './options.mjs'
|
|
16
11
|
|
|
17
12
|
function getPackageManager() {
|
|
18
13
|
const userAgent = process.env.npm_config_user_agent || ''
|
|
@@ -23,18 +18,6 @@ function getPackageManager() {
|
|
|
23
18
|
return 'npm'
|
|
24
19
|
}
|
|
25
20
|
|
|
26
|
-
function validateProjectName(projectName) {
|
|
27
|
-
if (!projectName) return 'Please enter a project name.'
|
|
28
|
-
if (!projectNamePattern.test(projectName)) {
|
|
29
|
-
return 'Use letters, numbers, dots, dashes, or underscores only.'
|
|
30
|
-
}
|
|
31
|
-
if (projectName === '.' || projectName === '..') {
|
|
32
|
-
return 'Choose a name other than . or ...'
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return true
|
|
36
|
-
}
|
|
37
|
-
|
|
38
21
|
function run(command, args, cwd) {
|
|
39
22
|
return new Promise((resolve, reject) => {
|
|
40
23
|
// Reuse the Node entry point when available. Otherwise cross-spawn
|
|
@@ -59,72 +42,127 @@ function run(command, args, cwd) {
|
|
|
59
42
|
})
|
|
60
43
|
}
|
|
61
44
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
45
|
+
async function main() {
|
|
46
|
+
const {
|
|
47
|
+
projectName: nameFromCli,
|
|
48
|
+
skipInstall,
|
|
49
|
+
help,
|
|
50
|
+
version,
|
|
51
|
+
} = parseArguments(process.argv.slice(2))
|
|
52
|
+
if (help) {
|
|
53
|
+
console.log('Usage: create-rdx [project-name] [--skip-install]')
|
|
54
|
+
console.log(' Without a project name, RDX asks for one interactively.')
|
|
55
|
+
console.log(
|
|
56
|
+
' --skip-install Create files without installing dependencies.'
|
|
57
|
+
)
|
|
58
|
+
console.log(' --help, -h Show this help.')
|
|
59
|
+
console.log(' --version, -v Show the generator version.')
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
if (version) {
|
|
63
|
+
const pkg = await fs.readJson(new URL('../package.json', import.meta.url))
|
|
64
|
+
console.log(pkg.version)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
if (nameFromCli !== undefined) {
|
|
68
|
+
const validation = validateProjectName(nameFromCli)
|
|
69
|
+
if (validation !== true) throw new Error(validation)
|
|
70
|
+
}
|
|
71
|
+
const response =
|
|
72
|
+
nameFromCli !== undefined
|
|
73
|
+
? { projectName: nameFromCli }
|
|
74
|
+
: await prompts({
|
|
75
|
+
type: 'text',
|
|
76
|
+
name: 'projectName',
|
|
77
|
+
message: 'What is your project named?',
|
|
78
|
+
validate: validateProjectName,
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const { projectName } = response
|
|
82
|
+
if (!projectName) {
|
|
83
|
+
console.log('Project creation cancelled.')
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
const validation = validateProjectName(projectName)
|
|
87
|
+
if (validation !== true) throw new Error(validation)
|
|
70
88
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
console.log('Project creation cancelled.')
|
|
74
|
-
process.exit(0)
|
|
75
|
-
}
|
|
89
|
+
const targetDir = path.resolve(process.cwd(), projectName)
|
|
90
|
+
const relativeTarget = path.relative(process.cwd(), targetDir)
|
|
76
91
|
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
if (relativeTarget.startsWith('..') || path.isAbsolute(relativeTarget)) {
|
|
93
|
+
throw new Error('Project must be created inside the current directory.')
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
await fs.mkdir(targetDir)
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (error.code === 'EEXIST')
|
|
99
|
+
throw new Error(
|
|
100
|
+
`The path "${projectName}" already exists. Choose another name; existing files are never overwritten.`
|
|
101
|
+
)
|
|
102
|
+
throw error
|
|
103
|
+
}
|
|
79
104
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
const currentFile = fileURLToPath(import.meta.url)
|
|
106
|
+
const templateDir = path.resolve(
|
|
107
|
+
path.dirname(currentFile),
|
|
108
|
+
'../templates/default'
|
|
109
|
+
)
|
|
110
|
+
await fs.copy(templateDir, targetDir, {
|
|
111
|
+
errorOnExist: true,
|
|
112
|
+
overwrite: false,
|
|
113
|
+
})
|
|
114
|
+
await fs.ensureDir(path.join(targetDir, 'public'))
|
|
86
115
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
)
|
|
92
|
-
await fs.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
await fs.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
const gitignoreTemplatePath = path.join(targetDir, 'gitignore.template')
|
|
117
|
+
await fs.move(gitignoreTemplatePath, path.join(targetDir, '.gitignore'), {
|
|
118
|
+
overwrite: true,
|
|
119
|
+
})
|
|
120
|
+
await fs.remove(path.join(targetDir, 'gitignore'))
|
|
121
|
+
await fs.remove(path.join(targetDir, '.npmignore'))
|
|
122
|
+
|
|
123
|
+
const pkgPath = path.join(targetDir, 'package.json')
|
|
124
|
+
const pkg = await fs.readJson(pkgPath)
|
|
125
|
+
pkg.name = projectName.toLowerCase()
|
|
126
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 })
|
|
127
|
+
|
|
128
|
+
const readmePath = path.join(targetDir, 'README.md')
|
|
129
|
+
const readme = await fs.readFile(readmePath, 'utf8')
|
|
130
|
+
await fs.writeFile(
|
|
131
|
+
readmePath,
|
|
132
|
+
readme
|
|
133
|
+
.replaceAll('{{RDX_PROJECT_NAME}}', projectName)
|
|
134
|
+
.replaceAll('__RDX_PROJECT_NAME__', projectName)
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
const packageManager = getPackageManager()
|
|
138
|
+
|
|
139
|
+
if (!skipInstall) {
|
|
140
|
+
try {
|
|
141
|
+
console.log(`\nInstalling dependencies with ${packageManager}...\n`)
|
|
142
|
+
await run(packageManager, ['install'], targetDir)
|
|
143
|
+
const prepareArgs =
|
|
144
|
+
packageManager === 'npm'
|
|
145
|
+
? ['exec', '--', 'rdx', 'prepare']
|
|
146
|
+
: ['exec', 'rdx', 'prepare']
|
|
147
|
+
await run(packageManager, prepareArgs, targetDir)
|
|
148
|
+
} catch (error) {
|
|
149
|
+
const runner = packageManager === 'npm' ? 'npm run' : packageManager
|
|
150
|
+
throw new Error(
|
|
151
|
+
`${error.message}\nProject files were kept in "${projectName}". Fix the reported error, then retry:\n cd ${projectName}\n ${packageManager} install\n ${runner} dev`
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log(`\nRDX project "${projectName}" created successfully.\n`)
|
|
157
|
+
console.log(` cd ${projectName}`)
|
|
158
|
+
console.log(
|
|
159
|
+
` ${packageManager === 'npm' ? 'npm run' : packageManager} dev\n`
|
|
160
|
+
)
|
|
126
161
|
}
|
|
127
162
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
163
|
+
try {
|
|
164
|
+
await main()
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error(`[RDX] ${error.message}`)
|
|
167
|
+
process.exitCode = 1
|
|
168
|
+
}
|
package/bin/options.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function validateProjectName(name) {
|
|
2
|
+
if (!name) return 'Please enter a project name.'
|
|
3
|
+
if (name.length > 214)
|
|
4
|
+
return 'Use a project name with at most 214 characters.'
|
|
5
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(name) || name.endsWith('.'))
|
|
6
|
+
return 'Start with a letter or number; use only letters, numbers, dots, dashes or underscores, and do not end with a dot.'
|
|
7
|
+
if (/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(name))
|
|
8
|
+
return 'Choose a project name that is not reserved by Windows.'
|
|
9
|
+
if (['node_modules', 'favicon.ico'].includes(name.toLowerCase()))
|
|
10
|
+
return 'Choose a project name that is not reserved by npm.'
|
|
11
|
+
return true
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function parseArguments(args) {
|
|
15
|
+
let projectName
|
|
16
|
+
let skipInstall = false
|
|
17
|
+
let help = false
|
|
18
|
+
let version = false
|
|
19
|
+
for (const argument of args) {
|
|
20
|
+
if (argument === '--skip-install') skipInstall = true
|
|
21
|
+
else if (argument === '--help' || argument === '-h') help = true
|
|
22
|
+
else if (argument === '--version' || argument === '-v') version = true
|
|
23
|
+
else if (argument.startsWith('-'))
|
|
24
|
+
throw new Error(`Unknown option "${argument}". Use --help for usage.`)
|
|
25
|
+
else if (projectName !== undefined)
|
|
26
|
+
throw new Error('Provide only one project name. Use --help for usage.')
|
|
27
|
+
else projectName = argument
|
|
28
|
+
}
|
|
29
|
+
return { projectName, skipInstall, help, version }
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexibase/create-rdx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Create a new RDX documentation project.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"README.md"
|
|
14
14
|
],
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": "
|
|
16
|
+
"node": "^22.18.0 || ^24.11.0"
|
|
17
17
|
},
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public"
|
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
This documentation site was created with RDX.
|
|
4
4
|
|
|
5
|
-
Requires Node.js
|
|
5
|
+
Requires Node.js 22.18+ (22.x) or 24.11+ (24.x). Use the latest patch of either line.
|
|
6
6
|
|
|
7
7
|
## Development
|
|
8
8
|
|
|
9
|
+
Use the same package manager that installed the project:
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
12
|
pnpm dev
|
|
13
|
+
# npm alternative: npm run dev
|
|
14
|
+
# Yarn alternative: yarn dev
|
|
11
15
|
```
|
|
12
16
|
|
|
13
17
|
Edit files in `docs/` to create your documentation. RDX creates and maintains
|
|
14
18
|
its internal runtime in `.rdx/`.
|
|
19
|
+
If installation failed during creation, keep these files, fix the reported error
|
|
20
|
+
and retry `pnpm install` (or `npm install` / `yarn install`) before starting.
|
|
15
21
|
|
|
16
22
|
## Optional versioning
|
|
17
23
|
|
|
@@ -39,9 +39,9 @@ Keep the server running while editing your documentation.
|
|
|
39
39
|
|
|
40
40
|
</AccordionContent>
|
|
41
41
|
</AccordionItem>
|
|
42
|
-
<AccordionItem value="
|
|
43
|
-
<AccordionTrigger>
|
|
44
|
-
<AccordionContent>
|
|
42
|
+
<AccordionItem value="disabled" disabled>
|
|
43
|
+
<AccordionTrigger>Disabled example</AccordionTrigger>
|
|
44
|
+
<AccordionContent>This item demonstrates the disabled state.</AccordionContent>
|
|
45
45
|
</AccordionItem>
|
|
46
46
|
</Accordion>
|
|
47
47
|
|
|
@@ -52,7 +52,7 @@ Each group works independently. Panels can contain normal Markdown and RDX compo
|
|
|
52
52
|
<TabsList aria-label="Environment">
|
|
53
53
|
<TabsTrigger value="development">Development</TabsTrigger>
|
|
54
54
|
<TabsTrigger value="production">Production</TabsTrigger>
|
|
55
|
-
<TabsTrigger value="preview" disabled>
|
|
55
|
+
<TabsTrigger value="preview" disabled>Disabled example</TabsTrigger>
|
|
56
56
|
</TabsList>
|
|
57
57
|
<TabsContent value="development">
|
|
58
58
|
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"start": "rdx start"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@lexibase/rdx-ui": "1.0.0
|
|
13
|
-
"@lexibase/rdx-next": "1.0.
|
|
12
|
+
"@lexibase/rdx-ui": "1.0.0",
|
|
13
|
+
"@lexibase/rdx-next": "1.0.1",
|
|
14
14
|
"next": "^16.4.2",
|
|
15
15
|
"react": "19.3.1",
|
|
16
16
|
"react-dom": "19.3.1"
|
|
@@ -21,6 +21,6 @@
|
|
|
21
21
|
"typescript": "6.0.3"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
|
-
"node": "
|
|
24
|
+
"node": "^22.18.0 || ^24.11.0"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
import { defineConfig } from '@lexibase/rdx-next'
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
|
-
title: 'My documentation',
|
|
5
4
|
description: 'Documentation built with RDX.',
|
|
5
|
+
// SEO and link previews. Paths starting with '/' refer to files in public/.
|
|
6
|
+
metadata: {
|
|
7
|
+
// The single site name: browser titles, social previews and default branding.
|
|
8
|
+
applicationName: 'My documentation',
|
|
9
|
+
// Set metadataBase to your public site URL to resolve relative share images.
|
|
10
|
+
// Optional examples below: uncomment only after adding the referenced files.
|
|
11
|
+
// icons: {
|
|
12
|
+
// icon: [
|
|
13
|
+
// { url: '/icon.svg', type: 'image/svg+xml' },
|
|
14
|
+
// { url: '/icon.png', sizes: '96x96', type: 'image/png' },
|
|
15
|
+
// ],
|
|
16
|
+
// shortcut: '/favicon.ico',
|
|
17
|
+
// },
|
|
18
|
+
// icon: browser tab icons with optional sizes and MIME types.
|
|
19
|
+
// shortcut: traditional favicon link for browser compatibility.
|
|
20
|
+
// manifest: '/site.webmanifest',
|
|
21
|
+
// The web app manifest describes its name, icons, etc.; RDX does not create it.
|
|
22
|
+
},
|
|
23
|
+
// Floating heading navigation; shown only on pages with enough sections.
|
|
6
24
|
TOC: false,
|
|
25
|
+
// Local documentation search in the navbar; no external search service needed.
|
|
7
26
|
search: false,
|
|
27
|
+
// Optional navbar text does not change metadata.applicationName.
|
|
8
28
|
navbar: {
|
|
9
|
-
title: '',
|
|
29
|
+
title: '', // Text beside the logo; empty or omitted shows only the logo.
|
|
30
|
+
// logo: Logo, // Import a React component that accepts className, not an image path.
|
|
10
31
|
actions: {
|
|
11
32
|
github: {
|
|
12
33
|
visible: true,
|
|
@@ -15,6 +36,8 @@ export default defineConfig({
|
|
|
15
36
|
showToggleMode: true,
|
|
16
37
|
},
|
|
17
38
|
},
|
|
39
|
+
// When disabled, '/' redirects to '/docs'.
|
|
40
|
+
// To use your own home.tsx, import its component and set homepage.component.
|
|
18
41
|
homepage: {
|
|
19
42
|
enabled: false,
|
|
20
43
|
},
|