create-docusaurus 2.0.0-beta.20 → 2.0.0-beta.21
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/index.js +11 -21
- package/lib/index.d.ts +10 -8
- package/lib/index.js +237 -156
- package/package.json +7 -6
- package/templates/classic/package.json +5 -5
- package/templates/classic/src/pages/index.js +3 -2
- package/templates/classic-typescript/package.json +5 -5
- package/templates/classic-typescript/src/pages/index.tsx +3 -2
- package/templates/facebook/package.json +7 -7
package/bin/index.js
CHANGED
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
|
|
9
9
|
// @ts-check
|
|
10
10
|
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import {createRequire} from 'module';
|
|
11
13
|
import logger from '@docusaurus/logger';
|
|
12
14
|
import semver from 'semver';
|
|
13
|
-
import path from 'path';
|
|
14
15
|
import {program} from 'commander';
|
|
15
|
-
import {createRequire} from 'module';
|
|
16
16
|
|
|
17
|
-
const packageJson =
|
|
17
|
+
const packageJson = /** @type {import("../package.json")} */ (
|
|
18
|
+
createRequire(import.meta.url)('../package.json')
|
|
19
|
+
);
|
|
18
20
|
const requiredVersion = packageJson.engines.node;
|
|
19
21
|
|
|
20
22
|
if (!semver.satisfies(process.version, requiredVersion)) {
|
|
@@ -45,24 +47,12 @@ program
|
|
|
45
47
|
\`custom\`: enter your custom git clone command. We will prompt you for it.`,
|
|
46
48
|
)
|
|
47
49
|
.description('Initialize website.')
|
|
48
|
-
.action(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
template,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
) => {
|
|
55
|
-
// See https://github.com/facebook/docusaurus/pull/6860
|
|
56
|
-
import('../lib/index.js').then(({default: init}) => {
|
|
57
|
-
init(path.resolve(rootDir), siteName, template, {
|
|
58
|
-
packageManager,
|
|
59
|
-
skipInstall,
|
|
60
|
-
typescript,
|
|
61
|
-
gitStrategy,
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
);
|
|
50
|
+
.action((siteName, template, rootDir, options) => {
|
|
51
|
+
// See https://github.com/facebook/docusaurus/pull/6860
|
|
52
|
+
import('../lib/index.js').then(({default: init}) => {
|
|
53
|
+
init(path.resolve(rootDir ?? '.'), siteName, template, options);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
66
56
|
|
|
67
57
|
program.parse(process.argv);
|
|
68
58
|
|
package/lib/index.d.ts
CHANGED
|
@@ -4,17 +4,19 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
declare
|
|
7
|
+
declare type CLIOptions = {
|
|
8
|
+
packageManager?: PackageManager;
|
|
9
|
+
skipInstall?: boolean;
|
|
10
|
+
typescript?: boolean;
|
|
11
|
+
gitStrategy?: GitStrategy;
|
|
12
|
+
};
|
|
13
|
+
declare const lockfileNames: {
|
|
8
14
|
npm: string;
|
|
9
15
|
yarn: string;
|
|
10
16
|
pnpm: string;
|
|
11
17
|
};
|
|
12
|
-
declare type
|
|
18
|
+
declare type PackageManager = keyof typeof lockfileNames;
|
|
13
19
|
declare const gitStrategies: readonly ["deep", "shallow", "copy", "custom"];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
skipInstall: boolean;
|
|
17
|
-
typescript: boolean;
|
|
18
|
-
gitStrategy: typeof gitStrategies[number];
|
|
19
|
-
}>): Promise<void>;
|
|
20
|
+
declare type GitStrategy = typeof gitStrategies[number];
|
|
21
|
+
export default function init(rootDir: string, reqName?: string, reqTemplate?: string, cliOptions?: CLIOptions): Promise<void>;
|
|
20
22
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -4,28 +4,27 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import logger from '@docusaurus/logger';
|
|
8
7
|
import fs from 'fs-extra';
|
|
9
|
-
import
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
10
9
|
import path from 'path';
|
|
11
|
-
import shell from 'shelljs';
|
|
12
10
|
import _ from 'lodash';
|
|
11
|
+
import logger from '@docusaurus/logger';
|
|
12
|
+
import shell from 'shelljs';
|
|
13
|
+
import prompts from 'prompts';
|
|
13
14
|
import supportsColor from 'supports-color';
|
|
14
|
-
import {
|
|
15
|
-
const RecommendedTemplate = 'classic';
|
|
16
|
-
const TypeScriptTemplateSuffix = '-typescript';
|
|
15
|
+
import { escapeShellArg } from '@docusaurus/utils';
|
|
17
16
|
// Only used in the rare, rare case of running globally installed create +
|
|
18
17
|
// using --skip-install. We need a default name to show the tip text
|
|
19
|
-
const
|
|
20
|
-
const
|
|
18
|
+
const defaultPackageManager = 'npm';
|
|
19
|
+
const lockfileNames = {
|
|
21
20
|
npm: 'package-lock.json',
|
|
22
21
|
yarn: 'yarn.lock',
|
|
23
22
|
pnpm: 'pnpm-lock.yaml',
|
|
24
23
|
};
|
|
25
|
-
const
|
|
26
|
-
async function findPackageManagerFromLockFile() {
|
|
27
|
-
for (const packageManager of
|
|
28
|
-
const lockFilePath = path.
|
|
24
|
+
const packageManagers = Object.keys(lockfileNames);
|
|
25
|
+
async function findPackageManagerFromLockFile(rootDir) {
|
|
26
|
+
for (const packageManager of packageManagers) {
|
|
27
|
+
const lockFilePath = path.join(rootDir, lockfileNames[packageManager]);
|
|
29
28
|
if (await fs.pathExists(lockFilePath)) {
|
|
30
29
|
return packageManager;
|
|
31
30
|
}
|
|
@@ -33,7 +32,7 @@ async function findPackageManagerFromLockFile() {
|
|
|
33
32
|
return undefined;
|
|
34
33
|
}
|
|
35
34
|
function findPackageManagerFromUserAgent() {
|
|
36
|
-
return
|
|
35
|
+
return packageManagers.find((packageManager) => process.env.npm_config_user_agent?.startsWith(packageManager));
|
|
37
36
|
}
|
|
38
37
|
async function askForPackageManagerChoice() {
|
|
39
38
|
const hasYarn = shell.exec('yarn --version', { silent: true }).code === 0;
|
|
@@ -44,76 +43,90 @@ async function askForPackageManagerChoice() {
|
|
|
44
43
|
const choices = ['npm', hasYarn && 'yarn', hasPnpm && 'pnpm']
|
|
45
44
|
.filter((p) => Boolean(p))
|
|
46
45
|
.map((p) => ({ title: p, value: p }));
|
|
47
|
-
return (await prompts({
|
|
46
|
+
return ((await prompts({
|
|
48
47
|
type: 'select',
|
|
49
48
|
name: 'packageManager',
|
|
50
49
|
message: 'Select a package manager...',
|
|
51
50
|
choices,
|
|
52
|
-
}
|
|
51
|
+
}, {
|
|
52
|
+
onCancel() {
|
|
53
|
+
logger.info `Falling back to name=${defaultPackageManager}`;
|
|
54
|
+
},
|
|
55
|
+
})).packageManager ?? defaultPackageManager);
|
|
53
56
|
}
|
|
54
|
-
async function getPackageManager(
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
throw new Error(`Invalid package manager choice ${packageManagerChoice}. Must be one of ${PackageManagersList.join(', ')}`);
|
|
57
|
+
async function getPackageManager(dest, { packageManager, skipInstall }) {
|
|
58
|
+
if (packageManager && !packageManagers.includes(packageManager)) {
|
|
59
|
+
throw new Error(`Invalid package manager choice ${packageManager}. Must be one of ${packageManagers.join(', ')}`);
|
|
58
60
|
}
|
|
59
|
-
return (
|
|
60
|
-
|
|
61
|
+
return (
|
|
62
|
+
// If dest already contains a lockfile (e.g. if using a local template), we
|
|
63
|
+
// always use that instead
|
|
64
|
+
(await findPackageManagerFromLockFile(dest)) ??
|
|
65
|
+
packageManager ??
|
|
66
|
+
(await findPackageManagerFromLockFile('.')) ??
|
|
61
67
|
findPackageManagerFromUserAgent() ??
|
|
62
68
|
// This only happens if the user has a global installation in PATH
|
|
63
|
-
(skipInstall ?
|
|
64
|
-
}
|
|
65
|
-
function isValidGitRepoUrl(gitRepoUrl) {
|
|
66
|
-
return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item));
|
|
69
|
+
(skipInstall ? defaultPackageManager : askForPackageManagerChoice()));
|
|
67
70
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const recommendedTemplate = 'classic';
|
|
72
|
+
const typeScriptTemplateSuffix = '-typescript';
|
|
73
|
+
const templatesDir = fileURLToPath(new URL('../templates', import.meta.url));
|
|
74
|
+
async function readTemplates() {
|
|
75
|
+
const dirContents = await fs.readdir(templatesDir);
|
|
76
|
+
const templates = await Promise.all(dirContents
|
|
77
|
+
.filter((d) => !d.startsWith('.') &&
|
|
75
78
|
!d.startsWith('README') &&
|
|
76
|
-
!d.endsWith(
|
|
77
|
-
d !== 'shared')
|
|
79
|
+
!d.endsWith(typeScriptTemplateSuffix) &&
|
|
80
|
+
d !== 'shared')
|
|
81
|
+
.map(async (name) => {
|
|
82
|
+
const tsVariantPath = path.join(templatesDir, `${name}${typeScriptTemplateSuffix}`);
|
|
83
|
+
return {
|
|
84
|
+
name,
|
|
85
|
+
path: path.join(templatesDir, name),
|
|
86
|
+
tsVariantPath: (await fs.pathExists(tsVariantPath))
|
|
87
|
+
? tsVariantPath
|
|
88
|
+
: undefined,
|
|
89
|
+
};
|
|
90
|
+
}));
|
|
78
91
|
// Classic should be first in list!
|
|
79
|
-
return _.sortBy(templates, (t) => t !==
|
|
92
|
+
return _.sortBy(templates, (t) => t.name !== recommendedTemplate);
|
|
80
93
|
}
|
|
81
|
-
function
|
|
82
|
-
function makeNameAndValueChoice(value) {
|
|
83
|
-
const title = value === RecommendedTemplate ? `${value} (recommended)` : value;
|
|
84
|
-
return { title, value };
|
|
85
|
-
}
|
|
86
|
-
return [
|
|
87
|
-
...templates.map((template) => makeNameAndValueChoice(template)),
|
|
88
|
-
makeNameAndValueChoice('Git repository'),
|
|
89
|
-
makeNameAndValueChoice('Local template'),
|
|
90
|
-
];
|
|
91
|
-
}
|
|
92
|
-
function getTypeScriptBaseTemplate(template) {
|
|
93
|
-
if (template.endsWith(TypeScriptTemplateSuffix)) {
|
|
94
|
-
return template.replace(TypeScriptTemplateSuffix, '');
|
|
95
|
-
}
|
|
96
|
-
return undefined;
|
|
97
|
-
}
|
|
98
|
-
async function copyTemplate(templatesDir, template, dest) {
|
|
94
|
+
async function copyTemplate(template, dest, typescript) {
|
|
99
95
|
await fs.copy(path.join(templatesDir, 'shared'), dest);
|
|
100
96
|
// TypeScript variants will copy duplicate resources like CSS & config from
|
|
101
97
|
// base template
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const tsBaseTemplatePath = path.resolve(templatesDir, tsBaseTemplate);
|
|
105
|
-
await fs.copy(tsBaseTemplatePath, dest, {
|
|
98
|
+
if (typescript) {
|
|
99
|
+
await fs.copy(template.path, dest, {
|
|
106
100
|
filter: async (filePath) => (await fs.stat(filePath)).isDirectory() ||
|
|
107
101
|
path.extname(filePath) === '.css' ||
|
|
108
102
|
path.basename(filePath) === 'docusaurus.config.js',
|
|
109
103
|
});
|
|
110
104
|
}
|
|
111
|
-
await fs.copy(
|
|
105
|
+
await fs.copy(typescript ? template.tsVariantPath : template.path, dest, {
|
|
112
106
|
// Symlinks don't exist in published npm packages anymore, so this is only
|
|
113
107
|
// to prevent errors during local testing
|
|
114
108
|
filter: async (filePath) => !(await fs.lstat(filePath)).isSymbolicLink(),
|
|
115
109
|
});
|
|
116
110
|
}
|
|
111
|
+
function createTemplateChoices(templates) {
|
|
112
|
+
function makeNameAndValueChoice(value) {
|
|
113
|
+
if (typeof value === 'string') {
|
|
114
|
+
return { title: value, value };
|
|
115
|
+
}
|
|
116
|
+
const title = value.name === recommendedTemplate
|
|
117
|
+
? `${value.name} (recommended)`
|
|
118
|
+
: value.name;
|
|
119
|
+
return { title, value };
|
|
120
|
+
}
|
|
121
|
+
return [
|
|
122
|
+
...templates.map((template) => makeNameAndValueChoice(template)),
|
|
123
|
+
makeNameAndValueChoice('Git repository'),
|
|
124
|
+
makeNameAndValueChoice('Local template'),
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
function isValidGitRepoUrl(gitRepoUrl) {
|
|
128
|
+
return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item));
|
|
129
|
+
}
|
|
117
130
|
const gitStrategies = ['deep', 'shallow', 'copy', 'custom'];
|
|
118
131
|
async function getGitCommand(gitStrategy) {
|
|
119
132
|
switch (gitStrategy) {
|
|
@@ -121,67 +134,104 @@ async function getGitCommand(gitStrategy) {
|
|
|
121
134
|
case 'copy':
|
|
122
135
|
return 'git clone --recursive --depth 1';
|
|
123
136
|
case 'custom': {
|
|
124
|
-
const { command } = await prompts({
|
|
137
|
+
const { command } = (await prompts({
|
|
125
138
|
type: 'text',
|
|
126
139
|
name: 'command',
|
|
127
140
|
message: 'Write your own git clone command. The repository URL and destination directory will be supplied. E.g. "git clone --depth 10"',
|
|
128
|
-
}
|
|
129
|
-
|
|
141
|
+
}, {
|
|
142
|
+
onCancel() {
|
|
143
|
+
logger.info `Falling back to code=${'git clone'}`;
|
|
144
|
+
},
|
|
145
|
+
}));
|
|
146
|
+
return command ?? 'git clone';
|
|
130
147
|
}
|
|
131
148
|
case 'deep':
|
|
132
149
|
default:
|
|
133
150
|
return 'git clone';
|
|
134
151
|
}
|
|
135
152
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
message: 'What should we name this site?',
|
|
147
|
-
initial: 'website',
|
|
148
|
-
});
|
|
149
|
-
name = prompt.name;
|
|
153
|
+
async function getSiteName(reqName, rootDir) {
|
|
154
|
+
async function validateSiteName(siteName) {
|
|
155
|
+
if (!siteName) {
|
|
156
|
+
return 'A website name is required.';
|
|
157
|
+
}
|
|
158
|
+
const dest = path.resolve(rootDir, siteName);
|
|
159
|
+
if (await fs.pathExists(dest)) {
|
|
160
|
+
return logger.interpolate `Directory already exists at path=${dest}!`;
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
150
163
|
}
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
164
|
+
if (reqName) {
|
|
165
|
+
const res = validateSiteName(reqName);
|
|
166
|
+
if (typeof res === 'string') {
|
|
167
|
+
throw new Error(res);
|
|
168
|
+
}
|
|
169
|
+
return reqName;
|
|
154
170
|
}
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
171
|
+
const { siteName } = (await prompts({
|
|
172
|
+
type: 'text',
|
|
173
|
+
name: 'siteName',
|
|
174
|
+
message: 'What should we name this site?',
|
|
175
|
+
initial: 'website',
|
|
176
|
+
validate: validateSiteName,
|
|
177
|
+
}, {
|
|
178
|
+
onCancel() {
|
|
179
|
+
logger.error('A website name is required.');
|
|
180
|
+
process.exit(1);
|
|
181
|
+
},
|
|
182
|
+
}));
|
|
183
|
+
return siteName;
|
|
184
|
+
}
|
|
185
|
+
async function getSource(reqTemplate, templates, cliOptions) {
|
|
186
|
+
if (reqTemplate) {
|
|
187
|
+
if (isValidGitRepoUrl(reqTemplate)) {
|
|
188
|
+
if (cliOptions.gitStrategy &&
|
|
189
|
+
!gitStrategies.includes(cliOptions.gitStrategy)) {
|
|
190
|
+
logger.error `Invalid git strategy: name=${cliOptions.gitStrategy}. Value must be one of ${gitStrategies.join(', ')}.`;
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
type: 'git',
|
|
195
|
+
url: reqTemplate,
|
|
196
|
+
strategy: cliOptions.gitStrategy ?? 'deep',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
else if (await fs.pathExists(path.resolve(reqTemplate))) {
|
|
200
|
+
return {
|
|
201
|
+
type: 'local',
|
|
202
|
+
path: path.resolve(reqTemplate),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
const template = templates.find((t) => t.name === reqTemplate);
|
|
206
|
+
if (!template) {
|
|
207
|
+
logger.error('Invalid template.');
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
if (cliOptions.typescript && !template.tsVariantPath) {
|
|
211
|
+
logger.error `Template name=${reqTemplate} doesn't provide the TypeScript variant.`;
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
type: 'template',
|
|
216
|
+
template,
|
|
217
|
+
typescript: cliOptions.typescript ?? false,
|
|
218
|
+
};
|
|
159
219
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (!template) {
|
|
164
|
-
const templatePrompt = await prompts({
|
|
220
|
+
const template = cliOptions.gitStrategy
|
|
221
|
+
? 'Git repository'
|
|
222
|
+
: (await prompts({
|
|
165
223
|
type: 'select',
|
|
166
224
|
name: 'template',
|
|
167
225
|
message: 'Select a template below...',
|
|
168
226
|
choices: createTemplateChoices(templates),
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
message: 'This template is available in TypeScript. Do you want to use the TS variant?',
|
|
176
|
-
initial: false,
|
|
177
|
-
});
|
|
178
|
-
useTS = tsPrompt.useTS;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
let gitStrategy = cliOptions.gitStrategy ?? 'deep';
|
|
182
|
-
// If user choose Git repository, we'll prompt for the url.
|
|
227
|
+
}, {
|
|
228
|
+
onCancel() {
|
|
229
|
+
logger.error('A choice is required.');
|
|
230
|
+
process.exit(1);
|
|
231
|
+
},
|
|
232
|
+
})).template;
|
|
183
233
|
if (template === 'Git repository') {
|
|
184
|
-
const
|
|
234
|
+
const { gitRepoUrl } = (await prompts({
|
|
185
235
|
type: 'text',
|
|
186
236
|
name: 'gitRepoUrl',
|
|
187
237
|
validate: (url) => {
|
|
@@ -192,25 +242,44 @@ export default async function init(rootDir, siteName, reqTemplate, cliOptions =
|
|
|
192
242
|
},
|
|
193
243
|
message: logger.interpolate `Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo.
|
|
194
244
|
(e.g: url=${'https://github.com/ownerName/repoName.git'})`,
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
choices: [
|
|
201
|
-
{ title: 'Deep clone: preserve full history', value: 'deep' },
|
|
202
|
-
{ title: 'Shallow clone: clone with --depth=1', value: 'shallow' },
|
|
203
|
-
{
|
|
204
|
-
title: 'Copy: do a shallow clone, but do not create a git repo',
|
|
205
|
-
value: 'copy',
|
|
206
|
-
},
|
|
207
|
-
{ title: 'Custom: enter your custom git clone command', value: 'custom' },
|
|
208
|
-
],
|
|
245
|
+
}, {
|
|
246
|
+
onCancel() {
|
|
247
|
+
logger.error('A git repo URL is required.');
|
|
248
|
+
process.exit(1);
|
|
249
|
+
},
|
|
209
250
|
}));
|
|
210
|
-
|
|
251
|
+
let strategy = cliOptions.gitStrategy;
|
|
252
|
+
if (!strategy) {
|
|
253
|
+
({ strategy } = (await prompts({
|
|
254
|
+
type: 'select',
|
|
255
|
+
name: 'strategy',
|
|
256
|
+
message: 'How should we clone this repo?',
|
|
257
|
+
choices: [
|
|
258
|
+
{ title: 'Deep clone: preserve full history', value: 'deep' },
|
|
259
|
+
{ title: 'Shallow clone: clone with --depth=1', value: 'shallow' },
|
|
260
|
+
{
|
|
261
|
+
title: 'Copy: do a shallow clone, but do not create a git repo',
|
|
262
|
+
value: 'copy',
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
title: 'Custom: enter your custom git clone command',
|
|
266
|
+
value: 'custom',
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
}, {
|
|
270
|
+
onCancel() {
|
|
271
|
+
logger.info `Falling back to name=${'deep'}`;
|
|
272
|
+
},
|
|
273
|
+
})));
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
type: 'git',
|
|
277
|
+
url: gitRepoUrl,
|
|
278
|
+
strategy: strategy ?? 'deep',
|
|
279
|
+
};
|
|
211
280
|
}
|
|
212
281
|
else if (template === 'Local template') {
|
|
213
|
-
const
|
|
282
|
+
const { templateDir } = (await prompts({
|
|
214
283
|
type: 'text',
|
|
215
284
|
name: 'templateDir',
|
|
216
285
|
validate: async (dir) => {
|
|
@@ -224,64 +293,76 @@ export default async function init(rootDir, siteName, reqTemplate, cliOptions =
|
|
|
224
293
|
return logger.red('Please enter a valid path.');
|
|
225
294
|
},
|
|
226
295
|
message: 'Enter a local folder path, relative to the current working directory.',
|
|
227
|
-
}
|
|
228
|
-
|
|
296
|
+
}, {
|
|
297
|
+
onCancel() {
|
|
298
|
+
logger.error('A file path is required.');
|
|
299
|
+
process.exit(1);
|
|
300
|
+
},
|
|
301
|
+
}));
|
|
302
|
+
return {
|
|
303
|
+
type: 'local',
|
|
304
|
+
path: templateDir,
|
|
305
|
+
};
|
|
229
306
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
307
|
+
let useTS = cliOptions.typescript;
|
|
308
|
+
if (!useTS && template.tsVariantPath) {
|
|
309
|
+
({ useTS } = (await prompts({
|
|
310
|
+
type: 'confirm',
|
|
311
|
+
name: 'useTS',
|
|
312
|
+
message: 'This template is available in TypeScript. Do you want to use the TS variant?',
|
|
313
|
+
initial: false,
|
|
314
|
+
})));
|
|
233
315
|
}
|
|
316
|
+
return {
|
|
317
|
+
type: 'template',
|
|
318
|
+
template,
|
|
319
|
+
typescript: useTS ?? false,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
async function updatePkg(pkgPath, obj) {
|
|
323
|
+
const pkg = (await fs.readJSON(pkgPath));
|
|
324
|
+
const newPkg = Object.assign(pkg, obj);
|
|
325
|
+
await fs.outputFile(pkgPath, `${JSON.stringify(newPkg, null, 2)}\n`);
|
|
326
|
+
}
|
|
327
|
+
export default async function init(rootDir, reqName, reqTemplate, cliOptions = {}) {
|
|
328
|
+
const templates = await readTemplates();
|
|
329
|
+
const siteName = await getSiteName(reqName, rootDir);
|
|
330
|
+
const dest = path.resolve(rootDir, siteName);
|
|
331
|
+
const source = await getSource(reqTemplate, templates, cliOptions);
|
|
234
332
|
logger.info('Creating new Docusaurus project...');
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
333
|
+
if (source.type === 'git') {
|
|
334
|
+
const gitCommand = await getGitCommand(source.strategy);
|
|
335
|
+
const gitCloneCommand = `${gitCommand} ${escapeShellArg(source.url)} ${escapeShellArg(dest)}`;
|
|
336
|
+
if (shell.exec(gitCloneCommand).code !== 0) {
|
|
337
|
+
logger.error `Cloning Git template failed!`;
|
|
239
338
|
process.exit(1);
|
|
240
339
|
}
|
|
241
|
-
|
|
242
|
-
if (shell.exec(`${command} ${template} ${dest}`).code !== 0) {
|
|
243
|
-
logger.error `Cloning Git template name=${template} failed!`;
|
|
244
|
-
process.exit(1);
|
|
245
|
-
}
|
|
246
|
-
if (gitStrategy === 'copy') {
|
|
340
|
+
if (source.strategy === 'copy') {
|
|
247
341
|
await fs.remove(path.join(dest, '.git'));
|
|
248
342
|
}
|
|
249
343
|
}
|
|
250
|
-
else if (
|
|
251
|
-
// Docusaurus templates.
|
|
252
|
-
if (useTS) {
|
|
253
|
-
if (!(await hasTS(template))) {
|
|
254
|
-
logger.error `Template name=${template} doesn't provide the TypeScript variant.`;
|
|
255
|
-
process.exit(1);
|
|
256
|
-
}
|
|
257
|
-
template = `${template}${TypeScriptTemplateSuffix}`;
|
|
258
|
-
}
|
|
344
|
+
else if (source.type === 'template') {
|
|
259
345
|
try {
|
|
260
|
-
await copyTemplate(
|
|
346
|
+
await copyTemplate(source.template, dest, source.typescript);
|
|
261
347
|
}
|
|
262
348
|
catch (err) {
|
|
263
|
-
logger.error `Copying Docusaurus template name=${template} failed!`;
|
|
349
|
+
logger.error `Copying Docusaurus template name=${source.template.name} failed!`;
|
|
264
350
|
throw err;
|
|
265
351
|
}
|
|
266
352
|
}
|
|
267
|
-
else
|
|
268
|
-
const templateDir = path.resolve(template);
|
|
353
|
+
else {
|
|
269
354
|
try {
|
|
270
|
-
await fs.copy(
|
|
355
|
+
await fs.copy(source.path, dest);
|
|
271
356
|
}
|
|
272
357
|
catch (err) {
|
|
273
|
-
logger.error `Copying local template path=${
|
|
358
|
+
logger.error `Copying local template path=${source.path} failed!`;
|
|
274
359
|
throw err;
|
|
275
360
|
}
|
|
276
361
|
}
|
|
277
|
-
else {
|
|
278
|
-
logger.error('Invalid template.');
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
362
|
// Update package.json info.
|
|
282
363
|
try {
|
|
283
364
|
await updatePkg(path.join(dest, 'package.json'), {
|
|
284
|
-
name: _.kebabCase(
|
|
365
|
+
name: _.kebabCase(siteName),
|
|
285
366
|
version: '0.0.0',
|
|
286
367
|
private: true,
|
|
287
368
|
});
|
|
@@ -300,15 +381,15 @@ export default async function init(rootDir, siteName, reqTemplate, cliOptions =
|
|
|
300
381
|
}
|
|
301
382
|
// Display the most elegant way to cd.
|
|
302
383
|
const cdpath = path.relative('.', dest);
|
|
303
|
-
const pkgManager = await getPackageManager(
|
|
384
|
+
const pkgManager = await getPackageManager(dest, cliOptions);
|
|
304
385
|
if (!cliOptions.skipInstall) {
|
|
305
386
|
shell.cd(dest);
|
|
306
387
|
logger.info `Installing dependencies with name=${pkgManager}...`;
|
|
307
388
|
if (shell.exec(pkgManager === 'yarn' ? 'yarn' : `${pkgManager} install --color always`, {
|
|
308
389
|
env: {
|
|
309
390
|
...process.env,
|
|
310
|
-
// Force coloring the output, since the command is invoked
|
|
311
|
-
//
|
|
391
|
+
// Force coloring the output, since the command is invoked by
|
|
392
|
+
// shelljs, which is not an interactive shell
|
|
312
393
|
...(supportsColor.stdout ? { FORCE_COLOR: '1' } : {}),
|
|
313
394
|
},
|
|
314
395
|
}).code !== 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-docusaurus",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"description": "Create Docusaurus apps easily.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
15
|
"create-docusaurus": "create-docusaurus",
|
|
16
|
-
"build": "tsc
|
|
17
|
-
"watch": "tsc
|
|
16
|
+
"build": "tsc --build",
|
|
17
|
+
"watch": "tsc --build --watch"
|
|
18
18
|
},
|
|
19
19
|
"bin": "bin/index.js",
|
|
20
20
|
"publishConfig": {
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@docusaurus/logger": "2.0.0-beta.
|
|
25
|
+
"@docusaurus/logger": "2.0.0-beta.21",
|
|
26
|
+
"@docusaurus/utils": "2.0.0-beta.21",
|
|
26
27
|
"commander": "^5.1.0",
|
|
27
28
|
"fs-extra": "^10.1.0",
|
|
28
29
|
"lodash": "^4.17.21",
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
"@types/supports-color": "^8.1.1"
|
|
37
38
|
},
|
|
38
39
|
"engines": {
|
|
39
|
-
"node": ">=14"
|
|
40
|
+
"node": ">=16.14"
|
|
40
41
|
},
|
|
41
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "69ac49fc6909517f13615ee40290c4bd00c39df4"
|
|
42
43
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docusaurus-2-classic-template",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"docusaurus": "docusaurus",
|
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
"write-heading-ids": "docusaurus write-heading-ids"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@docusaurus/core": "2.0.0-beta.
|
|
18
|
-
"@docusaurus/preset-classic": "2.0.0-beta.
|
|
17
|
+
"@docusaurus/core": "2.0.0-beta.21",
|
|
18
|
+
"@docusaurus/preset-classic": "2.0.0-beta.21",
|
|
19
19
|
"@mdx-js/react": "^1.6.22",
|
|
20
20
|
"clsx": "^1.1.1",
|
|
21
|
-
"prism-react-renderer": "^1.3.
|
|
21
|
+
"prism-react-renderer": "^1.3.3",
|
|
22
22
|
"react": "^17.0.2",
|
|
23
23
|
"react-dom": "^17.0.2"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@docusaurus/module-type-aliases": "2.0.0-beta.
|
|
26
|
+
"@docusaurus/module-type-aliases": "2.0.0-beta.21"
|
|
27
27
|
},
|
|
28
28
|
"browserslist": {
|
|
29
29
|
"production": [
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
|
-
import Layout from '@theme/Layout';
|
|
4
3
|
import Link from '@docusaurus/Link';
|
|
5
4
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
6
|
-
import
|
|
5
|
+
import Layout from '@theme/Layout';
|
|
7
6
|
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
|
8
7
|
|
|
8
|
+
import styles from './index.module.css';
|
|
9
|
+
|
|
9
10
|
function HomepageHeader() {
|
|
10
11
|
const {siteConfig} = useDocusaurusContext();
|
|
11
12
|
return (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docusaurus-2-classic-typescript-template",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"docusaurus": "docusaurus",
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
"typecheck": "tsc"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@docusaurus/core": "2.0.0-beta.
|
|
19
|
-
"@docusaurus/preset-classic": "2.0.0-beta.
|
|
18
|
+
"@docusaurus/core": "2.0.0-beta.21",
|
|
19
|
+
"@docusaurus/preset-classic": "2.0.0-beta.21",
|
|
20
20
|
"@mdx-js/react": "^1.6.22",
|
|
21
21
|
"clsx": "^1.1.1",
|
|
22
|
-
"prism-react-renderer": "^1.3.
|
|
22
|
+
"prism-react-renderer": "^1.3.3",
|
|
23
23
|
"react": "^17.0.2",
|
|
24
24
|
"react-dom": "^17.0.2"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@docusaurus/module-type-aliases": "2.0.0-beta.
|
|
27
|
+
"@docusaurus/module-type-aliases": "2.0.0-beta.21",
|
|
28
28
|
"@tsconfig/docusaurus": "^1.0.5",
|
|
29
29
|
"typescript": "^4.6.4"
|
|
30
30
|
},
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
|
-
import Layout from '@theme/Layout';
|
|
4
3
|
import Link from '@docusaurus/Link';
|
|
5
4
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
6
|
-
import
|
|
5
|
+
import Layout from '@theme/Layout';
|
|
7
6
|
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
|
8
7
|
|
|
8
|
+
import styles from './index.module.css';
|
|
9
|
+
|
|
9
10
|
function HomepageHeader() {
|
|
10
11
|
const {siteConfig} = useDocusaurusContext();
|
|
11
12
|
return (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docusaurus-2-facebook-template",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"docusaurus": "docusaurus",
|
|
@@ -18,25 +18,25 @@
|
|
|
18
18
|
"format:diff": "prettier --config .prettierrc --list-different \"**/*.{js,jsx,ts,tsx,md,mdx}\""
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@docusaurus/core": "2.0.0-beta.
|
|
22
|
-
"@docusaurus/preset-classic": "2.0.0-beta.
|
|
21
|
+
"@docusaurus/core": "2.0.0-beta.21",
|
|
22
|
+
"@docusaurus/preset-classic": "2.0.0-beta.21",
|
|
23
23
|
"@mdx-js/react": "^1.6.22",
|
|
24
24
|
"clsx": "^1.1.1",
|
|
25
25
|
"react": "^17.0.2",
|
|
26
26
|
"react-dom": "^17.0.2"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@babel/eslint-parser": "^7.
|
|
30
|
-
"eslint": "^8.
|
|
29
|
+
"@babel/eslint-parser": "^7.18.2",
|
|
30
|
+
"eslint": "^8.16.0",
|
|
31
31
|
"eslint-config-airbnb": "^19.0.4",
|
|
32
32
|
"eslint-config-prettier": "^8.5.0",
|
|
33
33
|
"eslint-plugin-header": "^3.1.1",
|
|
34
34
|
"eslint-plugin-import": "^2.26.0",
|
|
35
35
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
36
|
-
"eslint-plugin-react": "^7.
|
|
36
|
+
"eslint-plugin-react": "^7.30.0",
|
|
37
37
|
"eslint-plugin-react-hooks": "^4.5.0",
|
|
38
38
|
"prettier": "^2.6.2",
|
|
39
|
-
"stylelint": "^14.8.
|
|
39
|
+
"stylelint": "^14.8.5"
|
|
40
40
|
},
|
|
41
41
|
"browserslist": {
|
|
42
42
|
"production": [
|