@lexibase/create-rdx 4.1.0 → 4.2.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/README.md +6 -0
- package/bin/index.js +83 -61
- package/bin/installed-runtime.mjs +32 -0
- package/bin/progress.mjs +23 -0
- package/package.json +1 -1
- package/templates/default/README.md +2 -1
- package/templates/default/docs/init/intro.mdx +1 -1
- package/templates/default/package.json +1 -1
- package/templates/default/rdx.config.ts +2 -1
package/README.md
CHANGED
|
@@ -39,6 +39,12 @@ npm create @lexibase/rdx@latest my-docs -- --skip-install
|
|
|
39
39
|
`.rdx/`. Otherwise the creator uses the invoking package manager and prepares
|
|
40
40
|
the runtime. Follow the commands printed by the generator.
|
|
41
41
|
|
|
42
|
+
The creator reports file creation, dependency installation, and runtime preparation
|
|
43
|
+
as separate stages, with elapsed time and periodic activity messages during long
|
|
44
|
+
operations. Package-manager output and prompts stay visible. npm and pnpm projects
|
|
45
|
+
prepare using their installed RDX executable directly; Yarn provides its project
|
|
46
|
+
execution environment for Plug'n'Play compatibility.
|
|
47
|
+
|
|
42
48
|
## Recovery
|
|
43
49
|
|
|
44
50
|
In a pnpm workspace, installation uses the workspace's existing dependencies and
|
package/bin/index.js
CHANGED
|
@@ -9,6 +9,8 @@ import prompts from 'prompts'
|
|
|
9
9
|
|
|
10
10
|
import { parseArguments, validateProjectName } from './options.mjs'
|
|
11
11
|
import { normalizePnpmRdxApprovals } from './pnpm-policy.mjs'
|
|
12
|
+
import { installedRuntime } from './installed-runtime.mjs'
|
|
13
|
+
import { runStep } from './progress.mjs'
|
|
12
14
|
|
|
13
15
|
function getPackageManager() {
|
|
14
16
|
const userAgent = process.env.npm_config_user_agent || ''
|
|
@@ -19,7 +21,7 @@ function getPackageManager() {
|
|
|
19
21
|
return 'npm'
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
function run(command, args, cwd) {
|
|
24
|
+
function run(command, args, cwd, label = `${command} ${args.join(' ')}`) {
|
|
23
25
|
return new Promise((resolve, reject) => {
|
|
24
26
|
// Reuse the Node entry point when available. Otherwise cross-spawn
|
|
25
27
|
// resolves Windows command shims and escapes their arguments.
|
|
@@ -33,12 +35,13 @@ function run(command, args, cwd) {
|
|
|
33
35
|
const child = spawn(executable, commandArgs, {
|
|
34
36
|
cwd,
|
|
35
37
|
stdio: 'inherit',
|
|
38
|
+
windowsHide: true,
|
|
36
39
|
})
|
|
37
40
|
|
|
38
41
|
child.on('error', reject)
|
|
39
42
|
child.on('exit', (code) => {
|
|
40
43
|
if (code === 0) resolve()
|
|
41
|
-
else reject(new Error(`${
|
|
44
|
+
else reject(new Error(`${label} exited with ${code}`))
|
|
42
45
|
})
|
|
43
46
|
})
|
|
44
47
|
}
|
|
@@ -93,73 +96,92 @@ async function main() {
|
|
|
93
96
|
if (relativeTarget.startsWith('..') || path.isAbsolute(relativeTarget)) {
|
|
94
97
|
throw new Error('Project must be created inside the current directory.')
|
|
95
98
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
await runStep(
|
|
100
|
+
`[1/${skipInstall ? 1 : 3}] Creating project files...`,
|
|
101
|
+
async () => {
|
|
102
|
+
try {
|
|
103
|
+
await fs.mkdir(targetDir)
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (error.code === 'EEXIST')
|
|
106
|
+
throw new Error(
|
|
107
|
+
`The path "${projectName}" already exists. Choose another name; existing files are never overwritten.`
|
|
108
|
+
)
|
|
109
|
+
throw error
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const currentFile = fileURLToPath(import.meta.url)
|
|
113
|
+
const templateDir = path.resolve(
|
|
114
|
+
path.dirname(currentFile),
|
|
115
|
+
'../templates/default'
|
|
116
|
+
)
|
|
117
|
+
await fs.copy(templateDir, targetDir, {
|
|
118
|
+
errorOnExist: true,
|
|
119
|
+
overwrite: false,
|
|
120
|
+
})
|
|
121
|
+
await fs.ensureDir(path.join(targetDir, 'public'))
|
|
122
|
+
|
|
123
|
+
const configPath = path.join(targetDir, 'rdx.config.ts')
|
|
124
|
+
const config = await fs.readFile(configPath, 'utf8')
|
|
125
|
+
await fs.writeFile(
|
|
126
|
+
configPath,
|
|
127
|
+
config.replace(
|
|
128
|
+
'since: new Date().getFullYear(),',
|
|
129
|
+
`since: ${new Date().getFullYear()},`
|
|
130
|
+
)
|
|
102
131
|
)
|
|
103
|
-
throw error
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const currentFile = fileURLToPath(import.meta.url)
|
|
107
|
-
const templateDir = path.resolve(
|
|
108
|
-
path.dirname(currentFile),
|
|
109
|
-
'../templates/default'
|
|
110
|
-
)
|
|
111
|
-
await fs.copy(templateDir, targetDir, {
|
|
112
|
-
errorOnExist: true,
|
|
113
|
-
overwrite: false,
|
|
114
|
-
})
|
|
115
|
-
await fs.ensureDir(path.join(targetDir, 'public'))
|
|
116
|
-
|
|
117
|
-
const configPath = path.join(targetDir, 'rdx.config.ts')
|
|
118
|
-
const config = await fs.readFile(configPath, 'utf8')
|
|
119
|
-
await fs.writeFile(
|
|
120
|
-
configPath,
|
|
121
|
-
config.replace(
|
|
122
|
-
'since: new Date().getFullYear(),',
|
|
123
|
-
`since: ${new Date().getFullYear()},`
|
|
124
|
-
)
|
|
125
|
-
)
|
|
126
132
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
133
|
+
const gitignoreTemplatePath = path.join(targetDir, 'gitignore.template')
|
|
134
|
+
await fs.move(gitignoreTemplatePath, path.join(targetDir, '.gitignore'), {
|
|
135
|
+
overwrite: true,
|
|
136
|
+
})
|
|
137
|
+
await fs.remove(path.join(targetDir, 'gitignore'))
|
|
138
|
+
await fs.remove(path.join(targetDir, '.npmignore'))
|
|
139
|
+
|
|
140
|
+
const pkgPath = path.join(targetDir, 'package.json')
|
|
141
|
+
const pkg = await fs.readJson(pkgPath)
|
|
142
|
+
pkg.name = projectName.toLowerCase()
|
|
143
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 })
|
|
144
|
+
|
|
145
|
+
const readmePath = path.join(targetDir, 'README.md')
|
|
146
|
+
const readme = await fs.readFile(readmePath, 'utf8')
|
|
147
|
+
await fs.writeFile(
|
|
148
|
+
readmePath,
|
|
149
|
+
readme
|
|
150
|
+
.replaceAll('{{RDX_PROJECT_NAME}}', projectName)
|
|
151
|
+
.replaceAll('__RDX_PROJECT_NAME__', projectName)
|
|
152
|
+
)
|
|
153
|
+
}
|
|
146
154
|
)
|
|
147
155
|
|
|
148
156
|
const packageManager = getPackageManager()
|
|
149
157
|
|
|
150
158
|
if (!skipInstall) {
|
|
151
159
|
try {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
await
|
|
160
|
+
await runStep(
|
|
161
|
+
`[2/3] Installing dependencies with ${packageManager}...`,
|
|
162
|
+
async () => {
|
|
163
|
+
if (packageManager === 'pnpm')
|
|
164
|
+
await normalizePnpmRdxApprovals(targetDir)
|
|
165
|
+
await run(packageManager, ['install'], targetDir)
|
|
166
|
+
if (packageManager === 'pnpm')
|
|
167
|
+
await normalizePnpmRdxApprovals(targetDir)
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
await runStep('[3/3] Preparing RDX...', async () => {
|
|
171
|
+
if (packageManager === 'yarn') {
|
|
172
|
+
// Yarn provides the project's Plug'n'Play loader when needed.
|
|
173
|
+
await run(packageManager, ['exec', 'rdx', 'prepare'], targetDir)
|
|
174
|
+
} else {
|
|
175
|
+
// Avoid another package-manager startup and automatic install check.
|
|
176
|
+
const executable = await installedRuntime(targetDir)
|
|
177
|
+
await run(
|
|
178
|
+
process.execPath,
|
|
179
|
+
[executable, 'prepare'],
|
|
180
|
+
targetDir,
|
|
181
|
+
'rdx prepare'
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
})
|
|
163
185
|
} catch (error) {
|
|
164
186
|
const runner = packageManager === 'npm' ? 'npm run' : packageManager
|
|
165
187
|
throw new Error(
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
import { readFile, stat } from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
/** Resolve the framework installed in the new project, including hoisted workspaces. */
|
|
6
|
+
export async function installedRuntime(directory) {
|
|
7
|
+
const require = createRequire(path.join(directory, 'package.json'))
|
|
8
|
+
let filename
|
|
9
|
+
try {
|
|
10
|
+
filename = require.resolve('@lexibase/rdx/package.json')
|
|
11
|
+
} catch {
|
|
12
|
+
throw new Error(
|
|
13
|
+
'Could not find @lexibase/rdx in the new project after installation.'
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
const manifest = JSON.parse(await readFile(filename, 'utf8'))
|
|
17
|
+
const entry =
|
|
18
|
+
typeof manifest.bin === 'string' ? manifest.bin : manifest.bin?.rdx
|
|
19
|
+
if (typeof entry !== 'string' || !entry)
|
|
20
|
+
throw new Error(
|
|
21
|
+
'The installed @lexibase/rdx package does not provide its rdx executable.'
|
|
22
|
+
)
|
|
23
|
+
const executable = path.resolve(path.dirname(filename), entry)
|
|
24
|
+
try {
|
|
25
|
+
if (!(await stat(executable)).isFile()) throw new Error()
|
|
26
|
+
} catch {
|
|
27
|
+
throw new Error(
|
|
28
|
+
'The installed RDX executable is missing. Run the package manager install command again.'
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
return executable
|
|
32
|
+
}
|
package/bin/progress.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { performance } from 'node:perf_hooks'
|
|
2
|
+
|
|
3
|
+
/** Show real stage timings while preserving the installer's own terminal output. */
|
|
4
|
+
export async function runStep(
|
|
5
|
+
label,
|
|
6
|
+
operation,
|
|
7
|
+
{ log = console.log, intervalMs = 15_000 } = {}
|
|
8
|
+
) {
|
|
9
|
+
const started = performance.now()
|
|
10
|
+
const elapsed = () => ((performance.now() - started) / 1000).toFixed(1)
|
|
11
|
+
log(`\n${label}`)
|
|
12
|
+
const timer = setInterval(() => {
|
|
13
|
+
log(`[RDX] ${label} (${elapsed()}s elapsed)`)
|
|
14
|
+
}, intervalMs)
|
|
15
|
+
timer.unref()
|
|
16
|
+
try {
|
|
17
|
+
const result = await operation()
|
|
18
|
+
log(`[RDX] Completed in ${elapsed()}s.`)
|
|
19
|
+
return result
|
|
20
|
+
} finally {
|
|
21
|
+
clearInterval(timer)
|
|
22
|
+
}
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -51,7 +51,8 @@ public/images/rdx.svg → /images/rdx.svg
|
|
|
51
51
|
public/downloads/example.txt → /downloads/example.txt
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
Write pages as `.md` or `.mdx` inside `docs/`. Both formats support RDX's
|
|
55
|
+
Markdown components. Use site-root URLs for assets:
|
|
55
56
|
|
|
56
57
|
```md
|
|
57
58
|

|
|
@@ -6,5 +6,5 @@ link_position: 1
|
|
|
6
6
|
|
|
7
7
|
# Welcome to your documentation
|
|
8
8
|
|
|
9
|
-
RDX turns folders and `.mdx` files into a documentation site. Start by editing
|
|
9
|
+
RDX turns folders and `.md` or `.mdx` files into a documentation site. Start by editing
|
|
10
10
|
this page or adding new pages inside `docs/`.
|
|
@@ -32,7 +32,8 @@ export default defineConfig({
|
|
|
32
32
|
// Optional navbar text does not change metadata.applicationName.
|
|
33
33
|
navbar: {
|
|
34
34
|
title: '', // Text beside the logo; empty or omitted shows only the logo.
|
|
35
|
-
// logo:
|
|
35
|
+
// logo: '/images/logo.png', // File in public/images/; PNG, SVG and other image formats work.
|
|
36
|
+
// Or import your components/logo.tsx and set logo: Logo.
|
|
36
37
|
actions: {
|
|
37
38
|
github: {
|
|
38
39
|
visible: true,
|