@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 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
- const projectNamePattern = /^[a-z0-9][a-z0-9._-]*$/i
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
- const response = nameFromCli
63
- ? { projectName: nameFromCli }
64
- : await prompts({
65
- type: 'text',
66
- name: 'projectName',
67
- message: 'What is your project named?',
68
- validate: validateProjectName,
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 { projectName } = response
72
- if (!projectName) {
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
- const targetDir = path.resolve(process.cwd(), projectName)
78
- const relativeTarget = path.relative(process.cwd(), targetDir)
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
- if (relativeTarget.startsWith('..') || path.isAbsolute(relativeTarget)) {
81
- throw new Error('Project must be created inside the current directory.')
82
- }
83
- if (await fs.pathExists(targetDir)) {
84
- throw new Error(`The directory "${projectName}" already exists.`)
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 currentFile = fileURLToPath(import.meta.url)
88
- const templateDir = path.resolve(
89
- path.dirname(currentFile),
90
- '../templates/default'
91
- )
92
- await fs.copy(templateDir, targetDir, { errorOnExist: true })
93
- await fs.ensureDir(path.join(targetDir, 'public'))
94
-
95
- const gitignoreTemplatePath = path.join(targetDir, 'gitignore.template')
96
- await fs.move(gitignoreTemplatePath, path.join(targetDir, '.gitignore'), {
97
- overwrite: true,
98
- })
99
- await fs.remove(path.join(targetDir, 'gitignore'))
100
- await fs.remove(path.join(targetDir, '.npmignore'))
101
-
102
- const pkgPath = path.join(targetDir, 'package.json')
103
- const pkg = await fs.readJson(pkgPath)
104
- pkg.name = projectName
105
- await fs.writeJson(pkgPath, pkg, { spaces: 2 })
106
-
107
- const readmePath = path.join(targetDir, 'README.md')
108
- const readme = await fs.readFile(readmePath, 'utf8')
109
- await fs.writeFile(
110
- readmePath,
111
- readme
112
- .replaceAll('{{RDX_PROJECT_NAME}}', projectName)
113
- .replaceAll('__RDX_PROJECT_NAME__', projectName)
114
- )
115
-
116
- const packageManager = getPackageManager()
117
-
118
- if (!skipInstall) {
119
- console.log(`\nInstalling dependencies with ${packageManager}...\n`)
120
- await run(packageManager, ['install'], targetDir)
121
- const prepareArgs =
122
- packageManager === 'npm'
123
- ? ['exec', '--', 'rdx', 'prepare']
124
- : ['exec', 'rdx', 'prepare']
125
- await run(packageManager, prepareArgs, targetDir)
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
- console.log(`\nRDX project "${projectName}" created successfully.\n`)
129
- console.log(` cd ${projectName}`)
130
- console.log(` ${packageManager === 'npm' ? 'npm run' : packageManager} dev\n`)
163
+ try {
164
+ await main()
165
+ } catch (error) {
166
+ console.error(`[RDX] ${error.message}`)
167
+ process.exitCode = 1
168
+ }
@@ -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.0-beta.9",
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": ">=20.9"
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 20.9 or newer. Use a currently supported Node.js LTS release.
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="soon" disabled>
43
- <AccordionTrigger>More examples (soon)</AccordionTrigger>
44
- <AccordionContent>Not available yet.</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>Preview (soon)</TabsTrigger>
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-beta.2",
13
- "@lexibase/rdx-next": "1.0.0-beta.10",
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": ">=20.9"
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
  },