docpensieve 0.4.0 → 0.5.0-beta.2
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/bin/docpensieve.js +1 -0
- package/package.json +5 -5
- package/src/commands/init.js +199 -18
- package/starter/01-guide/01-installation.md +4 -2
- package/starter/01-guide/07-migrate-to-beta.md +41 -0
- package/starter/01-guide/10-languages.md +13 -0
- package/starter/03-reference/01-cli.md +1 -0
- package/starter/03-reference/05-api.md +36 -3
- package/starter/05-whats-new.md +29 -75
- package/types/commands/init.d.ts +10 -5
- package/starter/01-guide/07-migrate-from-0-3.md +0 -125
package/bin/docpensieve.js
CHANGED
|
@@ -34,6 +34,7 @@ program
|
|
|
34
34
|
.option('-t, --theme <framework>', 'tailwind | custom')
|
|
35
35
|
.option('-u, --site-url <url>', 'public URL of the site')
|
|
36
36
|
.option('--version-name <version>', 'first version, e.g. 1.0')
|
|
37
|
+
.option('--translation <code>', 'code of a second language, e.g. fr')
|
|
37
38
|
.option('-y, --yes', 'accept the defaults without a dialogue')
|
|
38
39
|
.option('-f, --force', 'overwrite an existing configuration')
|
|
39
40
|
.option('--minimal', "leave DocPensieve's documentation out of the new site")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docpensieve",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-beta.2",
|
|
4
4
|
"description": "DocPensieve command-line interface (init, build, check, dev, serve)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"types"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@docpensieve/components": "0.
|
|
28
|
-
"@docpensieve/core": "0.
|
|
29
|
-
"@docpensieve/shared": "0.
|
|
30
|
-
"@docpensieve/theme": "0.
|
|
27
|
+
"@docpensieve/components": "0.5.0-beta.2",
|
|
28
|
+
"@docpensieve/core": "0.5.0-beta.2",
|
|
29
|
+
"@docpensieve/shared": "0.5.0-beta.2",
|
|
30
|
+
"@docpensieve/theme": "0.5.0-beta.2",
|
|
31
31
|
"chalk": "^6.0.0",
|
|
32
32
|
"chokidar": "^5.0.0",
|
|
33
33
|
"commander": "^15.0.0"
|
package/src/commands/init.js
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
DocPensieveError,
|
|
19
19
|
THEME_FOLDER,
|
|
20
20
|
THEME_FRAMEWORKS,
|
|
21
|
+
isLanguageCode,
|
|
22
|
+
languageName,
|
|
21
23
|
} from '@docpensieve/shared';
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -30,7 +32,16 @@ const FRAMEWORK_LABELS = {
|
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
/** Answers used when there is no dialogue. */
|
|
33
|
-
const DEFAULTS = {
|
|
35
|
+
const DEFAULTS = {
|
|
36
|
+
name: 'My documentation',
|
|
37
|
+
siteUrl: '',
|
|
38
|
+
theme: 'tailwind',
|
|
39
|
+
version: '1.0',
|
|
40
|
+
translation: '',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Second language offered first, being the one whose wording ships too. */
|
|
44
|
+
const DEFAULT_TRANSLATION = 'fr';
|
|
34
45
|
|
|
35
46
|
/**
|
|
36
47
|
* Folder of the installed DocPensieve documentation, inside the version folder.
|
|
@@ -125,15 +136,43 @@ async function askDocumentation(rl) {
|
|
|
125
136
|
}
|
|
126
137
|
}
|
|
127
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Asks whether the site will carry a second language, and which one.
|
|
141
|
+
*
|
|
142
|
+
* Asked rather than left to the configuration: a translation changes the
|
|
143
|
+
* shape of the project — a folder per language beside the pages — and that is
|
|
144
|
+
* cheaper to set up at the start than to retrofit.
|
|
145
|
+
*
|
|
146
|
+
* @param {import('node:readline/promises').Interface} rl
|
|
147
|
+
* @returns {Promise<string>} Language code, or `''` for a single language.
|
|
148
|
+
*/
|
|
149
|
+
async function askTranslation(rl) {
|
|
150
|
+
for (;;) {
|
|
151
|
+
const answer = (await rl.question('Will the site be in several languages? [y/N]: '))
|
|
152
|
+
.trim()
|
|
153
|
+
.toLowerCase();
|
|
154
|
+
if (answer === '' || answer === 'n' || answer === 'no') return '';
|
|
155
|
+
if (answer === 'y' || answer === 'yes') break;
|
|
156
|
+
console.log('Answer not understood. Expected: y or n.');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (;;) {
|
|
160
|
+
const code = (await ask(rl, 'Code of the second language', DEFAULT_TRANSLATION)).trim();
|
|
161
|
+
if (isLanguageCode(code)) return code;
|
|
162
|
+
console.log(`"${code}" does not name a language. Expected a code: fr, de, pt-BR, zh-Hans.`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
128
166
|
/**
|
|
129
167
|
* Gathers the answers, through a dialogue or from the options.
|
|
130
168
|
*
|
|
131
169
|
* @param {{
|
|
132
170
|
* name?: string, theme?: string, siteUrl?: string, version?: string,
|
|
133
|
-
* yes?: boolean, minimal?: boolean,
|
|
171
|
+
* translation?: string, yes?: boolean, minimal?: boolean,
|
|
134
172
|
* }} options
|
|
135
173
|
* @returns {Promise<{
|
|
136
174
|
* name: string, theme: string, siteUrl: string, version: string, docs: boolean,
|
|
175
|
+
* translation: string,
|
|
137
176
|
* }>}
|
|
138
177
|
*/
|
|
139
178
|
async function collect(options) {
|
|
@@ -142,6 +181,7 @@ async function collect(options) {
|
|
|
142
181
|
siteUrl: options.siteUrl ?? DEFAULTS.siteUrl,
|
|
143
182
|
theme: options.theme ?? DEFAULTS.theme,
|
|
144
183
|
version: options.version ?? DEFAULTS.version,
|
|
184
|
+
translation: options.translation ?? DEFAULTS.translation,
|
|
145
185
|
docs: !options.minimal,
|
|
146
186
|
};
|
|
147
187
|
|
|
@@ -154,7 +194,7 @@ async function collect(options) {
|
|
|
154
194
|
if (!process.stdin.isTTY) {
|
|
155
195
|
console.log('No interactive terminal: no questions asked, the options and defaults apply.');
|
|
156
196
|
console.log(
|
|
157
|
-
'To choose, pass --name, --site-url, --theme, --version-name or --minimal; --yes silences this notice.',
|
|
197
|
+
'To choose, pass --name, --site-url, --theme, --version-name, --translation or --minimal; --yes silences this notice.',
|
|
158
198
|
);
|
|
159
199
|
return fromOptions;
|
|
160
200
|
}
|
|
@@ -164,9 +204,10 @@ async function collect(options) {
|
|
|
164
204
|
const name = await ask(rl, 'Project name', fromOptions.name);
|
|
165
205
|
const siteUrl = await ask(rl, 'Public URL of the site (optional)', fromOptions.siteUrl);
|
|
166
206
|
const version = await ask(rl, 'First version', fromOptions.version);
|
|
207
|
+
const translation = options.translation ?? (await askTranslation(rl));
|
|
167
208
|
const theme = options.theme ?? (await askFramework(rl));
|
|
168
209
|
const docs = options.minimal ? false : await askDocumentation(rl);
|
|
169
|
-
return { name, siteUrl, version, theme, docs };
|
|
210
|
+
return { name, siteUrl, version, theme, docs, translation };
|
|
170
211
|
} finally {
|
|
171
212
|
rl.close();
|
|
172
213
|
}
|
|
@@ -183,6 +224,18 @@ async function collect(options) {
|
|
|
183
224
|
*/
|
|
184
225
|
const quote = (value) => `'${String(value).replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
185
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Writes a language code as a property name.
|
|
229
|
+
*
|
|
230
|
+
* `fr` stands on its own; `pt-BR` and `zh-Hans` carry a hyphen, which is a
|
|
231
|
+
* minus sign to JavaScript — unquoted, the generated configuration would not
|
|
232
|
+
* parse.
|
|
233
|
+
*
|
|
234
|
+
* @param {string} code
|
|
235
|
+
* @returns {string}
|
|
236
|
+
*/
|
|
237
|
+
const key = (code) => (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(code) ? code : quote(code));
|
|
238
|
+
|
|
186
239
|
/**
|
|
187
240
|
* Renders `docpensieve.config.mjs`.
|
|
188
241
|
*
|
|
@@ -190,10 +243,13 @@ const quote = (value) => `'${String(value).replace(/\\/g, '\\\\').replace(/'/g,
|
|
|
190
243
|
* or commented out with an example — so that the first file a user opens also
|
|
191
244
|
* tells them everything they can change.
|
|
192
245
|
*
|
|
193
|
-
* @param {{
|
|
246
|
+
* @param {{
|
|
247
|
+
* name: string, theme: string, siteUrl: string, version: string,
|
|
248
|
+
* translation?: string,
|
|
249
|
+
* }} answers
|
|
194
250
|
* @returns {string} Contents of `docpensieve.config.mjs`.
|
|
195
251
|
*/
|
|
196
|
-
function renderConfig({ name, theme, siteUrl, version }) {
|
|
252
|
+
function renderConfig({ name, theme, siteUrl, version, translation = '' }) {
|
|
197
253
|
const slug = versionSlug(version);
|
|
198
254
|
// A type annotation rather than an `import`: `defineConfig` transforms
|
|
199
255
|
// nothing, it is only there for autocompletion. Actually importing it would
|
|
@@ -233,9 +289,14 @@ function renderConfig({ name, theme, siteUrl, version }) {
|
|
|
233
289
|
` name: ${quote(version)}, // label in the version switcher`,
|
|
234
290
|
` folder: ${quote(`docs/${slug}`)},`,
|
|
235
291
|
' current: true,',
|
|
236
|
-
|
|
292
|
+
` // Pages of this version in another language, served under /${translation || 'fr'}/.`,
|
|
237
293
|
' // Your own language stays where it is, and keeps its addresses.',
|
|
238
|
-
|
|
294
|
+
// Written out, not left as an example, once the language is known: the
|
|
295
|
+
// field is the whole of the feature, and the folder beside it already
|
|
296
|
+
// holds a page.
|
|
297
|
+
translation
|
|
298
|
+
? ` translations: { ${key(translation)}: ${quote(`docs/${slug}-${translation}`)} },`
|
|
299
|
+
: ` // translations: { fr: ${quote(`docs/${slug}-fr`)} },`,
|
|
239
300
|
' },',
|
|
240
301
|
' ],',
|
|
241
302
|
'',
|
|
@@ -353,11 +414,12 @@ function versionSlug(version) {
|
|
|
353
414
|
}
|
|
354
415
|
|
|
355
416
|
/**
|
|
356
|
-
*
|
|
357
|
-
*
|
|
417
|
+
* Home page of the project, in the language of the site.
|
|
418
|
+
*
|
|
419
|
+
* @param {{ name: string, docs: boolean, slug: string, translation: string }} answers
|
|
358
420
|
* @returns {string}
|
|
359
421
|
*/
|
|
360
|
-
const renderIndex = (name, docs) => `---
|
|
422
|
+
const renderIndex = ({ name, docs, slug, translation }) => `---
|
|
361
423
|
title: Introduction
|
|
362
424
|
description: Documentation of ${name}.
|
|
363
425
|
date: ${new Date().toISOString().slice(0, 10)}
|
|
@@ -378,6 +440,20 @@ without appearing in the URL.
|
|
|
378
440
|
|
|
379
441
|
See the [installation guide](/guide/installation/).
|
|
380
442
|
${
|
|
443
|
+
translation
|
|
444
|
+
? `
|
|
445
|
+
## In ${languageName(translation)}
|
|
446
|
+
|
|
447
|
+
The same pages live in \`docs/${slug}-${translation}/\`, and the language switcher
|
|
448
|
+
in the header moves between them.
|
|
449
|
+
|
|
450
|
+
A page with no twin there does not exist in that language: it stays out of the
|
|
451
|
+
menu and out of the sitemap, and the switcher names the language without
|
|
452
|
+
offering it. The installation page is in that case — write
|
|
453
|
+
\`docs/${slug}-${translation}/01-guide/01-installation.md\` and it appears.
|
|
454
|
+
${docs ? '\nThe [languages guide](/docpensieve/guide/languages/) covers the rest.\n' : ''}`
|
|
455
|
+
: ''
|
|
456
|
+
}${
|
|
381
457
|
docs
|
|
382
458
|
? `
|
|
383
459
|
## Learning DocPensieve
|
|
@@ -389,6 +465,70 @@ tool that builds this site, installed along with it. Delete its folder,
|
|
|
389
465
|
: ''
|
|
390
466
|
}`;
|
|
391
467
|
|
|
468
|
+
/**
|
|
469
|
+
* Home page of the second language.
|
|
470
|
+
*
|
|
471
|
+
* French is written out, the tool shipping its wording too. Any other
|
|
472
|
+
* language gets the page in English, saying in its first line that it is
|
|
473
|
+
* there to be translated: a copy passing for a translation is the one failure
|
|
474
|
+
* this feature invites — the reader gets English under an address that
|
|
475
|
+
* promised their language, and nothing reports it.
|
|
476
|
+
*
|
|
477
|
+
* Only the home page is written. Its twin, the installation page, is left
|
|
478
|
+
* untranslated on purpose: it is what shows that an untranslated page does
|
|
479
|
+
* not exist in that language, which no sentence explains as well as the menu
|
|
480
|
+
* that lacks it.
|
|
481
|
+
*
|
|
482
|
+
* @param {{ name: string, slug: string, translation: string }} answers
|
|
483
|
+
* @returns {string}
|
|
484
|
+
*/
|
|
485
|
+
function renderTranslatedIndex({ name, slug, translation }) {
|
|
486
|
+
const french = translation.toLowerCase().split('-')[0] === 'fr';
|
|
487
|
+
const head = `---
|
|
488
|
+
title: Introduction
|
|
489
|
+
description: ${french ? `Documentation de ${name}.` : `Documentation of ${name}.`}
|
|
490
|
+
date: ${new Date().toISOString().slice(0, 10)}
|
|
491
|
+
|
|
492
|
+
jsonld:
|
|
493
|
+
type: TechArticle
|
|
494
|
+
breadcrumbs: true
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
# ${name}
|
|
498
|
+
`;
|
|
499
|
+
|
|
500
|
+
if (french) {
|
|
501
|
+
return `${head}
|
|
502
|
+
Bienvenue dans la documentation.
|
|
503
|
+
|
|
504
|
+
## Une page et sa jumelle
|
|
505
|
+
|
|
506
|
+
Cette page est la version française de \`docs/${slug}/index.md\`. Le sélecteur
|
|
507
|
+
de langue, dans l'en-tête, passe de l'une à l'autre.
|
|
508
|
+
|
|
509
|
+
La page d'installation, elle, n'est pas traduite : elle **n'existe pas** en
|
|
510
|
+
français. Elle ne figure ni dans le menu ni dans le plan du site, et le
|
|
511
|
+
sélecteur la nomme sans la proposer. Écrivez
|
|
512
|
+
\`docs/${slug}-${translation}/01-guide/01-installation.md\` pour la voir apparaître.
|
|
513
|
+
`;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return `${head}
|
|
517
|
+
**Replace this page with your translation.** It is the ${languageName(translation)}
|
|
518
|
+
twin of \`docs/${slug}/index.md\`, written in English so that the site builds:
|
|
519
|
+
left as it is, a reader who picks ${languageName(translation, translation)} gets English.
|
|
520
|
+
|
|
521
|
+
## One page, two languages
|
|
522
|
+
|
|
523
|
+
The language switcher in the header moves between this page and its twin.
|
|
524
|
+
|
|
525
|
+
The installation page has no twin here, so it does not exist in this language:
|
|
526
|
+
it stays out of the menu and out of the sitemap, and the switcher names the
|
|
527
|
+
language without offering it. Write
|
|
528
|
+
\`docs/${slug}-${translation}/01-guide/01-installation.md\` and it appears.
|
|
529
|
+
`;
|
|
530
|
+
}
|
|
531
|
+
|
|
392
532
|
/** @returns {string} Sample page, showing ordering and highlighting. */
|
|
393
533
|
const renderGuide = () => `---
|
|
394
534
|
title: Installation
|
|
@@ -478,11 +618,14 @@ async function installDocumentation(source, target, slug) {
|
|
|
478
618
|
* @param {string} [dir] Target folder, created if needed.
|
|
479
619
|
* @param {{
|
|
480
620
|
* name?: string, theme?: string, siteUrl?: string, version?: string,
|
|
481
|
-
* yes?: boolean, force?: boolean, minimal?: boolean,
|
|
482
|
-
* }} [options] `minimal` leaves DocPensieve's documentation out of the site
|
|
483
|
-
*
|
|
484
|
-
* @
|
|
485
|
-
*
|
|
621
|
+
* translation?: string, yes?: boolean, force?: boolean, minimal?: boolean,
|
|
622
|
+
* }} [options] `minimal` leaves DocPensieve's documentation out of the site;
|
|
623
|
+
* `translation` is the code of a second language, `fr` for instance.
|
|
624
|
+
* @returns {Promise<{
|
|
625
|
+
* dir: string, theme: string, docs: boolean, translation: string,
|
|
626
|
+
* }>}
|
|
627
|
+
* @throws {DocPensieveError} Unknown framework, unknown language, project
|
|
628
|
+
* already initialised, or documentation to install missing.
|
|
486
629
|
*/
|
|
487
630
|
export async function init(dir = '.', options = {}) {
|
|
488
631
|
const target = path.resolve(dir);
|
|
@@ -504,6 +647,14 @@ export async function init(dir = '.', options = {}) {
|
|
|
504
647
|
});
|
|
505
648
|
}
|
|
506
649
|
|
|
650
|
+
// Checked here for the same reason as the framework: a code refused after
|
|
651
|
+
// five questions would be five questions wasted.
|
|
652
|
+
if (options.translation && !isLanguageCode(options.translation)) {
|
|
653
|
+
throw new DocPensieveError(`"${options.translation}" does not name a language.`, {
|
|
654
|
+
hint: 'Write the code, not the name: "fr" for French, "pt-BR", "zh-Hans". It becomes the lang of the document and a segment of the address.',
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
507
658
|
const answers = await collect(options);
|
|
508
659
|
|
|
509
660
|
// Located before anything is written: a project left half set up would be
|
|
@@ -535,8 +686,21 @@ export async function init(dir = '.', options = {}) {
|
|
|
535
686
|
|
|
536
687
|
await mkdir(path.join(docsDir, '01-guide'), { recursive: true });
|
|
537
688
|
await writeFile(configPath, renderConfig(answers), 'utf8');
|
|
538
|
-
await writeFile(
|
|
689
|
+
await writeFile(
|
|
690
|
+
path.join(docsDir, 'index.md'),
|
|
691
|
+
renderIndex({ name: answers.name, docs: answers.docs, slug, translation: answers.translation }),
|
|
692
|
+
'utf8',
|
|
693
|
+
);
|
|
539
694
|
await writeFile(path.join(docsDir, '01-guide', '01-installation.md'), renderGuide(), 'utf8');
|
|
695
|
+
if (answers.translation) {
|
|
696
|
+
const folder = path.join(target, 'docs', `${slug}-${answers.translation}`);
|
|
697
|
+
await mkdir(folder, { recursive: true });
|
|
698
|
+
await writeFile(
|
|
699
|
+
path.join(folder, 'index.md'),
|
|
700
|
+
renderTranslatedIndex({ name: answers.name, slug, translation: answers.translation }),
|
|
701
|
+
'utf8',
|
|
702
|
+
);
|
|
703
|
+
}
|
|
540
704
|
if (documentation) {
|
|
541
705
|
await installDocumentation(documentation, path.join(docsDir, DOCS_FOLDER), slug);
|
|
542
706
|
}
|
|
@@ -548,14 +712,31 @@ export async function init(dir = '.', options = {}) {
|
|
|
548
712
|
console.log(` ${CONFIG_FILENAME}`);
|
|
549
713
|
console.log(` docs/${slug}/index.md`);
|
|
550
714
|
console.log(` docs/${slug}/01-guide/01-installation.md`);
|
|
715
|
+
if (answers.translation) {
|
|
716
|
+
const state =
|
|
717
|
+
answers.translation.toLowerCase().split('-')[0] === 'fr'
|
|
718
|
+
? `in ${languageName(answers.translation)}`
|
|
719
|
+
: 'to translate';
|
|
720
|
+
console.log(` docs/${slug}-${answers.translation}/index.md the home page, ${state}`);
|
|
721
|
+
}
|
|
551
722
|
if (documentation) {
|
|
552
723
|
console.log(` docs/${slug}/${DOCS_FOLDER}/ DocPensieve's documentation, to delete when done`);
|
|
553
724
|
}
|
|
554
725
|
for (const line of stylesheets) console.log(` ${line}`);
|
|
555
726
|
console.log(`\nTheme: ${answers.theme} — ${FRAMEWORK_LABELS[answers.theme]}`);
|
|
727
|
+
if (answers.translation) {
|
|
728
|
+
console.log(
|
|
729
|
+
`Second language: ${languageName(answers.translation)} (${answers.translation}) — served under /${answers.translation}/`,
|
|
730
|
+
);
|
|
731
|
+
}
|
|
556
732
|
console.log('\nNext: npx docpensieve dev');
|
|
557
733
|
|
|
558
|
-
return {
|
|
734
|
+
return {
|
|
735
|
+
dir: target,
|
|
736
|
+
theme: answers.theme,
|
|
737
|
+
docs: answers.docs,
|
|
738
|
+
translation: answers.translation,
|
|
739
|
+
};
|
|
559
740
|
}
|
|
560
741
|
|
|
561
742
|
/**
|
|
@@ -46,6 +46,7 @@ npx docpensieve init my-site --yes --name "My documentation"
|
|
|
46
46
|
| `-t, --theme <framework>` | `tailwind` or `custom` |
|
|
47
47
|
| `-u, --site-url <url>` | Public URL, from which the deployment prefix is derived |
|
|
48
48
|
| `--version-name <version>` | First version, `1.0` for instance |
|
|
49
|
+
| `--translation <code>` | Code of a second language, `fr` for instance |
|
|
49
50
|
| `-y, --yes` | Accepts the defaults without a dialogue |
|
|
50
51
|
| `-f, --force` | Overwrites an existing configuration |
|
|
51
52
|
| `--minimal` | Leaves DocPensieve's documentation out of the site |
|
|
@@ -99,8 +100,9 @@ The documentation `init` installed in `99-docpensieve` stays at the version it
|
|
|
99
100
|
came with. To refresh it, run `init` in a scratch folder and copy that folder
|
|
100
101
|
over.
|
|
101
102
|
|
|
102
|
-
Coming from the 0.
|
|
103
|
-
changes on its own and what to check first.
|
|
103
|
+
Coming from the 0.4, [Migrate from latest to beta](./migrate-to-beta/) says
|
|
104
|
+
what changes on its own and what to check first. To try this beta, install
|
|
105
|
+
`docpensieve@beta`, or run `npx docpensieve@beta` alone.
|
|
104
106
|
|
|
105
107
|
## Checking
|
|
106
108
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Migrate from latest to beta
|
|
3
|
+
description: Move a project from the latest version, the 0.4, to the 0.5 beta — what changes on its own, and what to check.
|
|
4
|
+
tags: [guide, migration]
|
|
5
|
+
|
|
6
|
+
jsonld:
|
|
7
|
+
type: TechArticle
|
|
8
|
+
breadcrumbs: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Migrate from latest to beta
|
|
12
|
+
|
|
13
|
+
A project on the latest version — the 0.4 — builds with the 0.5 beta as it is:
|
|
14
|
+
every field the 0.5 adds is optional.
|
|
15
|
+
|
|
16
|
+
## Update
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install docpensieve@beta
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Through `npx` alone, `npx docpensieve@beta` runs the beta. Going back is
|
|
23
|
+
`npm install docpensieve@latest`.
|
|
24
|
+
|
|
25
|
+
Read your site back once after the update — it is the cheapest check there is:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx docpensieve build
|
|
29
|
+
npx docpensieve check
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## What changes on its own
|
|
33
|
+
|
|
34
|
+
Nothing yet: the 0.5 has just opened. Each change is listed here as it lands,
|
|
35
|
+
beside what it asks of a project already built on the 0.4.
|
|
36
|
+
|
|
37
|
+
## What to check afterwards
|
|
38
|
+
|
|
39
|
+
- **Your own CSS**, if the theme folder styles anything the beta touches.
|
|
40
|
+
- **`npx docpensieve check`**, which reads the built site back and reports dead
|
|
41
|
+
links and invalid markup.
|
|
@@ -13,6 +13,19 @@ jsonld:
|
|
|
13
13
|
A version can be published in several languages. Each one is a folder of pages
|
|
14
14
|
of its own, standing beside the version it translates.
|
|
15
15
|
|
|
16
|
+
## Starting from init
|
|
17
|
+
|
|
18
|
+
`init` asks whether the site will be in several languages. Answer yes, give a
|
|
19
|
+
code, and the project comes out wired: the folder beside your pages, the field
|
|
20
|
+
in the configuration, and a home page in that language to start from.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx docpensieve init my-site --translation fr
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Everything below is what that answer sets up — and what to do when you add a
|
|
27
|
+
language to a project that already exists.
|
|
28
|
+
|
|
16
29
|
## Declaring a translation
|
|
17
30
|
|
|
18
31
|
```js
|
|
@@ -29,6 +29,7 @@ npx docpensieve init [dir]
|
|
|
29
29
|
| `-t, --theme <framework>` | `tailwind` or `custom` |
|
|
30
30
|
| `-u, --site-url <url>` | Public URL of the site |
|
|
31
31
|
| `--version-name <version>` | First version, `1.0` for instance |
|
|
32
|
+
| `--translation <code>` | Code of a second language, `fr` |
|
|
32
33
|
| `-y, --yes` | Accepts the defaults without a dialogue |
|
|
33
34
|
| `-f, --force` | Overwrites an existing configuration |
|
|
34
35
|
| `--minimal` | Leaves DocPensieve's documentation out |
|
|
@@ -346,6 +346,39 @@ a language nobody thought of.
|
|
|
346
346
|
|
|
347
347
|
**Returns** `'ltr' \| 'rtl'` — `ltr` when the language is unknown — the safe default, and what every page did before this existed.
|
|
348
348
|
|
|
349
|
+
### `isLanguageCode`
|
|
350
|
+
|
|
351
|
+
`isLanguageCode(value)`
|
|
352
|
+
|
|
353
|
+
Whether a string names a language, as BCP 47 and CLDR understand it.
|
|
354
|
+
|
|
355
|
+
The standard is BCP 47, and `Intl` carries it: a regex of our own refused
|
|
356
|
+
`zh-Hans-CN`, which is valid, and accepted shapes that are not. Well formed
|
|
357
|
+
is not the same as real, though — BCP 47 allows a language subtag of five
|
|
358
|
+
to eight letters, so `francais` passes that check and would land in the
|
|
359
|
+
markup as `lang="francais"`, a value no browser maps to a language. CLDR
|
|
360
|
+
knows which tags name one; the subtag alone is asked, so that a region, a
|
|
361
|
+
script or a private extension does not get in the way.
|
|
362
|
+
|
|
363
|
+
| Parameter | Type | |
|
|
364
|
+
| --- | --- | --- |
|
|
365
|
+
| `value` | `string` | |
|
|
366
|
+
|
|
367
|
+
**Returns** `boolean`
|
|
368
|
+
|
|
369
|
+
### `languageName`
|
|
370
|
+
|
|
371
|
+
`languageName(code, [inLang])`
|
|
372
|
+
|
|
373
|
+
Name of a language, written in a language.
|
|
374
|
+
|
|
375
|
+
| Parameter | Type | |
|
|
376
|
+
| --- | --- | --- |
|
|
377
|
+
| `code` | `string` | Language code. |
|
|
378
|
+
| `[inLang]` | `string` | Language the name is written in. |
|
|
379
|
+
|
|
380
|
+
**Returns** `string` — The name, or the code itself when nothing names it.
|
|
381
|
+
|
|
349
382
|
## `@docpensieve/core`
|
|
350
383
|
|
|
351
384
|
Configuration, loading, compilation, structured data and generation.
|
|
@@ -1211,11 +1244,11 @@ Sets up a documentation project.
|
|
|
1211
1244
|
| Parameter | Type | |
|
|
1212
1245
|
| --- | --- | --- |
|
|
1213
1246
|
| `[dir]` | `string` | Target folder, created if needed. |
|
|
1214
|
-
| `[options]` | `{ name?: string, theme?: string, siteUrl?: string, version?: string, yes?: boolean, force?: boolean, minimal?: boolean, }` | `minimal` leaves DocPensieve's documentation out of the site. |
|
|
1247
|
+
| `[options]` | `{ name?: string, theme?: string, siteUrl?: string, version?: string, translation?: string, yes?: boolean, force?: boolean, minimal?: boolean, }` | `minimal` leaves DocPensieve's documentation out of the site; `translation` is the code of a second language, `fr` for instance. |
|
|
1215
1248
|
|
|
1216
|
-
**Returns** `Promise<{ dir: string, theme: string, docs: boolean }>`
|
|
1249
|
+
**Returns** `Promise<{ dir: string, theme: string, docs: boolean, translation: string, }>`
|
|
1217
1250
|
|
|
1218
|
-
**Throws** `DocPensieveError` — Unknown framework, project already initialised, or documentation to install missing.
|
|
1251
|
+
**Throws** `DocPensieveError` — Unknown framework, unknown language, project already initialised, or documentation to install missing.
|
|
1219
1252
|
|
|
1220
1253
|
### `serve`
|
|
1221
1254
|
|
package/starter/05-whats-new.md
CHANGED
|
@@ -1,92 +1,46 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: What's new in 0.
|
|
3
|
-
description: What the 0.
|
|
2
|
+
title: What's new in 0.5
|
|
3
|
+
description: What the 0.5 brings, and what it changes for a 0.4 project.
|
|
4
4
|
tags: [release]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# What's new in 0.
|
|
7
|
+
# What's new in 0.5
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
This version is **in preparation**. Its betas go out under the npm tag `beta`,
|
|
10
|
+
while the version installed by default stays the 0.4, documented in the
|
|
11
|
+
`latest` pages of this site:
|
|
10
12
|
|
|
11
13
|
```bash
|
|
12
|
-
npx docpensieve init my-site
|
|
14
|
+
npx docpensieve@beta init my-site
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
Each feature
|
|
16
|
-
|
|
17
|
+
Each feature is announced here as it lands, with a link to the guide and to the
|
|
18
|
+
reference: this page announces, it is never the only place something is
|
|
19
|
+
written.
|
|
17
20
|
|
|
18
|
-
##
|
|
21
|
+
## Already there
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
scroll past what did not concern them; it can now fold its menu, carry its own
|
|
22
|
-
links in the header, and set a passage apart in the middle of a page.
|
|
23
|
+
### init asks about languages
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
`init` now asks whether the site will be in several languages, and sets the
|
|
26
|
+
answer up: the folder beside your pages, `translations` written out in the
|
|
27
|
+
configuration, and a home page in that language to start from. The second
|
|
28
|
+
sample page is deliberately left untranslated, so that the menu shows what an
|
|
29
|
+
untranslated page does — nothing, in that language.
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
the content, whatever that setting — nothing to configure for that one. See
|
|
29
|
-
[Navigation](./guide/navigation/).
|
|
30
|
-
|
|
31
|
-
### Links and panels in the header
|
|
32
|
-
|
|
33
|
-
A `headerLinks` entry adds a link beside the version switcher. An entry
|
|
34
|
-
carrying `columns` opens a **panel** of links instead of leading anywhere, so a
|
|
35
|
-
site can navigate from the header alone, from the menu alone, or from both with
|
|
36
|
-
different links. A `version` field points every version at a single one, which
|
|
37
|
-
is how this site leads to its examples. See
|
|
38
|
-
[Navigation](./guide/navigation/) and
|
|
39
|
-
[the configuration reference](./reference/configuration/).
|
|
40
|
-
|
|
41
|
-
### A header held, or not
|
|
42
|
-
|
|
43
|
-
`stickyHeader` decides whether the header holds to the top of the screen or
|
|
44
|
-
scrolls away with the page, giving its height back to the text. It stays held
|
|
45
|
-
by default. See [Navigation](./guide/navigation/).
|
|
46
|
-
|
|
47
|
-
### A menu of links, anywhere in a page
|
|
48
|
-
|
|
49
|
-
The `Menu` component places a row of links where a page needs them — a summary
|
|
50
|
-
at the top of a landing page, the chapters of a guide. Entries can be grouped
|
|
51
|
-
under a title, and the row folds behind a button on a narrow screen, without a
|
|
52
|
-
script. See [Menu](./components/menu/).
|
|
53
|
-
|
|
54
|
-
### Blocks that stand apart
|
|
55
|
-
|
|
56
|
-
`Admonition` sets a passage apart and says how to read it: `note`, `info`,
|
|
57
|
-
`tip`, `attention`, `alert`, `danger`. A project declares **its own kinds** in
|
|
58
|
-
the `admonitions` field — a label and a tone taken from the theme — so the list
|
|
59
|
-
does not have to grow for a team to have the block it needs. See
|
|
60
|
-
[Admonition](./components/admonition/).
|
|
61
|
-
|
|
62
|
-
### Icons from a set
|
|
63
|
-
|
|
64
|
-
`LogoIcon` accepts the name of an icon from a collection, written
|
|
65
|
-
`simple-icons:github`, beside a file of your project. The set is a package your
|
|
66
|
-
project installs and the drawing is placed in the page at the build, like any
|
|
67
|
-
other icon: your reader downloads nothing, and no request leaves their browser.
|
|
68
|
-
An admonition kind takes its mark the same way. See
|
|
69
|
-
[LogoIcon](./components/logo-icon/).
|
|
70
|
-
|
|
71
|
-
### A site in several languages
|
|
72
|
-
|
|
73
|
-
A version declares the folder of each translation:
|
|
74
|
-
|
|
75
|
-
```js
|
|
76
|
-
versions: [
|
|
77
|
-
{ slug: 'latest', name: '1.0', folder: 'docs/v1.0', current: true,
|
|
78
|
-
translations: { fr: 'docs/v1.0-fr' } },
|
|
79
|
-
],
|
|
31
|
+
```bash
|
|
32
|
+
npx docpensieve init my-site --translation fr
|
|
80
33
|
```
|
|
81
34
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
35
|
+
A code is a BCP 47 one: `fr`, `pt-BR`, `zh-Hans`. French and English ship with
|
|
36
|
+
their wording for the shell; any other language keeps the English wording
|
|
37
|
+
until the `ui` field gives it its own.
|
|
38
|
+
|
|
39
|
+
[Languages](./guide/languages/) · [The init options](./reference/cli/)
|
|
87
40
|
|
|
88
|
-
## For a 0.
|
|
41
|
+
## For a 0.4 project
|
|
89
42
|
|
|
90
|
-
Nothing to change: a 0.
|
|
91
|
-
|
|
92
|
-
|
|
43
|
+
Nothing to change: a 0.4 configuration builds as it is, and a site already in
|
|
44
|
+
two languages is untouched — the question only shapes a **new** project.
|
|
45
|
+
[Migrate from latest to beta](./guide/migrate-to-beta/) lists what changes on
|
|
46
|
+
its own, and what is worth turning on.
|
package/types/commands/init.d.ts
CHANGED
|
@@ -9,17 +9,21 @@
|
|
|
9
9
|
* @param {string} [dir] Target folder, created if needed.
|
|
10
10
|
* @param {{
|
|
11
11
|
* name?: string, theme?: string, siteUrl?: string, version?: string,
|
|
12
|
-
* yes?: boolean, force?: boolean, minimal?: boolean,
|
|
13
|
-
* }} [options] `minimal` leaves DocPensieve's documentation out of the site
|
|
14
|
-
*
|
|
15
|
-
* @
|
|
16
|
-
*
|
|
12
|
+
* translation?: string, yes?: boolean, force?: boolean, minimal?: boolean,
|
|
13
|
+
* }} [options] `minimal` leaves DocPensieve's documentation out of the site;
|
|
14
|
+
* `translation` is the code of a second language, `fr` for instance.
|
|
15
|
+
* @returns {Promise<{
|
|
16
|
+
* dir: string, theme: string, docs: boolean, translation: string,
|
|
17
|
+
* }>}
|
|
18
|
+
* @throws {DocPensieveError} Unknown framework, unknown language, project
|
|
19
|
+
* already initialised, or documentation to install missing.
|
|
17
20
|
*/
|
|
18
21
|
export declare function init(dir?: string, options?: {
|
|
19
22
|
name?: string;
|
|
20
23
|
theme?: string;
|
|
21
24
|
siteUrl?: string;
|
|
22
25
|
version?: string;
|
|
26
|
+
translation?: string;
|
|
23
27
|
yes?: boolean;
|
|
24
28
|
force?: boolean;
|
|
25
29
|
minimal?: boolean;
|
|
@@ -27,4 +31,5 @@ export declare function init(dir?: string, options?: {
|
|
|
27
31
|
dir: string;
|
|
28
32
|
theme: string;
|
|
29
33
|
docs: boolean;
|
|
34
|
+
translation: string;
|
|
30
35
|
}>;
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Migrate from 0.3 to 0.4
|
|
3
|
-
description: Move a project from the 0.3 to the 0.4 — what changes on its own, and what to turn on.
|
|
4
|
-
tags: [guide, migration]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Migrate from 0.3 to 0.4
|
|
8
|
-
|
|
9
|
-
A project on the 0.3 builds with the 0.4 as it is: every field the 0.4 adds is
|
|
10
|
-
optional, and leaving them out keeps the site you have.
|
|
11
|
-
|
|
12
|
-
## Update
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm install docpensieve@latest
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Through `npx` alone, `npx docpensieve` already runs it.
|
|
19
|
-
|
|
20
|
-
Read your site back once after the update — it is the cheapest check there is:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npx docpensieve build
|
|
24
|
-
npx docpensieve check
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## What changes on its own
|
|
28
|
-
|
|
29
|
-
**On a narrow screen, the documentation menu now folds above the content**
|
|
30
|
-
instead of standing open between the header and the text. Nothing to
|
|
31
|
-
configure, and nothing to undo: on a wide screen the menu is unchanged.
|
|
32
|
-
|
|
33
|
-
Nothing else moves. Your pages, your configuration and your theme folder are
|
|
34
|
-
read exactly as before.
|
|
35
|
-
|
|
36
|
-
## What is worth turning on
|
|
37
|
-
|
|
38
|
-
Each of these is one line of `docpensieve.config.mjs`. None depends on
|
|
39
|
-
another.
|
|
40
|
-
|
|
41
|
-
### A menu that folds
|
|
42
|
-
|
|
43
|
-
Past twenty or so pages, a menu that shows everything asks the reader to scroll
|
|
44
|
-
past what does not concern them:
|
|
45
|
-
|
|
46
|
-
```js
|
|
47
|
-
foldedSidebar: true,
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
The categories fold, and the branch of the page being read opens on its own.
|
|
51
|
-
A category that is also a page keeps its page as the first entry — the handle
|
|
52
|
-
of a fold cannot be a link.
|
|
53
|
-
|
|
54
|
-
### Links in the header
|
|
55
|
-
|
|
56
|
-
```js
|
|
57
|
-
headerLinks: [
|
|
58
|
-
{ label: 'Blog', href: '/blog/' },
|
|
59
|
-
{ label: 'Repository', href: 'https://example.com/repo' },
|
|
60
|
-
],
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
A target starts from the root of a version, or is a full address. An entry
|
|
64
|
-
carrying `columns` opens a panel instead of leading anywhere; `href` and
|
|
65
|
-
`columns` together are refused, an entry doing one thing or the other.
|
|
66
|
-
|
|
67
|
-
See [Navigation](./navigation/) for the panel and for what happens on a phone.
|
|
68
|
-
|
|
69
|
-
### A header that scrolls away
|
|
70
|
-
|
|
71
|
-
```js
|
|
72
|
-
stickyHeader: false,
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
The header gives its height back to the text instead of holding to the top of
|
|
76
|
-
the screen. It stays held by default.
|
|
77
|
-
|
|
78
|
-
### Blocks that stand apart
|
|
79
|
-
|
|
80
|
-
Six kinds ship — `note`, `info`, `tip`, `attention`, `alert`, `danger` — and
|
|
81
|
-
need no configuration:
|
|
82
|
-
|
|
83
|
-
```mdx
|
|
84
|
-
<Admonition type="attention">Read this before upgrading.</Admonition>
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Kinds of your own take a label and a tone:
|
|
88
|
-
|
|
89
|
-
```js
|
|
90
|
-
admonitions: {
|
|
91
|
-
review: { label: 'To review', tone: 'attention' },
|
|
92
|
-
},
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
A kind nobody declared stops the build rather than rendering a block with no
|
|
96
|
-
colour and no label. See [Admonition](../components/admonition/).
|
|
97
|
-
|
|
98
|
-
### Icons from a set
|
|
99
|
-
|
|
100
|
-
Beside a file of your project, `LogoIcon` accepts the name of an icon from a
|
|
101
|
-
collection:
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
npm install --save-dev @iconify-json/simple-icons
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
```mdx
|
|
108
|
-
<LogoIcon src="simple-icons:github" label="Repository" />
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
The set is read at the build and the drawing placed in the page: no request
|
|
112
|
-
leaves your reader's browser. See [LogoIcon](../components/logo-icon/).
|
|
113
|
-
|
|
114
|
-
## What to check afterwards
|
|
115
|
-
|
|
116
|
-
- **Your own CSS**, if the theme folder styles the header or the menu: the
|
|
117
|
-
folded menu adds `details` and `summary` elements where there were only
|
|
118
|
-
links, and a static header no longer carries `position: sticky`.
|
|
119
|
-
- **A link to a heading**, if you turned the sticky header off: the space kept
|
|
120
|
-
above an anchor goes away with it, which is the point.
|
|
121
|
-
- **`npx docpensieve check`**, which reads the built site back and reports dead
|
|
122
|
-
links and invalid markup.
|
|
123
|
-
|
|
124
|
-
None of this is required. A project that turns none of it on is a 0.3 project
|
|
125
|
-
that happens to be running the 0.4.
|