@lexibase/create-rdx 1.1.0 → 1.2.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 +6 -0
- package/bin/index.js +15 -0
- package/bin/pnpm-policy.mjs +115 -0
- package/package.json +3 -2
- package/templates/default/package.json +1 -1
- package/templates/default/rdx.config.ts +3 -1
package/README.md
CHANGED
|
@@ -41,6 +41,12 @@ the runtime. Follow the commands printed by the generator.
|
|
|
41
41
|
|
|
42
42
|
## Recovery
|
|
43
43
|
|
|
44
|
+
In a pnpm workspace, installation uses the workspace's existing dependencies and
|
|
45
|
+
policy. Before installation and runtime preparation, the creator consolidates
|
|
46
|
+
duplicate exact-version approvals for RDX in `minimumReleaseAgeExclude`. Only
|
|
47
|
+
versions already listed are combined; the age threshold, strict mode, unrelated
|
|
48
|
+
package rules, comments and other workspace settings are preserved.
|
|
49
|
+
|
|
44
50
|
If installation or preparation fails, the command exits with an error and keeps
|
|
45
51
|
the generated files. Fix the reported issue, enter the created folder and retry
|
|
46
52
|
installation/development using the same package manager. Do not rerun creation
|
package/bin/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import fs from 'fs-extra'
|
|
|
8
8
|
import prompts from 'prompts'
|
|
9
9
|
|
|
10
10
|
import { parseArguments, validateProjectName } from './options.mjs'
|
|
11
|
+
import { normalizePnpmRdxApprovals } from './pnpm-policy.mjs'
|
|
11
12
|
|
|
12
13
|
function getPackageManager() {
|
|
13
14
|
const userAgent = process.env.npm_config_user_agent || ''
|
|
@@ -113,6 +114,16 @@ async function main() {
|
|
|
113
114
|
})
|
|
114
115
|
await fs.ensureDir(path.join(targetDir, 'public'))
|
|
115
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
|
+
|
|
116
127
|
const gitignoreTemplatePath = path.join(targetDir, 'gitignore.template')
|
|
117
128
|
await fs.move(gitignoreTemplatePath, path.join(targetDir, '.gitignore'), {
|
|
118
129
|
overwrite: true,
|
|
@@ -139,7 +150,11 @@ async function main() {
|
|
|
139
150
|
if (!skipInstall) {
|
|
140
151
|
try {
|
|
141
152
|
console.log(`\nInstalling dependencies with ${packageManager}...\n`)
|
|
153
|
+
if (packageManager === 'pnpm')
|
|
154
|
+
await normalizePnpmRdxApprovals(targetDir)
|
|
142
155
|
await run(packageManager, ['install'], targetDir)
|
|
156
|
+
if (packageManager === 'pnpm')
|
|
157
|
+
await normalizePnpmRdxApprovals(targetDir)
|
|
143
158
|
const prepareArgs =
|
|
144
159
|
packageManager === 'npm'
|
|
145
160
|
? ['exec', '--', 'rdx', 'prepare']
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import { lstat, readFile, rename, rm, writeFile } from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { isScalar, isSeq, parseDocument } from 'yaml'
|
|
6
|
+
|
|
7
|
+
const rdxPackages = new Set([
|
|
8
|
+
'@lexibase/rdx',
|
|
9
|
+
'@lexibase/rdx-core',
|
|
10
|
+
'@lexibase/rdx-next',
|
|
11
|
+
'@lexibase/rdx-types',
|
|
12
|
+
'@lexibase/rdx-ui',
|
|
13
|
+
'@lexibase/rdx-versioning',
|
|
14
|
+
'@lexibase/create-rdx',
|
|
15
|
+
])
|
|
16
|
+
const version =
|
|
17
|
+
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[\da-z.-]+)?(?:\+[\da-z.-]+)?$/i
|
|
18
|
+
|
|
19
|
+
async function workspaceFile(directory) {
|
|
20
|
+
let current = path.resolve(directory)
|
|
21
|
+
while (true) {
|
|
22
|
+
const filename = path.join(current, 'pnpm-workspace.yaml')
|
|
23
|
+
try {
|
|
24
|
+
const info = await lstat(filename)
|
|
25
|
+
if (!info.isFile() || info.isSymbolicLink()) return undefined
|
|
26
|
+
return filename
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (error.code !== 'ENOENT') throw error
|
|
29
|
+
}
|
|
30
|
+
const parent = path.dirname(current)
|
|
31
|
+
if (parent === current) return undefined
|
|
32
|
+
current = parent
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function exactRule(value) {
|
|
37
|
+
if (typeof value !== 'string') return undefined
|
|
38
|
+
const at = value.indexOf('@', 1)
|
|
39
|
+
if (at < 0 || !rdxPackages.has(value.slice(0, at))) return undefined
|
|
40
|
+
const versions = value
|
|
41
|
+
.slice(at + 1)
|
|
42
|
+
.split('||')
|
|
43
|
+
.map((item) => item.trim())
|
|
44
|
+
if (!versions.length || !versions.every((item) => version.test(item)))
|
|
45
|
+
return undefined
|
|
46
|
+
return { name: value.slice(0, at), versions }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Merge only exact RDX approvals already recorded by the user or pnpm. */
|
|
50
|
+
export async function normalizePnpmRdxApprovals(directory) {
|
|
51
|
+
const filename = await workspaceFile(directory)
|
|
52
|
+
if (!filename) return false
|
|
53
|
+
const original = await readFile(filename, 'utf8')
|
|
54
|
+
const document = parseDocument(original)
|
|
55
|
+
if (document.errors.length)
|
|
56
|
+
throw new Error(`Cannot read ${filename}: ${document.errors[0].message}`)
|
|
57
|
+
const approvals = document.get('minimumReleaseAgeExclude', true)
|
|
58
|
+
if (approvals === undefined) return false
|
|
59
|
+
// Leave aliases and non-literal policy definitions to pnpm itself.
|
|
60
|
+
if (
|
|
61
|
+
!isSeq(approvals) ||
|
|
62
|
+
approvals.items.some(
|
|
63
|
+
(item) => !isScalar(item) || typeof item.value !== 'string'
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
return false
|
|
67
|
+
|
|
68
|
+
const groups = new Map()
|
|
69
|
+
const removed = new Set()
|
|
70
|
+
for (const node of approvals.items) {
|
|
71
|
+
const rule = exactRule(node.value)
|
|
72
|
+
if (!rule) continue
|
|
73
|
+
const first = groups.get(rule.name)
|
|
74
|
+
if (!first) {
|
|
75
|
+
groups.set(rule.name, { node, versions: new Set(rule.versions) })
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
for (const value of rule.versions) first.versions.add(value)
|
|
79
|
+
first.node.value = `${rule.name}@${[...first.versions].join(' || ')}`
|
|
80
|
+
// Retain comments attached to approvals that are folded into the first rule.
|
|
81
|
+
if (node.commentBefore)
|
|
82
|
+
first.node.commentBefore = [first.node.commentBefore, node.commentBefore]
|
|
83
|
+
.filter(Boolean)
|
|
84
|
+
.join('\n')
|
|
85
|
+
if (node.comment)
|
|
86
|
+
first.node.comment = [first.node.comment, node.comment]
|
|
87
|
+
.filter(Boolean)
|
|
88
|
+
.join('\n')
|
|
89
|
+
removed.add(node)
|
|
90
|
+
}
|
|
91
|
+
if (!removed.size) return false
|
|
92
|
+
approvals.items = approvals.items.filter((node) => !removed.has(node))
|
|
93
|
+
let updated = document.toString({ lineWidth: 0 })
|
|
94
|
+
if (original.includes('\r\n')) updated = updated.replaceAll('\n', '\r\n')
|
|
95
|
+
const temporary = path.join(
|
|
96
|
+
path.dirname(filename),
|
|
97
|
+
`.rdx-policy-${randomUUID()}.tmp`
|
|
98
|
+
)
|
|
99
|
+
try {
|
|
100
|
+
const info = await lstat(filename)
|
|
101
|
+
await writeFile(temporary, updated, { flag: 'wx', mode: info.mode })
|
|
102
|
+
if (
|
|
103
|
+
info.isSymbolicLink() ||
|
|
104
|
+
(await readFile(filename, 'utf8')) !== original
|
|
105
|
+
)
|
|
106
|
+
throw new Error(
|
|
107
|
+
`The pnpm policy changed during project creation: ${filename}. Retry without concurrent installs.`
|
|
108
|
+
)
|
|
109
|
+
await rename(temporary, filename)
|
|
110
|
+
} finally {
|
|
111
|
+
await rm(temporary, { force: true })
|
|
112
|
+
}
|
|
113
|
+
console.log(`Consolidated existing RDX version approvals in ${filename}.`)
|
|
114
|
+
return true
|
|
115
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexibase/create-rdx",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Create a new RDX documentation project.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"cross-spawn": "^7.0.6",
|
|
32
32
|
"fs-extra": "^11.1.1",
|
|
33
|
-
"prompts": "^2.4.2"
|
|
33
|
+
"prompts": "^2.4.2",
|
|
34
|
+
"yaml": "^2.9.1"
|
|
34
35
|
},
|
|
35
36
|
"scripts": {
|
|
36
37
|
"test": "node --test tests/*.test.mjs"
|
|
@@ -2,10 +2,12 @@ import { defineConfig } from '@lexibase/rdx'
|
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
4
|
description: 'Documentation built with RDX.',
|
|
5
|
-
// SEO and link previews.
|
|
5
|
+
// Site identity, SEO and link previews. '/' paths refer to files in public/.
|
|
6
6
|
metadata: {
|
|
7
7
|
// The single site name: browser titles, social previews and default branding.
|
|
8
8
|
applicationName: 'My documentation',
|
|
9
|
+
// Footer starting year. Change it to an earlier founding year if needed.
|
|
10
|
+
since: new Date().getFullYear(),
|
|
9
11
|
// Set metadataBase to your public site URL to resolve relative share images.
|
|
10
12
|
// Optional examples below: uncomment only after adding the referenced files.
|
|
11
13
|
// icons: {
|