@lexibase/rdx-next 4.0.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 +9 -0
- package/bin/add-plugin.mjs +111 -35
- package/bin/cli.mjs +35 -8
- package/bin/i18n-setup.mjs +115 -0
- package/bin/locale-routes.mjs +138 -0
- package/bin/plugin-config.mjs +47 -13
- package/config.mjs +28 -7
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +203 -36
- package/package.json +7 -6
- package/templates/runtime/app/globals.css +1 -0
package/README.md
CHANGED
|
@@ -19,6 +19,8 @@ internal `.rdx` application and run Next.js.
|
|
|
19
19
|
Run `pnpm rdx check` to validate static documentation links, heading fragments
|
|
20
20
|
and local files in public/ before deployment. It reports source locations and
|
|
21
21
|
exits nonzero for problems, without preparing the runtime or rendering documents.
|
|
22
|
+
`rdx build` runs the same check automatically before runtime preparation and
|
|
23
|
+
Next.js compilation, and stops if problems are found.
|
|
22
24
|
|
|
23
25
|
Run `pnpm rdx add versioning` (or `npm exec -- rdx add versioning`) from a
|
|
24
26
|
documentation project to install and activate the official optional plugin.
|
|
@@ -29,6 +31,13 @@ Use `--package-manager npm|pnpm|yarn` to resolve ambiguous lockfiles. Dynamic
|
|
|
29
31
|
configurations receive manual instructions and are not automatically edited.
|
|
30
32
|
Installing a package with npm/pnpm/yarn alone never edits `rdx.config.ts`.
|
|
31
33
|
|
|
34
|
+
Run `pnpm rdx add i18n` to activate multilingual documentation. It reuses the
|
|
35
|
+
primary `lang`, asks for additional language tags and creates translation
|
|
36
|
+
directories with `.gitkeep` files for empty trees. `--locales en,es-ES` supplies
|
|
37
|
+
additional languages noninteractively. Existing configurations and authored
|
|
38
|
+
translations are preserved; add later languages directly to `locales` and
|
|
39
|
+
`locale/<folder>/docs/`. The main project creator asks only for a project name.
|
|
40
|
+
|
|
32
41
|
First plugin installation follows the installed runtime: stable releases use
|
|
33
42
|
`latest`, betas use `beta`, and release candidates use `rc`. Unknown prerelease
|
|
34
43
|
channels require manual installation; missing tags do not fall back to another
|
package/bin/add-plugin.mjs
CHANGED
|
@@ -8,7 +8,18 @@ import { createRdxProject, resolveConfig } from '@lexibase/rdx-core/config'
|
|
|
8
8
|
import spawn from 'cross-spawn'
|
|
9
9
|
import { createJiti } from 'jiti'
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
activateVersioning,
|
|
13
|
+
versioningPackage,
|
|
14
|
+
activateI18n,
|
|
15
|
+
inspectI18n,
|
|
16
|
+
i18nPackage,
|
|
17
|
+
} from './plugin-config.mjs'
|
|
18
|
+
import {
|
|
19
|
+
askI18nLanguages,
|
|
20
|
+
initialLocales,
|
|
21
|
+
prepareLanguageFolders,
|
|
22
|
+
} from './i18n-setup.mjs'
|
|
12
23
|
|
|
13
24
|
const managers = new Set(['npm', 'pnpm', 'yarn'])
|
|
14
25
|
const runtimeVersion = createRequire(import.meta.url)('../package.json').version
|
|
@@ -16,10 +27,18 @@ const runtimeVersion = createRequire(import.meta.url)('../package.json').version
|
|
|
16
27
|
// Internal installer policy; channels belong to the installed runtime release,
|
|
17
28
|
// not the user's docs version, invoking command or dependency range.
|
|
18
29
|
export function versioningInstallRequest(version, declared) {
|
|
30
|
+
return pluginInstallRequest(version, declared, versioningPackage)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function i18nInstallRequest(version, declared) {
|
|
34
|
+
return pluginInstallRequest(version, declared, i18nPackage)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function pluginInstallRequest(version, declared, packageName) {
|
|
19
38
|
if (declared !== undefined) {
|
|
20
39
|
if (typeof declared !== 'string' || !declared.trim())
|
|
21
40
|
throw new Error(
|
|
22
|
-
|
|
41
|
+
`The declared ${packageName} dependency must be a non-empty string.`
|
|
23
42
|
)
|
|
24
43
|
return { kind: 'restore' }
|
|
25
44
|
}
|
|
@@ -46,26 +65,36 @@ export function versioningInstallRequest(version, declared) {
|
|
|
46
65
|
)
|
|
47
66
|
return {
|
|
48
67
|
kind: 'add',
|
|
49
|
-
specifier: `${
|
|
68
|
+
specifier: `${packageName}@${prerelease ?? 'latest'}`,
|
|
50
69
|
}
|
|
51
70
|
}
|
|
52
71
|
|
|
53
72
|
export function parseAddArguments(args) {
|
|
54
73
|
const [plugin, ...rest] = args
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
const usage =
|
|
75
|
+
'Usage: rdx add versioning|i18n [--package-manager npm|pnpm|yarn]. i18n also accepts --locales en,es-ES.'
|
|
76
|
+
if (!['versioning', 'i18n'].includes(plugin)) throw new Error(usage)
|
|
77
|
+
const options = {}
|
|
78
|
+
for (let index = 0; index < rest.length; index += 2) {
|
|
79
|
+
const flag = rest[index]
|
|
80
|
+
const value = rest[index + 1]
|
|
81
|
+
if (
|
|
82
|
+
flag === '--package-manager' &&
|
|
83
|
+
managers.has(value) &&
|
|
84
|
+
!options.packageManager
|
|
58
85
|
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
86
|
+
options.packageManager = value
|
|
87
|
+
else if (
|
|
88
|
+
plugin === 'i18n' &&
|
|
89
|
+
flag === '--locales' &&
|
|
90
|
+
value?.trim() &&
|
|
91
|
+
!value.startsWith('-') &&
|
|
92
|
+
options.locales === undefined
|
|
93
|
+
)
|
|
94
|
+
options.locales = value
|
|
95
|
+
else throw new Error(usage)
|
|
96
|
+
}
|
|
97
|
+
return options
|
|
69
98
|
}
|
|
70
99
|
|
|
71
100
|
async function exists(filename) {
|
|
@@ -160,7 +189,7 @@ export function installPackage(
|
|
|
160
189
|
})
|
|
161
190
|
}
|
|
162
191
|
|
|
163
|
-
async function validateCandidate(filename) {
|
|
192
|
+
async function validateCandidate(filename, packageName) {
|
|
164
193
|
const jiti = createJiti(import.meta.url, {
|
|
165
194
|
moduleCache: false,
|
|
166
195
|
fsCache: false,
|
|
@@ -168,27 +197,62 @@ async function validateCandidate(filename) {
|
|
|
168
197
|
})
|
|
169
198
|
const input = await jiti.import(filename, { default: true })
|
|
170
199
|
const config = resolveConfig(input)
|
|
171
|
-
//
|
|
172
|
-
await createRdxProject(
|
|
200
|
+
// Read the official language declaration; other setup hooks run during prepare.
|
|
201
|
+
const project = await createRdxProject(
|
|
173
202
|
{
|
|
174
203
|
...config,
|
|
175
204
|
plugins: config.plugins.map((plugin) => ({
|
|
176
205
|
...plugin,
|
|
177
|
-
setup:
|
|
206
|
+
setup:
|
|
207
|
+
packageName === i18nPackage && plugin.name === i18nPackage
|
|
208
|
+
? plugin.setup
|
|
209
|
+
: undefined,
|
|
178
210
|
})),
|
|
179
211
|
},
|
|
180
|
-
{ rootDir: path.dirname(filename), command: '
|
|
212
|
+
{ rootDir: path.dirname(filename), command: 'runtime' }
|
|
181
213
|
)
|
|
182
214
|
if (
|
|
183
|
-
config.plugins.filter((plugin) => plugin.name ===
|
|
184
|
-
.length !== 1
|
|
215
|
+
config.plugins.filter((plugin) => plugin.name === packageName).length !== 1
|
|
185
216
|
)
|
|
186
217
|
throw new Error(
|
|
187
|
-
|
|
218
|
+
`Expected exactly one ${packageName} plugin in the resulting configuration.`
|
|
188
219
|
)
|
|
220
|
+
return project
|
|
189
221
|
}
|
|
190
222
|
|
|
191
223
|
export async function addVersioning(rootDir, options = {}) {
|
|
224
|
+
return addPlugin(rootDir, options, {
|
|
225
|
+
packageName: versioningPackage,
|
|
226
|
+
label: 'Versioning',
|
|
227
|
+
activate: activateVersioning,
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export async function addI18n(rootDir, options = {}) {
|
|
232
|
+
return addPlugin(rootDir, options, {
|
|
233
|
+
packageName: i18nPackage,
|
|
234
|
+
label: 'i18n',
|
|
235
|
+
async activate(source) {
|
|
236
|
+
const state = inspectI18n(source)
|
|
237
|
+
if (state.configured) {
|
|
238
|
+
if (options.locales !== undefined)
|
|
239
|
+
throw new Error(
|
|
240
|
+
'i18n is already configured. Add further languages to locales in rdx.config.ts and create their locale/<folder>/docs/ directories.'
|
|
241
|
+
)
|
|
242
|
+
return source
|
|
243
|
+
}
|
|
244
|
+
const primary = Intl.getCanonicalLocales(state.lang)[0]
|
|
245
|
+
if (!primary) throw new Error('lang must be a valid language tag.')
|
|
246
|
+
const additional =
|
|
247
|
+
options.locales ?? (await (options.ask ?? askI18nLanguages)(primary))
|
|
248
|
+
if (additional === undefined) return
|
|
249
|
+
return activateI18n(source, initialLocales(primary, additional))
|
|
250
|
+
},
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function addPlugin(rootDir, options, definition) {
|
|
255
|
+
const { packageName, label } = definition
|
|
192
256
|
const {
|
|
193
257
|
install = installPackage,
|
|
194
258
|
log = console.log,
|
|
@@ -209,7 +273,11 @@ export async function addVersioning(rootDir, options = {}) {
|
|
|
209
273
|
throw new Error('rdx.config.ts must be a regular project file, not a link.')
|
|
210
274
|
const original = await readFile(filename, 'utf8')
|
|
211
275
|
// Refuse unsupported configurations before running the package manager.
|
|
212
|
-
const updated =
|
|
276
|
+
const updated = await definition.activate(original)
|
|
277
|
+
if (updated === undefined) {
|
|
278
|
+
log(`${label} setup cancelled.`)
|
|
279
|
+
return { changed: false, cancelled: true }
|
|
280
|
+
}
|
|
213
281
|
const pkg = JSON.parse(
|
|
214
282
|
await readFile(path.join(rootDir, 'package.json'), 'utf8')
|
|
215
283
|
)
|
|
@@ -220,11 +288,10 @@ export async function addVersioning(rootDir, options = {}) {
|
|
|
220
288
|
options.packageManager
|
|
221
289
|
)
|
|
222
290
|
const declared =
|
|
223
|
-
pkg.dependencies?.[
|
|
224
|
-
pkg.devDependencies?.[versioningPackage]
|
|
291
|
+
pkg.dependencies?.[packageName] ?? pkg.devDependencies?.[packageName]
|
|
225
292
|
let installed = false
|
|
226
293
|
try {
|
|
227
|
-
createRequire(path.join(rootDir, 'package.json')).resolve(
|
|
294
|
+
createRequire(path.join(rootDir, 'package.json')).resolve(packageName)
|
|
228
295
|
installed = true
|
|
229
296
|
} catch (error) {
|
|
230
297
|
// The official package exposes ESM imports only. require.resolve can find
|
|
@@ -234,21 +301,27 @@ export async function addVersioning(rootDir, options = {}) {
|
|
|
234
301
|
throw error
|
|
235
302
|
}
|
|
236
303
|
if (!declared || !installed) {
|
|
237
|
-
const request =
|
|
304
|
+
const request = pluginInstallRequest(runtimeVersion, declared, packageName)
|
|
238
305
|
log(
|
|
239
306
|
request.kind === 'restore'
|
|
240
|
-
? `Restoring the declared ${
|
|
307
|
+
? `Restoring the declared ${packageName} dependency with ${manager}...`
|
|
241
308
|
: `Installing ${request.specifier} with ${manager}...`
|
|
242
309
|
)
|
|
243
310
|
await install(manager, rootDir, env, request)
|
|
244
|
-
} else
|
|
245
|
-
log(`${versioningPackage} is already installed; preserving its version.`)
|
|
311
|
+
} else log(`${packageName} is already installed; preserving its version.`)
|
|
246
312
|
|
|
247
313
|
const temporary = path.join(rootDir, `rdx.config.add-${randomUUID()}.ts`)
|
|
314
|
+
let rollbackFolders
|
|
315
|
+
let committed = false
|
|
248
316
|
try {
|
|
249
317
|
await writeFile(temporary, updated, { flag: 'wx', mode: info.mode })
|
|
250
318
|
try {
|
|
251
|
-
await validateCandidate(temporary)
|
|
319
|
+
const project = await validateCandidate(temporary, packageName)
|
|
320
|
+
if (project.localization)
|
|
321
|
+
rollbackFolders = await prepareLanguageFolders(
|
|
322
|
+
rootDir,
|
|
323
|
+
project.localization
|
|
324
|
+
)
|
|
252
325
|
} catch (error) {
|
|
253
326
|
throw new Error(
|
|
254
327
|
`Plugin configuration validation failed: ${error.message}. rdx.config.ts was not changed. Installed dependencies were kept; fix the error and retry.`
|
|
@@ -265,10 +338,13 @@ export async function addVersioning(rootDir, options = {}) {
|
|
|
265
338
|
)
|
|
266
339
|
if (updated !== original) {
|
|
267
340
|
await rename(temporary, filename)
|
|
268
|
-
|
|
341
|
+
committed = true
|
|
342
|
+
log(`${label} activated in rdx.config.ts.`)
|
|
269
343
|
} else
|
|
270
|
-
log(
|
|
344
|
+
log(`${label} is already configured; no configuration changes needed.`)
|
|
345
|
+
committed = true
|
|
271
346
|
} finally {
|
|
347
|
+
if (!committed) await rollbackFolders?.()
|
|
272
348
|
await unlink(temporary).catch((error) => {
|
|
273
349
|
if (error.code !== 'ENOENT') throw error
|
|
274
350
|
})
|
package/bin/cli.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import { createJiti } from 'jiti'
|
|
|
11
11
|
import postcssConfig from '../postcss.config.mjs'
|
|
12
12
|
import { preparePublicAssets } from './public-assets.mjs'
|
|
13
13
|
import { prepareProjectStyles } from './project-styles.mjs'
|
|
14
|
+
import { prepareLocaleRoutes } from './locale-routes.mjs'
|
|
14
15
|
|
|
15
16
|
export async function runRdxCli({ templateDir } = {}) {
|
|
16
17
|
const supportedCommands = new Set(['dev', 'build', 'start'])
|
|
@@ -25,7 +26,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
25
26
|
templateDir ?? path.join(packageRoot, 'templates', 'runtime')
|
|
26
27
|
const runtimeDirectory = path.join(projectRoot, '.rdx')
|
|
27
28
|
|
|
28
|
-
async function prepareRuntime() {
|
|
29
|
+
async function prepareRuntime(project) {
|
|
29
30
|
await mkdir(runtimeDirectory, { recursive: true })
|
|
30
31
|
await preparePublicAssets(projectRoot, runtimeDirectory)
|
|
31
32
|
await cp(runtimeTemplate, runtimeDirectory, {
|
|
@@ -33,6 +34,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
33
34
|
recursive: true,
|
|
34
35
|
})
|
|
35
36
|
await prepareProjectStyles(projectRoot, runtimeDirectory)
|
|
37
|
+
await prepareLocaleRoutes(project, runtimeDirectory, runtimeTemplate)
|
|
36
38
|
// Resolve in Node before Next processes this file: UI may be transitive,
|
|
37
39
|
// and native Tailwind plugins must stay outside the Turbopack module graph.
|
|
38
40
|
const resolvePlugin = createRequire(import.meta.url)
|
|
@@ -57,6 +59,9 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
57
59
|
' rdx check: validate documentation links, sections and local assets'
|
|
58
60
|
)
|
|
59
61
|
console.log(' rdx add versioning [--package-manager npm|pnpm|yarn]')
|
|
62
|
+
console.log(
|
|
63
|
+
' rdx add i18n [--locales en,es-ES] [--package-manager npm|pnpm|yarn]'
|
|
64
|
+
)
|
|
60
65
|
console.log(
|
|
61
66
|
'Plugin commands are registered through plugins in rdx.config.ts.'
|
|
62
67
|
)
|
|
@@ -69,7 +74,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
69
74
|
['--help', '-h'].includes(commandArgs[0])
|
|
70
75
|
) {
|
|
71
76
|
console.log(
|
|
72
|
-
'Usage: rdx check\nValidate static MDX links, section anchors and local public/ files without building the site.'
|
|
77
|
+
'Usage: rdx check\nValidate static Markdown and MDX links, section anchors and local public/ files without building the site.'
|
|
73
78
|
)
|
|
74
79
|
return
|
|
75
80
|
}
|
|
@@ -77,10 +82,31 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
if (command === 'add') {
|
|
80
|
-
|
|
85
|
+
if (
|
|
86
|
+
(commandArgs.length === 1 &&
|
|
87
|
+
['--help', '-h'].includes(commandArgs[0])) ||
|
|
88
|
+
(commandArgs.length === 2 &&
|
|
89
|
+
['versioning', 'i18n'].includes(commandArgs[0]) &&
|
|
90
|
+
['--help', '-h'].includes(commandArgs[1]))
|
|
91
|
+
) {
|
|
92
|
+
console.log(
|
|
93
|
+
'Usage: rdx add versioning|i18n [--package-manager npm|pnpm|yarn]'
|
|
94
|
+
)
|
|
95
|
+
console.log(
|
|
96
|
+
' i18n: reuse lang and ask for additional languages, or pass --locales en,es-ES.'
|
|
97
|
+
)
|
|
98
|
+
console.log(
|
|
99
|
+
' Existing i18n languages are edited in rdx.config.ts and locale/<folder>/docs/.'
|
|
100
|
+
)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
const { addVersioning, addI18n, parseAddArguments } =
|
|
81
104
|
await import('./add-plugin.mjs')
|
|
82
105
|
const options = parseAddArguments(commandArgs)
|
|
83
|
-
await
|
|
106
|
+
const result = await (
|
|
107
|
+
commandArgs[0] === 'i18n' ? addI18n : addVersioning
|
|
108
|
+
)(projectRoot, options)
|
|
109
|
+
if (result.cancelled) return
|
|
84
110
|
command = 'prepare'
|
|
85
111
|
}
|
|
86
112
|
|
|
@@ -114,7 +140,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
114
140
|
rootDir: projectRoot,
|
|
115
141
|
command,
|
|
116
142
|
})
|
|
117
|
-
if (command === 'check') {
|
|
143
|
+
if (command === 'check' || command === 'build') {
|
|
118
144
|
const { checkDocumentation, formatDocumentationCheck } =
|
|
119
145
|
await import('@lexibase/rdx-core/check')
|
|
120
146
|
const report = checkDocumentation(project)
|
|
@@ -122,11 +148,12 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
122
148
|
if (report.diagnostics.length) {
|
|
123
149
|
console.error(output)
|
|
124
150
|
process.exitCode = 1
|
|
151
|
+
return
|
|
125
152
|
} else console.log(output)
|
|
126
|
-
return
|
|
153
|
+
if (command === 'check') return
|
|
127
154
|
}
|
|
128
155
|
if (command === 'prepare') {
|
|
129
|
-
await prepareRuntime()
|
|
156
|
+
await prepareRuntime(project)
|
|
130
157
|
console.log('RDX runtime prepared in .rdx/')
|
|
131
158
|
return
|
|
132
159
|
}
|
|
@@ -147,7 +174,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
147
174
|
return
|
|
148
175
|
}
|
|
149
176
|
|
|
150
|
-
await prepareRuntime()
|
|
177
|
+
await prepareRuntime(project)
|
|
151
178
|
const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
|
|
152
179
|
const nextCli = projectRequire.resolve('next/dist/bin/next')
|
|
153
180
|
const child = spawn(
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lstat,
|
|
3
|
+
mkdir,
|
|
4
|
+
realpath,
|
|
5
|
+
rmdir,
|
|
6
|
+
writeFile,
|
|
7
|
+
readFile,
|
|
8
|
+
unlink,
|
|
9
|
+
} from 'node:fs/promises'
|
|
10
|
+
import path from 'node:path'
|
|
11
|
+
import process from 'node:process'
|
|
12
|
+
|
|
13
|
+
import { normalizeLocalization } from '@lexibase/rdx-core/config'
|
|
14
|
+
|
|
15
|
+
function languageLabel(code) {
|
|
16
|
+
try {
|
|
17
|
+
const label = new Intl.DisplayNames([code], { type: 'language' }).of(code)
|
|
18
|
+
return label[0].toLocaleUpperCase(code) + label.slice(1)
|
|
19
|
+
} catch {
|
|
20
|
+
// Valid tags with extensions need not have a display name in ICU.
|
|
21
|
+
return code
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Additional language tags; the existing lang always remains primary. */
|
|
26
|
+
export function initialLocales(primary, additional) {
|
|
27
|
+
const lang = Intl.getCanonicalLocales(primary)[0]
|
|
28
|
+
if (!lang) throw new Error('lang must be a valid language tag.')
|
|
29
|
+
if (typeof additional !== 'string' || !additional.trim())
|
|
30
|
+
throw new Error('Enter at least one additional language, e.g. en, es-ES.')
|
|
31
|
+
const codes = additional.split(',').map((value) => {
|
|
32
|
+
const code = Intl.getCanonicalLocales(value.trim())[0]
|
|
33
|
+
if (!code) throw new Error('Enter language tags separated by commas.')
|
|
34
|
+
return code
|
|
35
|
+
})
|
|
36
|
+
const locales = [lang, ...codes.filter((code) => code !== lang)].map(
|
|
37
|
+
(code) => ({
|
|
38
|
+
code,
|
|
39
|
+
label: languageLabel(code),
|
|
40
|
+
})
|
|
41
|
+
)
|
|
42
|
+
// Use the same validation as manual configuration, including duplicates.
|
|
43
|
+
normalizeLocalization({ locales }, lang)
|
|
44
|
+
return locales
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function askI18nLanguages(primary) {
|
|
48
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
49
|
+
throw new Error(
|
|
50
|
+
'Interactive language setup needs a terminal. Use rdx add i18n --locales en,es-ES (additional languages; lang stays primary).'
|
|
51
|
+
)
|
|
52
|
+
const { default: prompts } = await import('prompts')
|
|
53
|
+
const response = await prompts({
|
|
54
|
+
type: 'text',
|
|
55
|
+
name: 'languages',
|
|
56
|
+
message: `Additional languages (primary: ${primary}; e.g. en, es-ES)`,
|
|
57
|
+
validate(value) {
|
|
58
|
+
try {
|
|
59
|
+
initialLocales(primary, value)
|
|
60
|
+
return true
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return error.message
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
return response.languages
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Create only empty translation directories; never copy or replace documents. */
|
|
70
|
+
export async function prepareLanguageFolders(rootDir, localization) {
|
|
71
|
+
const root = await realpath(rootDir)
|
|
72
|
+
const created = []
|
|
73
|
+
const markers = []
|
|
74
|
+
async function rollback() {
|
|
75
|
+
for (const marker of markers)
|
|
76
|
+
if ((await readFile(marker, 'utf8').catch(() => undefined)) === '')
|
|
77
|
+
await unlink(marker).catch((error) => {
|
|
78
|
+
if (error.code !== 'ENOENT') throw error
|
|
79
|
+
})
|
|
80
|
+
for (const directory of [...created].reverse())
|
|
81
|
+
await rmdir(directory).catch((error) => {
|
|
82
|
+
// A user may have started writing while installation was running.
|
|
83
|
+
if (!['ENOENT', 'ENOTEMPTY', 'EEXIST'].includes(error.code)) throw error
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
for (const locale of localization.locales) {
|
|
88
|
+
if (!locale.folder) continue
|
|
89
|
+
let directory = root
|
|
90
|
+
for (const part of ['locale', locale.folder, 'docs']) {
|
|
91
|
+
directory = path.join(directory, part)
|
|
92
|
+
try {
|
|
93
|
+
await mkdir(directory)
|
|
94
|
+
created.push(directory)
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error.code !== 'EEXIST') throw error
|
|
97
|
+
}
|
|
98
|
+
const info = await lstat(directory)
|
|
99
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Translation folders must be regular project directories: ${directory}`
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
if (created.includes(directory)) {
|
|
105
|
+
const marker = path.join(directory, '.gitkeep')
|
|
106
|
+
await writeFile(marker, '', { flag: 'wx' })
|
|
107
|
+
markers.push(marker)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
await rollback()
|
|
112
|
+
throw error
|
|
113
|
+
}
|
|
114
|
+
return rollback
|
|
115
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { lstat, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
const defaultFiles = [
|
|
5
|
+
'layout.tsx',
|
|
6
|
+
'page.tsx',
|
|
7
|
+
'not-found.tsx',
|
|
8
|
+
'docs/[[...slug]]/page.tsx',
|
|
9
|
+
]
|
|
10
|
+
const generated = [
|
|
11
|
+
...defaultFiles.map((file) => `app/(rdx-default)/${file}`),
|
|
12
|
+
'app/(rdx-default)/[...notFound]/page.tsx',
|
|
13
|
+
'app/(rdx-locales)/[locale]/layout.tsx',
|
|
14
|
+
'app/(rdx-locales)/[locale]/not-found.tsx',
|
|
15
|
+
'app/(rdx-locales)/[locale]/docs/[[...slug]]/page.tsx',
|
|
16
|
+
'app/(rdx-locales)/[locale]/rdx-search/[source]/route.ts',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
/** Root layouts keep HTML language correct on the server, without middleware. */
|
|
20
|
+
export async function prepareLocaleRoutes(project, runtime, template) {
|
|
21
|
+
async function safe(file) {
|
|
22
|
+
const parts = file.split('/')
|
|
23
|
+
let current = runtime
|
|
24
|
+
for (const segment of parts) {
|
|
25
|
+
current = path.join(current, segment)
|
|
26
|
+
try {
|
|
27
|
+
if ((await lstat(current)).isSymbolicLink())
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Generated locale routes must not contain links: ${current}`
|
|
30
|
+
)
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (error.code !== 'ENOENT') throw error
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return current
|
|
36
|
+
}
|
|
37
|
+
const marker = await safe('.rdx-localization.json')
|
|
38
|
+
let owned = false
|
|
39
|
+
try {
|
|
40
|
+
owned = JSON.parse(await readFile(marker, 'utf8')).version === 1
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error.code !== 'ENOENT') throw error
|
|
43
|
+
}
|
|
44
|
+
if (!project.localization) {
|
|
45
|
+
if (owned) {
|
|
46
|
+
for (const file of generated) await rm(await safe(file), { force: true })
|
|
47
|
+
await rm(marker)
|
|
48
|
+
}
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
async function emit(file, content) {
|
|
52
|
+
const target = await safe(file)
|
|
53
|
+
if (!owned) {
|
|
54
|
+
try {
|
|
55
|
+
await lstat(target)
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Conflicting generated locale route: ${target}. Remove the old .rdx/ runtime and prepare again.`
|
|
58
|
+
)
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (error.code !== 'ENOENT') throw error
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
await mkdir(path.dirname(target), { recursive: true })
|
|
64
|
+
await writeFile(target, content)
|
|
65
|
+
}
|
|
66
|
+
const layout = await readFile(path.join(template, 'app/layout.tsx'), 'utf8')
|
|
67
|
+
const provider = layout.match(/from '([^']+\/runtime)'/)[1]
|
|
68
|
+
for (const file of defaultFiles) {
|
|
69
|
+
const text = await readFile(path.join(template, 'app', file), 'utf8')
|
|
70
|
+
await emit(
|
|
71
|
+
`app/(rdx-default)/${file}`,
|
|
72
|
+
text
|
|
73
|
+
.replace(/from '(\.\.\/[^']*rdx-project)'/g, "from '../$1'")
|
|
74
|
+
.replace("'./globals.css'", "'../globals.css'")
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
await emit(
|
|
78
|
+
'app/(rdx-default)/[...notFound]/page.tsx',
|
|
79
|
+
`import { notFound } from 'next/navigation'\nexport default function Missing() { notFound() }\n`
|
|
80
|
+
)
|
|
81
|
+
await emit(
|
|
82
|
+
'app/(rdx-locales)/[locale]/layout.tsx',
|
|
83
|
+
`import { RdxLayout, getRdxMetadata, getLocalizedProject } from '${provider}'
|
|
84
|
+
import { getProject } from '../../../rdx-project'
|
|
85
|
+
import '../../globals.css'
|
|
86
|
+
export async function generateStaticParams() { return (await getProject()).localization!.locales.map(locale => ({ locale: locale.path })) }
|
|
87
|
+
export const dynamicParams = false
|
|
88
|
+
async function configuration(params: Promise<{ locale: string }>) {
|
|
89
|
+
const project = await getProject()
|
|
90
|
+
const { locale } = await params
|
|
91
|
+
return project.localization!.locales.some(entry => entry.path === locale) ? getLocalizedProject(project, locale).config : project.config
|
|
92
|
+
}
|
|
93
|
+
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { return getRdxMetadata(await configuration(params)) }
|
|
94
|
+
export default async function Layout({ children, params }: { children: React.ReactNode, params: Promise<{ locale: string }> }) {
|
|
95
|
+
return <RdxLayout config={await configuration(params)} bodyClassName="antialiased">{children}</RdxLayout>
|
|
96
|
+
}
|
|
97
|
+
`
|
|
98
|
+
)
|
|
99
|
+
await emit(
|
|
100
|
+
'app/(rdx-locales)/[locale]/not-found.tsx',
|
|
101
|
+
`import { NotFoundPage } from '${provider}'
|
|
102
|
+
import { getProject } from '../../../rdx-project'
|
|
103
|
+
export default async function Missing() { return <NotFoundPage project={await getProject()} /> }
|
|
104
|
+
`
|
|
105
|
+
)
|
|
106
|
+
await emit(
|
|
107
|
+
'app/(rdx-locales)/[locale]/docs/[[...slug]]/page.tsx',
|
|
108
|
+
`import { DocsPage, getDocumentMetadata, getProjectDocsPaths, getLocalizedProject } from '${provider}'
|
|
109
|
+
import { notFound } from 'next/navigation'
|
|
110
|
+
import { getProject } from '../../../../../rdx-project'
|
|
111
|
+
type Params = { locale: string, slug?: string[] }
|
|
112
|
+
async function selected(locale: string) {
|
|
113
|
+
const project = await getProject()
|
|
114
|
+
if (!project.localization!.locales.some(entry => entry.path === locale)) notFound()
|
|
115
|
+
return getLocalizedProject(project, locale)
|
|
116
|
+
}
|
|
117
|
+
export async function generateStaticParams({ params }: { params: { locale: string } }) { return getProjectDocsPaths(await selected(params.locale)).map(slug => ({ slug: slug.split('/') })) }
|
|
118
|
+
export async function generateMetadata({ params }: { params: Promise<Params> }) { const { locale, slug } = await params; return getDocumentMetadata({ project: await selected(locale), slug }) }
|
|
119
|
+
export default async function Page({ params }: { params: Promise<Params> }) { const { locale, slug } = await params; return <DocsPage project={await selected(locale)} slug={slug} /> }
|
|
120
|
+
`
|
|
121
|
+
)
|
|
122
|
+
await emit(
|
|
123
|
+
'app/(rdx-locales)/[locale]/rdx-search/[source]/route.ts',
|
|
124
|
+
`import { getSearchResponse, getSearchSources, getLocalizedProject } from '${provider}'
|
|
125
|
+
import { getProject } from '../../../../../rdx-project'
|
|
126
|
+
export const dynamic = 'force-static'
|
|
127
|
+
export const dynamicParams = false
|
|
128
|
+
export async function generateStaticParams() {
|
|
129
|
+
const project = await getProject()
|
|
130
|
+
return project.localization!.locales.flatMap(locale => getSearchSources(getLocalizedProject(project, locale.path)).map(source => ({ locale: locale.path, ...source })))
|
|
131
|
+
}
|
|
132
|
+
export async function GET(_request: Request, { params }: { params: Promise<{ locale: string, source: string }> }) { const { locale, source } = await params; return getSearchResponse(getLocalizedProject(await getProject(), locale), source) }
|
|
133
|
+
`
|
|
134
|
+
)
|
|
135
|
+
await writeFile(marker, JSON.stringify({ version: 1 }) + '\n')
|
|
136
|
+
for (const file of defaultFiles)
|
|
137
|
+
await rm(await safe(`app/${file}`), { force: true })
|
|
138
|
+
}
|
package/bin/plugin-config.mjs
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import ts from 'typescript'
|
|
2
2
|
|
|
3
3
|
export const versioningPackage = '@lexibase/rdx-versioning'
|
|
4
|
-
const
|
|
4
|
+
export const i18nPackage = '@lexibase/rdx-i18n'
|
|
5
|
+
const versioning = {
|
|
6
|
+
packageName: versioningPackage,
|
|
7
|
+
name: 'versioning',
|
|
8
|
+
label: 'Versioning',
|
|
9
|
+
}
|
|
10
|
+
const localization = { packageName: i18nPackage, name: 'i18n', label: 'i18n' }
|
|
11
|
+
|
|
12
|
+
export function activateVersioning(source) {
|
|
13
|
+
return editPluginConfig(source, versioning)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function inspectI18n(source) {
|
|
17
|
+
return editPluginConfig(source, localization, '', true)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function activateI18n(source, locales) {
|
|
21
|
+
return editPluginConfig(
|
|
22
|
+
source,
|
|
23
|
+
localization,
|
|
24
|
+
JSON.stringify({ locales }, null, 2)
|
|
25
|
+
)
|
|
26
|
+
}
|
|
5
27
|
|
|
6
28
|
function unwrap(node) {
|
|
7
29
|
while (
|
|
@@ -14,7 +36,9 @@ function unwrap(node) {
|
|
|
14
36
|
}
|
|
15
37
|
|
|
16
38
|
// Edit only known literal shapes; never print/reconstruct the user's entire file.
|
|
17
|
-
|
|
39
|
+
function editPluginConfig(source, plugin, argument = '', inspect = false) {
|
|
40
|
+
const { packageName, name: pluginName, label } = plugin
|
|
41
|
+
const manual = `Cannot safely edit rdx.config.ts. Add "import { ${pluginName} } from '${packageName}'" and ${pluginName}(${pluginName === 'i18n' ? '{ locales: [...] }' : ''}) to plugins manually, then run rdx prepare.`
|
|
18
42
|
const file = ts.createSourceFile(
|
|
19
43
|
'rdx.config.ts',
|
|
20
44
|
source,
|
|
@@ -44,7 +68,7 @@ export function activateVersioning(source) {
|
|
|
44
68
|
imported === 'defineConfig'
|
|
45
69
|
)
|
|
46
70
|
definitions.add(specifier.name.text)
|
|
47
|
-
if (name ===
|
|
71
|
+
if (name === packageName && imported === pluginName) {
|
|
48
72
|
if (factory) throw new Error(manual)
|
|
49
73
|
factory = specifier.name.text
|
|
50
74
|
}
|
|
@@ -52,10 +76,10 @@ export function activateVersioning(source) {
|
|
|
52
76
|
} else if (
|
|
53
77
|
bindings &&
|
|
54
78
|
ts.isNamespaceImport(bindings) &&
|
|
55
|
-
name ===
|
|
79
|
+
name === packageName
|
|
56
80
|
) {
|
|
57
81
|
if (factory) throw new Error(manual)
|
|
58
|
-
factory = `${bindings.name.text}
|
|
82
|
+
factory = `${bindings.name.text}.${pluginName}`
|
|
59
83
|
}
|
|
60
84
|
}
|
|
61
85
|
const exports = file.statements.filter(ts.isExportAssignment)
|
|
@@ -100,9 +124,18 @@ export function activateVersioning(source) {
|
|
|
100
124
|
)
|
|
101
125
|
if (matches.length > 1)
|
|
102
126
|
throw new Error(
|
|
103
|
-
|
|
127
|
+
`${label} is configured more than once. Remove the duplicate plugin before retrying.`
|
|
104
128
|
)
|
|
105
|
-
if (matches.length === 1) return source
|
|
129
|
+
if (matches.length === 1) return inspect ? { configured: true } : source
|
|
130
|
+
}
|
|
131
|
+
if (inspect) {
|
|
132
|
+
const languages = properties.filter((entry) => entry.name.text === 'lang')
|
|
133
|
+
if (languages.length > 1) throw new Error(manual)
|
|
134
|
+
const language = languages.length
|
|
135
|
+
? unwrap(languages[0].initializer)
|
|
136
|
+
: undefined
|
|
137
|
+
if (language && !ts.isStringLiteral(language)) throw new Error(manual)
|
|
138
|
+
return { configured: false, lang: language?.text ?? 'en' }
|
|
106
139
|
}
|
|
107
140
|
const newline = source.includes('\r\n') ? '\r\n' : '\n'
|
|
108
141
|
const edits = []
|
|
@@ -113,11 +146,12 @@ export function activateVersioning(source) {
|
|
|
113
146
|
ts.forEachChild(node, visit)
|
|
114
147
|
}
|
|
115
148
|
visit(file)
|
|
116
|
-
factory =
|
|
149
|
+
factory = pluginName
|
|
117
150
|
let suffix = 1
|
|
118
|
-
|
|
151
|
+
const alias = `rdx${pluginName[0].toUpperCase()}${pluginName.slice(1)}`
|
|
152
|
+
while (identifiers.has(factory)) factory = `${alias}${suffix++}`
|
|
119
153
|
const specifier =
|
|
120
|
-
factory ===
|
|
154
|
+
factory === pluginName ? pluginName : `${pluginName} as ${factory}`
|
|
121
155
|
let position = imports.length
|
|
122
156
|
? imports.at(-1).end
|
|
123
157
|
: file.statements[0].getStart(file)
|
|
@@ -133,7 +167,7 @@ export function activateVersioning(source) {
|
|
|
133
167
|
}
|
|
134
168
|
edits.push({
|
|
135
169
|
position,
|
|
136
|
-
text: `${newline}import { ${specifier} } from '${
|
|
170
|
+
text: `${newline}import { ${specifier} } from '${packageName}'${newline}`,
|
|
137
171
|
})
|
|
138
172
|
}
|
|
139
173
|
if (plugins) {
|
|
@@ -142,14 +176,14 @@ export function activateVersioning(source) {
|
|
|
142
176
|
: plugins.getStart(file) + 1
|
|
143
177
|
edits.push({
|
|
144
178
|
position,
|
|
145
|
-
text: `${plugins.elements.length ? ',' : ''} ${factory}()`,
|
|
179
|
+
text: `${plugins.elements.length ? ',' : ''} ${factory}(${argument.replaceAll('\n', newline)})`,
|
|
146
180
|
})
|
|
147
181
|
} else {
|
|
148
182
|
if (properties.length && !properties.hasTrailingComma)
|
|
149
183
|
edits.push({ position: properties.at(-1).end, text: ',' })
|
|
150
184
|
edits.push({
|
|
151
185
|
position: config.end - 1,
|
|
152
|
-
text: `${newline} plugins: [${factory}()],${newline}`,
|
|
186
|
+
text: `${newline} plugins: [${factory}(${argument.replaceAll('\n', newline)})],${newline}`,
|
|
153
187
|
})
|
|
154
188
|
}
|
|
155
189
|
for (const edit of edits.sort((a, b) => b.position - a.position))
|
package/config.mjs
CHANGED
|
@@ -2,7 +2,11 @@ import { readdir, realpath, stat } from 'node:fs/promises'
|
|
|
2
2
|
import { createRequire } from 'node:module'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createRdxProject,
|
|
7
|
+
resolveProjectPath,
|
|
8
|
+
getContentSources,
|
|
9
|
+
} from '@lexibase/rdx-core/config'
|
|
6
10
|
import { createJiti } from 'jiti'
|
|
7
11
|
|
|
8
12
|
/** Include the project and the real Next.js installation in Turbopack's root. */
|
|
@@ -45,7 +49,7 @@ async function contentFiles(directory) {
|
|
|
45
49
|
const filename = path.join(directory, entry.name)
|
|
46
50
|
if (entry.isDirectory()) return contentFiles(filename)
|
|
47
51
|
return entry.isFile() &&
|
|
48
|
-
(entry.name
|
|
52
|
+
(/\.mdx?$/.test(entry.name) || entry.name === '_category.json')
|
|
49
53
|
? [filename]
|
|
50
54
|
: []
|
|
51
55
|
})
|
|
@@ -77,7 +81,7 @@ export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
|
|
|
77
81
|
const project = await createRdxProject(input, { rootDir })
|
|
78
82
|
const files = (
|
|
79
83
|
await Promise.all(
|
|
80
|
-
project
|
|
84
|
+
getContentSources(project)
|
|
81
85
|
.filter((source) => source.redirectTo === undefined)
|
|
82
86
|
.map((source) =>
|
|
83
87
|
contentFiles(
|
|
@@ -102,11 +106,28 @@ export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
|
|
|
102
106
|
}
|
|
103
107
|
const redirects = project.sources
|
|
104
108
|
.filter((source) => source.redirectTo !== undefined)
|
|
105
|
-
.
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
.flatMap((source) =>
|
|
110
|
+
[
|
|
111
|
+
'/docs',
|
|
112
|
+
...(project.localization?.locales.map(
|
|
113
|
+
(locale) => `/${locale.path}/docs`
|
|
114
|
+
) ?? []),
|
|
115
|
+
].map((base) => ({
|
|
116
|
+
source: `${base}/${source.routePrefix}/:path*`,
|
|
117
|
+
destination: `${base}/${source.redirectTo}/:path*`,
|
|
118
|
+
permanent: true,
|
|
119
|
+
}))
|
|
120
|
+
)
|
|
121
|
+
if (project.localization) {
|
|
122
|
+
const primary = project.localization.locales.find(
|
|
123
|
+
(locale) => locale.code === project.localization.defaultLocale
|
|
124
|
+
)
|
|
125
|
+
redirects.push({
|
|
126
|
+
source: '/docs/:path*',
|
|
127
|
+
destination: `/${primary.path}/docs/:path*`,
|
|
108
128
|
permanent: true,
|
|
109
|
-
})
|
|
129
|
+
})
|
|
130
|
+
}
|
|
110
131
|
return {
|
|
111
132
|
...(redirects.length ? { redirects: async () => redirects } : {}),
|
|
112
133
|
outputFileTracingIncludes: {
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { RdxProject, RDXConfig, RdxContentSource, RdxDocPage } from '@lexibase/rdx-types';
|
|
4
|
-
export { createRdxProject, getProjectDocsPaths } from '@lexibase/rdx-core';
|
|
4
|
+
export { createRdxProject, getLocalizedProject, getProjectDocsPaths } from '@lexibase/rdx-core';
|
|
5
5
|
import { MetadataRoute, Metadata } from 'next';
|
|
6
6
|
|
|
7
7
|
declare function getSearchSources(project: RdxProject): {
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
// src/runtime/index.tsx
|
|
2
2
|
import {
|
|
3
|
-
getDocument as
|
|
3
|
+
getDocument as getDocument3,
|
|
4
4
|
getDocsPaths,
|
|
5
|
-
getSourceOptions as
|
|
6
|
-
resolveDocsRoute as resolveDocsRoute2
|
|
5
|
+
getSourceOptions as getSourceOptions4,
|
|
6
|
+
resolveDocsRoute as resolveDocsRoute2,
|
|
7
|
+
getLocalizedProject as getLocalizedProject2,
|
|
8
|
+
getDocsHref as getDocsHref3,
|
|
9
|
+
getLanguageLinks,
|
|
10
|
+
isFallbackPage as isFallbackPage3
|
|
7
11
|
} from "@lexibase/rdx-core";
|
|
8
12
|
import { Button } from "@lexibase/rdx-ui/components/button";
|
|
13
|
+
import { Callout } from "@lexibase/rdx-ui/components/callout";
|
|
14
|
+
import { LanguageDropdown } from "@lexibase/rdx-ui/components/language-dropdown";
|
|
9
15
|
import { DocsSidebar } from "@lexibase/rdx-ui/components/docs-sidebar";
|
|
10
16
|
import { DocsToc } from "@lexibase/rdx-ui/components/docs-toc";
|
|
11
17
|
import { DocsPageTransition } from "@lexibase/rdx-ui/components/docs-page-transition";
|
|
@@ -13,12 +19,13 @@ import { DocsSearch } from "@lexibase/rdx-ui/components/docs-search";
|
|
|
13
19
|
import { Home } from "@lexibase/rdx-ui/components/home";
|
|
14
20
|
import { SkipLink } from "@lexibase/rdx-ui/components/skip-link";
|
|
15
21
|
import { FooterCredit } from "@lexibase/rdx-ui/components/footer-credit";
|
|
16
|
-
import {
|
|
22
|
+
import { BrandLogo } from "@lexibase/rdx-ui/components/brand-logo";
|
|
17
23
|
import { getMdxComponents } from "@lexibase/rdx-ui/components/mdx-components";
|
|
18
24
|
import { getMessages, formatMessage } from "@lexibase/rdx-ui/lib/i18n";
|
|
19
25
|
import { LocaleProvider } from "@lexibase/rdx-ui/providers/locale-provider";
|
|
20
26
|
import { Navbar } from "@lexibase/rdx-ui/components/navbar";
|
|
21
27
|
import { NotFound } from "@lexibase/rdx-ui/components/not-found";
|
|
28
|
+
import { LocalizedNotFound } from "@lexibase/rdx-ui/components/localized-not-found";
|
|
22
29
|
import {
|
|
23
30
|
VersionDropdown
|
|
24
31
|
} from "@lexibase/rdx-ui/components/version-dropdown";
|
|
@@ -42,6 +49,7 @@ function compileDocumentation(source, components, links) {
|
|
|
42
49
|
blockJS: true,
|
|
43
50
|
blockDangerousJS: true,
|
|
44
51
|
mdxOptions: {
|
|
52
|
+
format: links?.sourcePath.endsWith(".md") ? "md" : "mdx",
|
|
45
53
|
remarkPlugins: [
|
|
46
54
|
remarkGfm,
|
|
47
55
|
remarkDocumentationComponents,
|
|
@@ -54,10 +62,19 @@ function compileDocumentation(source, components, links) {
|
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
// src/runtime/index.tsx
|
|
57
|
-
import {
|
|
65
|
+
import {
|
|
66
|
+
createRdxProject,
|
|
67
|
+
getProjectDocsPaths,
|
|
68
|
+
getLocalizedProject as getLocalizedProject3
|
|
69
|
+
} from "@lexibase/rdx-core";
|
|
58
70
|
|
|
59
71
|
// src/runtime/search.ts
|
|
60
|
-
import {
|
|
72
|
+
import {
|
|
73
|
+
getDocsIndex,
|
|
74
|
+
getDocument,
|
|
75
|
+
getSourceOptions,
|
|
76
|
+
getDocsHref
|
|
77
|
+
} from "@lexibase/rdx-core";
|
|
61
78
|
import { buildSearchIndex } from "@lexibase/rdx-core/search";
|
|
62
79
|
function getSearchSources(project) {
|
|
63
80
|
return project.config.search ? project.sources.filter((source) => source.redirectTo === void 0).map((source) => ({ source: source.routePrefix || "_" })) : [];
|
|
@@ -70,17 +87,17 @@ function getSearchResponse(project, key) {
|
|
|
70
87
|
(entry) => entry.redirectTo === void 0 && (entry.routePrefix || "_") === key
|
|
71
88
|
);
|
|
72
89
|
if (!source) return new Response(null, { status: 404, headers });
|
|
73
|
-
|
|
90
|
+
if (source.fallbackOnly)
|
|
91
|
+
return Response.json(buildSearchIndex([]), { headers });
|
|
92
|
+
const { docsDir } = getSourceOptions(project, source);
|
|
93
|
+
const options = { docsDir };
|
|
74
94
|
const documents = getDocsIndex(options).flatMap(
|
|
75
95
|
(category) => category.pages.map((page) => ({
|
|
76
96
|
title: page.title,
|
|
77
97
|
description: page.description,
|
|
78
98
|
category: category.title,
|
|
79
|
-
href:
|
|
80
|
-
|
|
81
|
-
source.routePrefix,
|
|
82
|
-
page.slug.split("/").map(encodeURIComponent).join("/")
|
|
83
|
-
].filter(Boolean).join("/"),
|
|
99
|
+
href: getDocsHref(project, source, page.slug),
|
|
100
|
+
sourcePath: page.sourcePath,
|
|
84
101
|
content: getDocument(page.slug, options)?.content ?? ""
|
|
85
102
|
}))
|
|
86
103
|
);
|
|
@@ -88,7 +105,12 @@ function getSearchResponse(project, key) {
|
|
|
88
105
|
}
|
|
89
106
|
|
|
90
107
|
// src/runtime/indexing.ts
|
|
91
|
-
import {
|
|
108
|
+
import {
|
|
109
|
+
getDocsIndex as getDocsIndex2,
|
|
110
|
+
getSourceOptions as getSourceOptions2,
|
|
111
|
+
getContentSources,
|
|
112
|
+
isFallbackPage
|
|
113
|
+
} from "@lexibase/rdx-core";
|
|
92
114
|
function getSourceRobots(project, source) {
|
|
93
115
|
const published = project.sources.some(
|
|
94
116
|
(entry) => entry.id !== "current" && entry.redirectTo === void 0 && entry.badge !== "Archived"
|
|
@@ -107,7 +129,7 @@ function getRdxRobots(config) {
|
|
|
107
129
|
}
|
|
108
130
|
function getRdxSitemap(project, {
|
|
109
131
|
documentPath = (source, page) => [
|
|
110
|
-
"/docs",
|
|
132
|
+
source.basePath ?? "/docs",
|
|
111
133
|
source.routePrefix,
|
|
112
134
|
page.slug.split("/").map(encodeURIComponent).join("/")
|
|
113
135
|
].filter(Boolean).join("/")
|
|
@@ -116,10 +138,11 @@ function getRdxSitemap(project, {
|
|
|
116
138
|
if (!base) return [];
|
|
117
139
|
const urls = /* @__PURE__ */ new Set();
|
|
118
140
|
if (project.config.homepage?.enabled) urls.add(new URL("/", base).href);
|
|
119
|
-
for (const source of project
|
|
141
|
+
for (const source of getContentSources(project)) {
|
|
120
142
|
if (!getSourceRobots(project, source).index) continue;
|
|
121
143
|
for (const category of getDocsIndex2(getSourceOptions2(project, source))) {
|
|
122
144
|
for (const page of category.pages) {
|
|
145
|
+
if (isFallbackPage(project, source, page.sourcePath)) continue;
|
|
123
146
|
urls.add(new URL(documentPath(source, page), base).href);
|
|
124
147
|
}
|
|
125
148
|
}
|
|
@@ -128,21 +151,67 @@ function getRdxSitemap(project, {
|
|
|
128
151
|
}
|
|
129
152
|
|
|
130
153
|
// src/runtime/metadata.ts
|
|
131
|
-
import {
|
|
154
|
+
import {
|
|
155
|
+
resolveDocsRoute,
|
|
156
|
+
getLocalizedProject,
|
|
157
|
+
getDocsHref as getDocsHref2,
|
|
158
|
+
isFallbackPage as isFallbackPage2,
|
|
159
|
+
getDocument as getDocument2,
|
|
160
|
+
getSourceOptions as getSourceOptions3
|
|
161
|
+
} from "@lexibase/rdx-core";
|
|
132
162
|
import { notFound } from "next/navigation";
|
|
133
163
|
function getDocumentMetadata({
|
|
134
164
|
project,
|
|
135
165
|
slug
|
|
136
166
|
}) {
|
|
167
|
+
if (project.localization && !project.locale)
|
|
168
|
+
return { robots: { index: false, follow: true } };
|
|
137
169
|
const route = resolveDocsRoute(project, slug);
|
|
138
170
|
if (route.source.redirectTo !== void 0)
|
|
139
171
|
return { robots: getSourceRobots(project, route.source) };
|
|
140
172
|
if (!route.slug) return { robots: { index: false, follow: true } };
|
|
141
173
|
if (!route.document) notFound();
|
|
142
174
|
const page = route.categories.flatMap((category) => category.pages).find((page2) => page2.slug === route.slug);
|
|
175
|
+
const fallback = isFallbackPage2(project, route.source, page.sourcePath);
|
|
176
|
+
const primary = project.localization?.locales.find(
|
|
177
|
+
(locale) => locale.code === project.localization.defaultLocale
|
|
178
|
+
);
|
|
179
|
+
const canonicalProject = fallback ? getLocalizedProject(project, primary.path) : project;
|
|
180
|
+
const base = project.config.metadata.metadataBase;
|
|
181
|
+
const languages = project.localization && base ? Object.fromEntries(
|
|
182
|
+
project.localization.locales.flatMap((locale) => {
|
|
183
|
+
const view = getLocalizedProject(project, locale.path);
|
|
184
|
+
const source = view.sources.find(
|
|
185
|
+
(entry) => entry.id === route.source.id
|
|
186
|
+
);
|
|
187
|
+
return !source.fallbackOnly && getDocument2(page.slug, {
|
|
188
|
+
docsDir: getSourceOptions3(view, source).docsDir
|
|
189
|
+
}) ? [
|
|
190
|
+
[
|
|
191
|
+
locale.code,
|
|
192
|
+
new URL(getDocsHref2(view, source, page.slug), base).href
|
|
193
|
+
]
|
|
194
|
+
] : [];
|
|
195
|
+
})
|
|
196
|
+
) : void 0;
|
|
143
197
|
return {
|
|
144
198
|
...getPageMetadata(project.config, page),
|
|
145
|
-
robots: getSourceRobots(project, route.source)
|
|
199
|
+
robots: fallback ? { index: false, follow: true } : getSourceRobots(project, route.source),
|
|
200
|
+
...project.localization && base ? {
|
|
201
|
+
alternates: {
|
|
202
|
+
canonical: new URL(
|
|
203
|
+
getDocsHref2(
|
|
204
|
+
canonicalProject,
|
|
205
|
+
canonicalProject.sources.find(
|
|
206
|
+
(entry) => entry.id === route.source.id
|
|
207
|
+
),
|
|
208
|
+
page.slug
|
|
209
|
+
),
|
|
210
|
+
base
|
|
211
|
+
).href,
|
|
212
|
+
...fallback ? {} : { languages }
|
|
213
|
+
}
|
|
214
|
+
} : {}
|
|
146
215
|
};
|
|
147
216
|
}
|
|
148
217
|
function getPageMetadata(config, page) {
|
|
@@ -211,16 +280,15 @@ function RdxHeader({
|
|
|
211
280
|
const messages = getMessages(config.lang);
|
|
212
281
|
const { source, slug: currentSlug } = resolveDocsRoute2(project, slug);
|
|
213
282
|
const options = project.sources.filter((edition) => edition.redirectTo === void 0).map((edition) => {
|
|
214
|
-
const docs =
|
|
215
|
-
const destination = currentSlug &&
|
|
283
|
+
const docs = getSourceOptions4(project, edition);
|
|
284
|
+
const destination = currentSlug && getDocument3(currentSlug, docs) ? currentSlug : getDocsPaths(docs)[0];
|
|
216
285
|
return {
|
|
217
286
|
id: edition.id,
|
|
218
287
|
label: edition.id === "current" ? messages.current : formatMessage(messages.version, { version: edition.label }),
|
|
219
288
|
kind: edition.id === "current" ? "live" : edition.badge === "Archived" ? "archived" : "version",
|
|
220
|
-
href:
|
|
289
|
+
href: getDocsHref3(project, edition, destination)
|
|
221
290
|
};
|
|
222
291
|
});
|
|
223
|
-
const BrandLogo = config.navbar?.logo ?? Logo;
|
|
224
292
|
return /* @__PURE__ */ jsx(
|
|
225
293
|
Navbar,
|
|
226
294
|
{
|
|
@@ -229,14 +297,23 @@ function RdxHeader({
|
|
|
229
297
|
search: config.search ? /* @__PURE__ */ jsx(
|
|
230
298
|
DocsSearch,
|
|
231
299
|
{
|
|
232
|
-
indexUrl:
|
|
300
|
+
indexUrl: `${project.locale ? `/${project.locale.path}` : ""}/rdx-search/${encodeURIComponent(source.routePrefix || "_")}`,
|
|
233
301
|
version: source.id === "current" ? messages.current : formatMessage(messages.version, { version: source.label })
|
|
234
302
|
}
|
|
235
303
|
) : void 0,
|
|
236
304
|
siteTitle: config.metadata.applicationName,
|
|
237
|
-
logo: /* @__PURE__ */ jsx(BrandLogo, { className: "size-5" }),
|
|
238
|
-
homeHref: config.homepage?.enabled ? "/" :
|
|
239
|
-
docsHref:
|
|
305
|
+
logo: /* @__PURE__ */ jsx(BrandLogo, { source: config.navbar?.logo, className: "size-5" }),
|
|
306
|
+
homeHref: config.homepage?.enabled ? "/" : getDocsHref3(project),
|
|
307
|
+
docsHref: getDocsHref3(project, source),
|
|
308
|
+
languageMenu: project.localization ? /* @__PURE__ */ jsx(
|
|
309
|
+
LanguageDropdown,
|
|
310
|
+
{
|
|
311
|
+
lang: config.lang,
|
|
312
|
+
current: project.locale?.code ?? project.localization.defaultLocale,
|
|
313
|
+
options: getLanguageLinks(project, source, currentSlug),
|
|
314
|
+
contributionUrl: project.localization.contributionUrl
|
|
315
|
+
}
|
|
316
|
+
) : void 0,
|
|
240
317
|
versionMenu: project.sources.length > 1 ? /* @__PURE__ */ jsx(VersionDropdown, { options, currentId: source.id }) : void 0,
|
|
241
318
|
github: config.navbar?.actions?.github,
|
|
242
319
|
showToggleMode: config.navbar?.actions?.showToggleMode
|
|
@@ -245,10 +322,9 @@ function RdxHeader({
|
|
|
245
322
|
}
|
|
246
323
|
function HomePage({ project }) {
|
|
247
324
|
const { config } = project;
|
|
248
|
-
if (!config.homepage?.enabled) redirect(
|
|
325
|
+
if (!config.homepage?.enabled) redirect(getDocsHref3(project));
|
|
249
326
|
const homepage = config.homepage;
|
|
250
327
|
const CustomHome = homepage.component;
|
|
251
|
-
const BrandLogo = config.navbar?.logo ?? Logo;
|
|
252
328
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
253
329
|
/* @__PURE__ */ jsx(RdxHeader, { project }),
|
|
254
330
|
/* @__PURE__ */ jsx(
|
|
@@ -261,7 +337,13 @@ function HomePage({ project }) {
|
|
|
261
337
|
Home,
|
|
262
338
|
{
|
|
263
339
|
title: homepage.title ?? config.metadata.applicationName,
|
|
264
|
-
logo: /* @__PURE__ */ jsx(
|
|
340
|
+
logo: /* @__PURE__ */ jsx(
|
|
341
|
+
BrandLogo,
|
|
342
|
+
{
|
|
343
|
+
source: config.navbar?.logo,
|
|
344
|
+
className: "size-52 hover:scale-105 hover:rotate-1 transition-[scale,rotation] duration-1000"
|
|
345
|
+
}
|
|
346
|
+
),
|
|
265
347
|
description: homepage.description,
|
|
266
348
|
buttons: homepage.buttons
|
|
267
349
|
}
|
|
@@ -271,6 +353,24 @@ function HomePage({ project }) {
|
|
|
271
353
|
] });
|
|
272
354
|
}
|
|
273
355
|
function NotFoundPage({ project }) {
|
|
356
|
+
if (project.localization) {
|
|
357
|
+
const { config, localization } = project;
|
|
358
|
+
return /* @__PURE__ */ jsx(
|
|
359
|
+
LocalizedNotFound,
|
|
360
|
+
{
|
|
361
|
+
locales: localization.locales,
|
|
362
|
+
defaultLocale: localization.defaultLocale,
|
|
363
|
+
homepage: !!config.homepage?.enabled,
|
|
364
|
+
brand: {
|
|
365
|
+
title: config.navbar?.title,
|
|
366
|
+
siteTitle: config.metadata.applicationName,
|
|
367
|
+
github: config.navbar?.actions?.github,
|
|
368
|
+
showToggleMode: config.navbar?.actions?.showToggleMode,
|
|
369
|
+
logo: /* @__PURE__ */ jsx(BrandLogo, { source: config.navbar?.logo, className: "size-5" })
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
}
|
|
274
374
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
275
375
|
/* @__PURE__ */ jsx(RdxHeader, { project }),
|
|
276
376
|
/* @__PURE__ */ jsx(NotFound, { lang: project.config.lang })
|
|
@@ -280,6 +380,8 @@ async function DocsPage({
|
|
|
280
380
|
slug,
|
|
281
381
|
project
|
|
282
382
|
}) {
|
|
383
|
+
if (project.localization && !project.locale)
|
|
384
|
+
permanentRedirect(getDocsHref3(project, project.sources[0], slug?.join("/")));
|
|
283
385
|
const messages = getMessages(project.config.lang);
|
|
284
386
|
const {
|
|
285
387
|
source,
|
|
@@ -289,11 +391,13 @@ async function DocsPage({
|
|
|
289
391
|
} = resolveDocsRoute2(project, slug);
|
|
290
392
|
if (source.redirectTo !== void 0)
|
|
291
393
|
permanentRedirect(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
394
|
+
getDocsHref3(
|
|
395
|
+
project,
|
|
396
|
+
project.sources.find(
|
|
397
|
+
(entry) => entry.routePrefix === source.redirectTo
|
|
398
|
+
),
|
|
399
|
+
slug?.slice(1).join("/")
|
|
400
|
+
)
|
|
297
401
|
);
|
|
298
402
|
if (!currentSlug)
|
|
299
403
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -304,19 +408,32 @@ async function DocsPage({
|
|
|
304
408
|
] })
|
|
305
409
|
] });
|
|
306
410
|
if (!document) notFound2();
|
|
411
|
+
const fallback = isFallbackPage3(project, source, document.sourcePath);
|
|
412
|
+
const primaryLocale = (source.localization ?? project.localization)?.locales.find(
|
|
413
|
+
(locale) => locale.code === project.localization.defaultLocale
|
|
414
|
+
);
|
|
415
|
+
const originalProject = fallback && primaryLocale ? getLocalizedProject2(project, primaryLocale.path) : project;
|
|
416
|
+
const contentSource = originalProject.sources.find(
|
|
417
|
+
(entry) => entry.id === source.id
|
|
418
|
+
);
|
|
419
|
+
const contentOptions = getSourceOptions4(originalProject, contentSource);
|
|
420
|
+
const contentCategories = fallback ? resolveDocsRoute2(originalProject, slug).categories : categories;
|
|
421
|
+
const contentLanguage = fallback ? primaryLocale.code : project.config.lang;
|
|
307
422
|
const { content } = await compileDocumentation(
|
|
308
423
|
document.content,
|
|
309
424
|
getMdxComponents(project.config.lang),
|
|
310
425
|
{
|
|
311
|
-
sourceRoot:
|
|
426
|
+
sourceRoot: contentOptions.docsDir,
|
|
312
427
|
sourcePath: document.sourcePath,
|
|
313
428
|
routePrefix: source.routePrefix,
|
|
314
|
-
|
|
429
|
+
basePath: contentSource.basePath,
|
|
430
|
+
virtualPaths: !!contentOptions.fallbackDocsDir,
|
|
431
|
+
documents: contentCategories.flatMap((category2) => category2.pages)
|
|
315
432
|
}
|
|
316
433
|
);
|
|
317
434
|
const title = typeof document.frontmatter.title === "string" ? document.frontmatter.title : currentSlug;
|
|
318
435
|
const description = typeof document.frontmatter.description === "string" ? document.frontmatter.description : null;
|
|
319
|
-
const hrefFor = (pageSlug) =>
|
|
436
|
+
const hrefFor = (pageSlug) => getDocsHref3(project, source, pageSlug);
|
|
320
437
|
const sidebarCategories = categories.map((category2) => ({
|
|
321
438
|
title: category2.title,
|
|
322
439
|
links: category2.pages.map((page) => ({
|
|
@@ -362,9 +479,58 @@ async function DocsPage({
|
|
|
362
479
|
"main",
|
|
363
480
|
{
|
|
364
481
|
id: "rdx-main",
|
|
482
|
+
lang: contentLanguage,
|
|
365
483
|
tabIndex: -1,
|
|
366
484
|
className: "w-full flex flex-col gap-5 md:mx-auto md:max-w-[860px] pt-14 md:pt-0 flex-1 outline-none",
|
|
367
485
|
children: [
|
|
486
|
+
fallback && /* @__PURE__ */ jsxs(
|
|
487
|
+
Callout,
|
|
488
|
+
{
|
|
489
|
+
lang: project.config.lang,
|
|
490
|
+
variant: "note",
|
|
491
|
+
title: messages.translationUnavailable,
|
|
492
|
+
"data-rdx-translation-fallback": true,
|
|
493
|
+
children: [
|
|
494
|
+
/* @__PURE__ */ jsx("p", { children: formatMessage(messages.translationFallback, {
|
|
495
|
+
requested: project.locale.label,
|
|
496
|
+
original: primaryLocale.label
|
|
497
|
+
}) }),
|
|
498
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-2", children: [
|
|
499
|
+
/* @__PURE__ */ jsx(
|
|
500
|
+
Button,
|
|
501
|
+
{
|
|
502
|
+
variant: "link",
|
|
503
|
+
href: getDocsHref3(
|
|
504
|
+
originalProject,
|
|
505
|
+
contentSource,
|
|
506
|
+
currentSlug
|
|
507
|
+
),
|
|
508
|
+
children: messages.viewOriginal
|
|
509
|
+
}
|
|
510
|
+
),
|
|
511
|
+
project.localization?.contributionUrl && /* @__PURE__ */ jsxs(
|
|
512
|
+
Button,
|
|
513
|
+
{
|
|
514
|
+
variant: "link",
|
|
515
|
+
href: project.localization.contributionUrl,
|
|
516
|
+
target: "_blank",
|
|
517
|
+
rel: "noopener noreferrer",
|
|
518
|
+
"data-rdx-translate-page": true,
|
|
519
|
+
children: [
|
|
520
|
+
messages.translateThisPage,
|
|
521
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
522
|
+
" ",
|
|
523
|
+
"(",
|
|
524
|
+
messages.opensInNewTab,
|
|
525
|
+
")"
|
|
526
|
+
] })
|
|
527
|
+
]
|
|
528
|
+
}
|
|
529
|
+
)
|
|
530
|
+
] })
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
),
|
|
368
534
|
/* @__PURE__ */ jsxs("header", { className: "mb-6", children: [
|
|
369
535
|
source.badge && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: source.badge === "Archived" ? messages.archivedVersion : source.badge }),
|
|
370
536
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-600 font-semibold uppercase block -mb-0.5", children: category?.title }),
|
|
@@ -425,6 +591,7 @@ export {
|
|
|
425
591
|
RdxLayout,
|
|
426
592
|
createRdxProject,
|
|
427
593
|
getDocumentMetadata,
|
|
594
|
+
getLocalizedProject3 as getLocalizedProject,
|
|
428
595
|
getPageMetadata,
|
|
429
596
|
getProjectDocsPaths,
|
|
430
597
|
getRdxMetadata,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexibase/rdx-next",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "The Next.js runtime for RDX documentation projects.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -48,14 +48,15 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"cross-spawn": "^7.0.6",
|
|
50
50
|
"jiti": "^2.6.1",
|
|
51
|
+
"prompts": "^2.4.2",
|
|
51
52
|
"next-mdx-remote": "^6.0.0",
|
|
52
53
|
"remark-gfm": "^4",
|
|
53
54
|
"typescript": "6.0.3",
|
|
54
|
-
"@lexibase/rdx-types": "2.
|
|
55
|
-
"@lexibase/rdx-core": "2.
|
|
55
|
+
"@lexibase/rdx-types": "2.2.0",
|
|
56
|
+
"@lexibase/rdx-core": "2.2.0"
|
|
56
57
|
},
|
|
57
58
|
"peerDependencies": {
|
|
58
|
-
"@lexibase/rdx-ui": "^3.
|
|
59
|
+
"@lexibase/rdx-ui": "^3.4.0",
|
|
59
60
|
"next": "^16.4.2",
|
|
60
61
|
"react": "^19.3.1",
|
|
61
62
|
"react-dom": "^19.3.1"
|
|
@@ -80,9 +81,9 @@
|
|
|
80
81
|
"next": "^16.4.2",
|
|
81
82
|
"react": "19.3.1",
|
|
82
83
|
"react-dom": "19.3.1",
|
|
84
|
+
"@rdx/typescript-config": "1.0.0",
|
|
83
85
|
"@rdx/eslint-config": "1.0.0",
|
|
84
|
-
"@lexibase/rdx-ui": "3.
|
|
85
|
-
"@rdx/typescript-config": "1.0.0"
|
|
86
|
+
"@lexibase/rdx-ui": "3.4.0"
|
|
86
87
|
},
|
|
87
88
|
"scripts": {
|
|
88
89
|
"dev": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --watch --external @lexibase/rdx-core --external @lexibase/rdx-types --external @lexibase/rdx-ui --external next --external react --external react-dom --external next-mdx-remote",
|