create-strapi-app 5.9.0 → 5.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1174 -1030
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1170 -994
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -7
package/dist/index.js
CHANGED
|
@@ -1,508 +1,503 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)
|
|
24
|
-
Object.
|
|
25
|
-
const path = require("node:path");
|
|
26
|
-
const os$1 = require("node:os");
|
|
27
|
-
const chalk = require("chalk");
|
|
28
|
-
const commander = require("commander");
|
|
29
|
-
const crypto = require("crypto");
|
|
30
|
-
const fse = require("fs-extra");
|
|
31
|
-
const inquirer = require("inquirer");
|
|
32
|
-
const cloudCli = require("@strapi/cloud-cli");
|
|
33
|
-
const execa = require("execa");
|
|
34
|
-
const url = require("node:url");
|
|
35
|
-
const node_stream = require("node:stream");
|
|
36
|
-
const promises = require("node:stream/promises");
|
|
37
|
-
const tar = require("tar");
|
|
38
|
-
const retry = require("async-retry");
|
|
39
|
-
const os = require("os");
|
|
40
|
-
const _ = require("lodash");
|
|
41
|
-
const path$1 = require("path");
|
|
42
|
-
const semver = require("semver");
|
|
43
|
-
const nodeMachineId = require("node-machine-id");
|
|
44
|
-
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
45
|
-
function _interopNamespace(e) {
|
|
46
|
-
if (e && e.__esModule) return e;
|
|
47
|
-
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var path = require('node:path');
|
|
4
|
+
var os$1 = require('node:os');
|
|
5
|
+
var chalk = require('chalk');
|
|
6
|
+
var commander = require('commander');
|
|
7
|
+
var crypto = require('crypto');
|
|
8
|
+
var fse = require('fs-extra');
|
|
9
|
+
var inquirer = require('inquirer');
|
|
10
|
+
var cloudCli = require('@strapi/cloud-cli');
|
|
11
|
+
var execa = require('execa');
|
|
12
|
+
var url = require('node:url');
|
|
13
|
+
var node_stream = require('node:stream');
|
|
14
|
+
var promises = require('node:stream/promises');
|
|
15
|
+
var tar = require('tar');
|
|
16
|
+
var retry = require('async-retry');
|
|
17
|
+
var os = require('os');
|
|
18
|
+
var _ = require('lodash');
|
|
19
|
+
var path$1 = require('path');
|
|
20
|
+
var semver = require('semver');
|
|
21
|
+
var nodeMachineId = require('node-machine-id');
|
|
22
|
+
|
|
23
|
+
function _interopNamespaceDefault(e) {
|
|
24
|
+
var n = Object.create(null);
|
|
48
25
|
if (e) {
|
|
49
|
-
|
|
50
|
-
if (k !==
|
|
51
|
-
|
|
26
|
+
Object.keys(e).forEach(function (k) {
|
|
27
|
+
if (k !== 'default') {
|
|
28
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
52
29
|
Object.defineProperty(n, k, d.get ? d : {
|
|
53
30
|
enumerable: true,
|
|
54
|
-
get: ()
|
|
31
|
+
get: function () { return e[k]; }
|
|
55
32
|
});
|
|
56
33
|
}
|
|
57
|
-
}
|
|
34
|
+
});
|
|
58
35
|
}
|
|
59
36
|
n.default = e;
|
|
60
37
|
return Object.freeze(n);
|
|
61
38
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const commander__default = /* @__PURE__ */ _interopDefault(commander);
|
|
66
|
-
const crypto__default = /* @__PURE__ */ _interopDefault(crypto);
|
|
67
|
-
const fse__default = /* @__PURE__ */ _interopDefault(fse);
|
|
68
|
-
const inquirer__default = /* @__PURE__ */ _interopDefault(inquirer);
|
|
69
|
-
const execa__default = /* @__PURE__ */ _interopDefault(execa);
|
|
70
|
-
const url__default = /* @__PURE__ */ _interopDefault(url);
|
|
71
|
-
const tar__namespace = /* @__PURE__ */ _interopNamespace(tar);
|
|
72
|
-
const retry__default = /* @__PURE__ */ _interopDefault(retry);
|
|
73
|
-
const os__default = /* @__PURE__ */ _interopDefault(os);
|
|
74
|
-
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
75
|
-
const semver__default = /* @__PURE__ */ _interopDefault(semver);
|
|
39
|
+
|
|
40
|
+
var tar__namespace = /*#__PURE__*/_interopNamespaceDefault(tar);
|
|
41
|
+
|
|
76
42
|
async function directory() {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
43
|
+
const { directory } = await inquirer.prompt([
|
|
44
|
+
{
|
|
45
|
+
type: 'input',
|
|
46
|
+
default: 'my-strapi-project',
|
|
47
|
+
name: 'directory',
|
|
48
|
+
message: 'What is the name of your project?'
|
|
49
|
+
}
|
|
50
|
+
]);
|
|
51
|
+
return directory;
|
|
86
52
|
}
|
|
87
53
|
async function typescript() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
54
|
+
const { useTypescript } = await inquirer.prompt([
|
|
55
|
+
{
|
|
56
|
+
type: 'confirm',
|
|
57
|
+
name: 'useTypescript',
|
|
58
|
+
message: 'Start with Typescript?',
|
|
59
|
+
default: true
|
|
60
|
+
}
|
|
61
|
+
]);
|
|
62
|
+
return useTypescript;
|
|
97
63
|
}
|
|
98
64
|
async function example() {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
65
|
+
const { useExample } = await inquirer.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: 'confirm',
|
|
68
|
+
name: 'useExample',
|
|
69
|
+
message: 'Start with an example structure & data?',
|
|
70
|
+
default: false
|
|
71
|
+
}
|
|
72
|
+
]);
|
|
73
|
+
return useExample;
|
|
108
74
|
}
|
|
109
75
|
async function gitInit() {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
76
|
+
const { gitInit } = await inquirer.prompt([
|
|
77
|
+
{
|
|
78
|
+
type: 'confirm',
|
|
79
|
+
name: 'gitInit',
|
|
80
|
+
message: 'Initialize a git repository?',
|
|
81
|
+
default: true
|
|
82
|
+
}
|
|
83
|
+
]);
|
|
84
|
+
return gitInit;
|
|
119
85
|
}
|
|
120
86
|
async function installDependencies(packageManager) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
87
|
+
const { installDependencies } = await inquirer.prompt([
|
|
88
|
+
{
|
|
89
|
+
type: 'confirm',
|
|
90
|
+
name: 'installDependencies',
|
|
91
|
+
message: `Install dependencies with ${packageManager}?`,
|
|
92
|
+
default: true
|
|
93
|
+
}
|
|
94
|
+
]);
|
|
95
|
+
return installDependencies;
|
|
130
96
|
}
|
|
97
|
+
|
|
98
|
+
// TODO: move styles to API
|
|
131
99
|
const supportedStyles = {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
100
|
+
magentaBright: chalk.magentaBright,
|
|
101
|
+
blueBright: chalk.blueBright,
|
|
102
|
+
yellowBright: chalk.yellowBright,
|
|
103
|
+
green: chalk.green,
|
|
104
|
+
red: chalk.red,
|
|
105
|
+
bold: chalk.bold,
|
|
106
|
+
italic: chalk.italic
|
|
139
107
|
};
|
|
140
108
|
function parseToChalk(template) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
109
|
+
let result = template;
|
|
110
|
+
for (const [color, chalkFunction] of Object.entries(supportedStyles)){
|
|
111
|
+
const regex = new RegExp(`{${color}}(.*?){/${color}}`, 'g');
|
|
112
|
+
result = result.replace(regex, (_, p1)=>chalkFunction(p1.trim()));
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
147
115
|
}
|
|
116
|
+
|
|
148
117
|
function assertCloudError(e) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
118
|
+
if (e.response === undefined) {
|
|
119
|
+
throw Error('Expected CloudError');
|
|
120
|
+
}
|
|
152
121
|
}
|
|
153
122
|
async function handleCloudLogin() {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
logger2.log(parseToChalk(config.projectCreation.introText));
|
|
164
|
-
} catch (e) {
|
|
165
|
-
logger2.debug(e);
|
|
166
|
-
logger2.error(defaultErrorMessage);
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const { userChoice } = await inquirer__default.default.prompt([
|
|
170
|
-
{
|
|
171
|
-
type: "list",
|
|
172
|
-
name: "userChoice",
|
|
173
|
-
message: `Please log in or sign up.`,
|
|
174
|
-
choices: ["Login/Sign up", "Skip"]
|
|
175
|
-
}
|
|
176
|
-
]);
|
|
177
|
-
if (userChoice !== "Skip") {
|
|
178
|
-
const cliContext = {
|
|
179
|
-
logger: logger2,
|
|
180
|
-
cwd: process.cwd()
|
|
181
|
-
};
|
|
123
|
+
const logger = cloudCli.services.createLogger({
|
|
124
|
+
silent: false,
|
|
125
|
+
debug: process.argv.includes('--debug'),
|
|
126
|
+
timestamp: false
|
|
127
|
+
});
|
|
128
|
+
const cloudApiService = await cloudCli.services.cloudApiFactory({
|
|
129
|
+
logger
|
|
130
|
+
});
|
|
131
|
+
const defaultErrorMessage = 'An error occurred while trying to interact with Strapi Cloud. Use strapi deploy command once the project is generated.';
|
|
182
132
|
try {
|
|
183
|
-
|
|
133
|
+
const { data: config } = await cloudApiService.config();
|
|
134
|
+
logger.log(parseToChalk(config.projectCreation.introText));
|
|
184
135
|
} catch (e) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
136
|
+
logger.debug(e);
|
|
137
|
+
logger.error(defaultErrorMessage);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const { userChoice } = await inquirer.prompt([
|
|
141
|
+
{
|
|
142
|
+
type: 'list',
|
|
143
|
+
name: 'userChoice',
|
|
144
|
+
message: `Please log in or sign up.`,
|
|
145
|
+
choices: [
|
|
146
|
+
'Login/Sign up',
|
|
147
|
+
'Skip'
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
]);
|
|
151
|
+
if (userChoice !== 'Skip') {
|
|
152
|
+
const cliContext = {
|
|
153
|
+
logger,
|
|
154
|
+
cwd: process.cwd()
|
|
155
|
+
};
|
|
156
|
+
try {
|
|
157
|
+
await cloudCli.cli.login.action(cliContext);
|
|
158
|
+
} catch (e) {
|
|
159
|
+
logger.debug(e);
|
|
160
|
+
try {
|
|
161
|
+
assertCloudError(e);
|
|
162
|
+
if (e.response.status === 403) {
|
|
163
|
+
const message = typeof e.response.data === 'string' ? e.response.data : 'We are sorry, but we are not able to log you into Strapi Cloud at the moment.';
|
|
164
|
+
logger.warn(message);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
/* empty */ }
|
|
169
|
+
logger.error(defaultErrorMessage);
|
|
192
170
|
}
|
|
193
|
-
} catch (e2) {
|
|
194
|
-
}
|
|
195
|
-
logger2.error(defaultErrorMessage);
|
|
196
171
|
}
|
|
197
|
-
}
|
|
198
172
|
}
|
|
199
|
-
|
|
200
|
-
|
|
173
|
+
|
|
174
|
+
const stripTrailingSlash = (str)=>{
|
|
175
|
+
return str.endsWith('/') ? str.slice(0, -1) : str;
|
|
201
176
|
};
|
|
177
|
+
// Merge template with new project being created
|
|
202
178
|
async function copyTemplate(scope, rootPath) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
).split("/");
|
|
247
|
-
if (t !== void 0 && t !== "tree") {
|
|
248
|
-
throw new Error(`Invalid GitHub template URL: ${template}`);
|
|
249
|
-
}
|
|
250
|
-
if (scope.templateBranch) {
|
|
251
|
-
await retry__default.default(
|
|
252
|
-
() => downloadGithubRepo(rootPath, {
|
|
253
|
-
owner,
|
|
254
|
-
repo,
|
|
255
|
-
branch: scope.templateBranch,
|
|
256
|
-
subPath: scope.templatePath
|
|
257
|
-
}),
|
|
258
|
-
{
|
|
259
|
-
retries: 3,
|
|
260
|
-
onRetry(err, attempt) {
|
|
261
|
-
console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
|
|
262
|
-
}
|
|
179
|
+
const { template } = scope;
|
|
180
|
+
if (!template) {
|
|
181
|
+
throw new Error('Missing template or example app option');
|
|
182
|
+
}
|
|
183
|
+
if (await isOfficialTemplate(template, scope.templateBranch)) {
|
|
184
|
+
await retry(()=>downloadGithubRepo(rootPath, {
|
|
185
|
+
owner: 'strapi',
|
|
186
|
+
repo: 'strapi',
|
|
187
|
+
branch: scope.templateBranch,
|
|
188
|
+
subPath: `templates/${template}`
|
|
189
|
+
}), {
|
|
190
|
+
retries: 3,
|
|
191
|
+
onRetry (err, attempt) {
|
|
192
|
+
console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (isLocalTemplate(template)) {
|
|
198
|
+
const filePath = template.startsWith('file://') ? url.fileURLToPath(template) : template;
|
|
199
|
+
await fse.copy(filePath, rootPath);
|
|
200
|
+
}
|
|
201
|
+
if (isGithubShorthand(template)) {
|
|
202
|
+
const [owner, repo, ...pathSegments] = template.split('/');
|
|
203
|
+
const subPath = pathSegments.length ? pathSegments.join('/') : scope.templatePath;
|
|
204
|
+
await retry(()=>downloadGithubRepo(rootPath, {
|
|
205
|
+
owner,
|
|
206
|
+
repo,
|
|
207
|
+
branch: scope.templateBranch,
|
|
208
|
+
subPath
|
|
209
|
+
}), {
|
|
210
|
+
retries: 3,
|
|
211
|
+
onRetry (err, attempt) {
|
|
212
|
+
console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (isGithubRepo(template)) {
|
|
218
|
+
const url = new URL(template);
|
|
219
|
+
const [owner, repo, t, branch, ...pathSegments] = stripTrailingSlash(url.pathname.slice(1)).split('/');
|
|
220
|
+
if (t !== undefined && t !== 'tree') {
|
|
221
|
+
throw new Error(`Invalid GitHub template URL: ${template}`);
|
|
263
222
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
|
|
223
|
+
if (scope.templateBranch) {
|
|
224
|
+
await retry(()=>downloadGithubRepo(rootPath, {
|
|
225
|
+
owner,
|
|
226
|
+
repo,
|
|
227
|
+
branch: scope.templateBranch,
|
|
228
|
+
subPath: scope.templatePath
|
|
229
|
+
}), {
|
|
230
|
+
retries: 3,
|
|
231
|
+
onRetry (err, attempt) {
|
|
232
|
+
console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
278
236
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
237
|
+
await retry(()=>downloadGithubRepo(rootPath, {
|
|
238
|
+
owner,
|
|
239
|
+
repo,
|
|
240
|
+
branch: decodeURIComponent(branch) ?? scope.templateBranch,
|
|
241
|
+
subPath: pathSegments.length ? decodeURIComponent(pathSegments.join('/')) : scope.templatePath
|
|
242
|
+
}), {
|
|
243
|
+
retries: 3,
|
|
244
|
+
onRetry (err, attempt) {
|
|
245
|
+
console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
throw new Error(`Invalid GitHub template URL: ${template}`);
|
|
249
|
+
}
|
|
283
250
|
}
|
|
284
251
|
async function downloadGithubRepo(rootPath, { owner, repo, branch, subPath }) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (filePath) {
|
|
317
|
-
return path2.split("/").slice(1).join("/").startsWith(filePath);
|
|
252
|
+
const filePath = subPath ? subPath.split('/').join(path.posix.sep) : null;
|
|
253
|
+
let checkContentUrl = `https://api.github.com/repos/${owner}/${repo}/contents`;
|
|
254
|
+
if (filePath) {
|
|
255
|
+
checkContentUrl = `${checkContentUrl}/${filePath}`;
|
|
256
|
+
}
|
|
257
|
+
if (branch) {
|
|
258
|
+
checkContentUrl = `${checkContentUrl}?ref=${branch}`;
|
|
259
|
+
}
|
|
260
|
+
const checkRes = await fetch(checkContentUrl, {
|
|
261
|
+
method: 'HEAD'
|
|
262
|
+
});
|
|
263
|
+
if (checkRes.status !== 200) {
|
|
264
|
+
throw new Error(`Could not find a template at https://github.com/${owner}/${repo}${branch ? ` on branch ${branch}` : ''}${filePath ? ` at path ${filePath}` : ''}`);
|
|
265
|
+
}
|
|
266
|
+
let url = `https://api.github.com/repos/${owner}/${repo}/tarball`;
|
|
267
|
+
if (branch) {
|
|
268
|
+
url = `${url}/${branch}`;
|
|
269
|
+
}
|
|
270
|
+
const res = await fetch(url);
|
|
271
|
+
if (!res.body) {
|
|
272
|
+
throw new Error(`Failed to download ${url}`);
|
|
273
|
+
}
|
|
274
|
+
await promises.pipeline(// @ts-expect-error - Readable is not a valid source
|
|
275
|
+
node_stream.Readable.fromWeb(res.body), tar__namespace.x({
|
|
276
|
+
cwd: rootPath,
|
|
277
|
+
strip: filePath ? filePath.split('/').length + 1 : 1,
|
|
278
|
+
filter (path) {
|
|
279
|
+
if (filePath) {
|
|
280
|
+
return path.split('/').slice(1).join('/').startsWith(filePath);
|
|
281
|
+
}
|
|
282
|
+
return true;
|
|
318
283
|
}
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
})
|
|
322
|
-
);
|
|
284
|
+
}));
|
|
323
285
|
}
|
|
324
286
|
function isLocalTemplate(template) {
|
|
325
|
-
|
|
287
|
+
return template.startsWith('file://') || fse.existsSync(path.isAbsolute(template) ? template : path.resolve(process.cwd(), template));
|
|
326
288
|
}
|
|
327
289
|
function isGithubShorthand(value) {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
290
|
+
if (isValidUrl(value)) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
return /^[\w-]+\/[\w-.]+(\/[\w-.]+)*$/.test(value);
|
|
332
294
|
}
|
|
333
295
|
function isGithubRepo(value) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
296
|
+
try {
|
|
297
|
+
const url = new URL(value);
|
|
298
|
+
return url.origin === 'https://github.com';
|
|
299
|
+
} catch {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
340
302
|
}
|
|
341
303
|
function isValidUrl(value) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
304
|
+
try {
|
|
305
|
+
// eslint-disable-next-line no-new
|
|
306
|
+
new URL(value);
|
|
307
|
+
return true;
|
|
308
|
+
} catch {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
348
311
|
}
|
|
312
|
+
const OFFICIAL_NAME_REGEX = /^[a-zA-Z]*$/;
|
|
349
313
|
async function isOfficialTemplate(template, branch) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
return res.status === 200;
|
|
314
|
+
if (isValidUrl(template) || !OFFICIAL_NAME_REGEX.test(template)) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
const res = await fetch(`https://api.github.com/repos/strapi/strapi/contents/templates/${template}?${branch ? `ref=${branch}` : ''}`, {
|
|
318
|
+
method: 'HEAD'
|
|
319
|
+
});
|
|
320
|
+
return res.status === 200;
|
|
358
321
|
}
|
|
322
|
+
|
|
359
323
|
async function isInGitRepository(rootDir) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
324
|
+
try {
|
|
325
|
+
await execa('git', [
|
|
326
|
+
'rev-parse',
|
|
327
|
+
'--is-inside-work-tree'
|
|
328
|
+
], {
|
|
329
|
+
stdio: 'ignore',
|
|
330
|
+
cwd: rootDir
|
|
331
|
+
});
|
|
332
|
+
return true;
|
|
333
|
+
} catch (_) {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
366
336
|
}
|
|
367
337
|
async function isInMercurialRepository(rootDir) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
338
|
+
try {
|
|
339
|
+
await execa('hg', [
|
|
340
|
+
'-cwd',
|
|
341
|
+
'.',
|
|
342
|
+
'root'
|
|
343
|
+
], {
|
|
344
|
+
stdio: 'ignore',
|
|
345
|
+
cwd: rootDir
|
|
346
|
+
});
|
|
347
|
+
return true;
|
|
348
|
+
} catch (_) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
374
351
|
}
|
|
375
352
|
async function tryGitInit(rootDir) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
353
|
+
try {
|
|
354
|
+
await execa('git', [
|
|
355
|
+
'--version'
|
|
356
|
+
], {
|
|
357
|
+
stdio: 'ignore'
|
|
358
|
+
});
|
|
359
|
+
if (await isInGitRepository(rootDir) || await isInMercurialRepository(rootDir)) {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
await execa('git', [
|
|
363
|
+
'init'
|
|
364
|
+
], {
|
|
365
|
+
stdio: 'ignore',
|
|
366
|
+
cwd: rootDir
|
|
367
|
+
});
|
|
368
|
+
await execa('git', [
|
|
369
|
+
'add',
|
|
370
|
+
'.'
|
|
371
|
+
], {
|
|
372
|
+
stdio: 'ignore',
|
|
373
|
+
cwd: rootDir
|
|
374
|
+
});
|
|
375
|
+
await execa('git', [
|
|
376
|
+
'commit',
|
|
377
|
+
'-m',
|
|
378
|
+
'Initial commit from Strapi'
|
|
379
|
+
], {
|
|
380
|
+
stdio: 'ignore',
|
|
381
|
+
cwd: rootDir
|
|
382
|
+
});
|
|
383
|
+
return true;
|
|
384
|
+
} catch (e) {
|
|
385
|
+
console.error('Error while trying to initialize git:', e);
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
392
388
|
}
|
|
389
|
+
|
|
390
|
+
// Add properties from the package.json strapi key in the metadata
|
|
393
391
|
function addPackageJsonStrapiMetadata(metadata, scope) {
|
|
394
|
-
|
|
395
|
-
|
|
392
|
+
const { packageJsonStrapi = {} } = scope;
|
|
393
|
+
return _.defaults(metadata, packageJsonStrapi);
|
|
396
394
|
}
|
|
397
|
-
const boolToString = (value)
|
|
398
|
-
const getProperties = (scope, error)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
groupProperties: addPackageJsonStrapiMetadata(groupProperties, scope)
|
|
430
|
-
};
|
|
395
|
+
const boolToString = (value)=>(value === true).toString();
|
|
396
|
+
const getProperties = (scope, error)=>{
|
|
397
|
+
const eventProperties = {
|
|
398
|
+
error: typeof error === 'string' ? error : error && error.message
|
|
399
|
+
};
|
|
400
|
+
const userProperties = {
|
|
401
|
+
os: os.type(),
|
|
402
|
+
osPlatform: os.platform(),
|
|
403
|
+
osArch: os.arch(),
|
|
404
|
+
osRelease: os.release(),
|
|
405
|
+
nodeVersion: process.versions.node
|
|
406
|
+
};
|
|
407
|
+
const groupProperties = {
|
|
408
|
+
version: scope.strapiVersion,
|
|
409
|
+
docker: scope.docker,
|
|
410
|
+
useYarn: scope.packageManager === 'yarn',
|
|
411
|
+
packageManager: scope.packageManager,
|
|
412
|
+
/** @deprecated */ useTypescriptOnServer: boolToString(scope.useTypescript),
|
|
413
|
+
/** @deprecated */ useTypescriptOnAdmin: boolToString(scope.useTypescript),
|
|
414
|
+
useTypescript: boolToString(scope.useTypescript),
|
|
415
|
+
isHostedOnStrapiCloud: process.env.STRAPI_HOSTING === 'strapi.cloud',
|
|
416
|
+
noRun: boolToString(scope.runApp),
|
|
417
|
+
projectId: scope.uuid,
|
|
418
|
+
useExample: boolToString(scope.useExample),
|
|
419
|
+
gitInit: boolToString(scope.gitInit),
|
|
420
|
+
installDependencies: boolToString(scope.installDependencies)
|
|
421
|
+
};
|
|
422
|
+
return {
|
|
423
|
+
eventProperties,
|
|
424
|
+
userProperties,
|
|
425
|
+
groupProperties: addPackageJsonStrapiMetadata(groupProperties, scope)
|
|
426
|
+
};
|
|
431
427
|
};
|
|
432
428
|
function trackEvent(event, payload) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
})
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
429
|
+
if (process.env.NODE_ENV === 'test') {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
return fetch('https://analytics.strapi.io/api/v2/track', {
|
|
434
|
+
method: 'POST',
|
|
435
|
+
body: JSON.stringify({
|
|
436
|
+
event,
|
|
437
|
+
...payload
|
|
438
|
+
}),
|
|
439
|
+
signal: AbortSignal.timeout(1000),
|
|
440
|
+
headers: {
|
|
441
|
+
'Content-Type': 'application/json',
|
|
442
|
+
'X-Strapi-Event': event
|
|
443
|
+
}
|
|
444
|
+
}).catch(()=>{});
|
|
445
|
+
} catch (err) {
|
|
446
|
+
/** ignore errors */ return Promise.resolve();
|
|
447
|
+
}
|
|
453
448
|
}
|
|
454
449
|
async function trackError({ scope, error }) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
450
|
+
const properties = getProperties(scope, error);
|
|
451
|
+
try {
|
|
452
|
+
return await trackEvent('didNotCreateProject', {
|
|
453
|
+
deviceId: scope.deviceId,
|
|
454
|
+
...properties
|
|
455
|
+
});
|
|
456
|
+
} catch (err) {
|
|
457
|
+
/** ignore errors */ return Promise.resolve();
|
|
458
|
+
}
|
|
464
459
|
}
|
|
465
|
-
async function trackUsage({
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
});
|
|
476
|
-
} catch (err) {
|
|
477
|
-
return Promise.resolve();
|
|
478
|
-
}
|
|
460
|
+
async function trackUsage({ event, scope, error }) {
|
|
461
|
+
const properties = getProperties(scope, error);
|
|
462
|
+
try {
|
|
463
|
+
return await trackEvent(event, {
|
|
464
|
+
deviceId: scope.deviceId,
|
|
465
|
+
...properties
|
|
466
|
+
});
|
|
467
|
+
} catch (err) {
|
|
468
|
+
/** ignore errors */ return Promise.resolve();
|
|
469
|
+
}
|
|
479
470
|
}
|
|
471
|
+
|
|
480
472
|
const engines = {
|
|
481
|
-
|
|
482
|
-
|
|
473
|
+
node: '>=18.0.0 <=22.x.x',
|
|
474
|
+
npm: '>=6.0.0'
|
|
483
475
|
};
|
|
476
|
+
|
|
484
477
|
async function createPackageJSON(scope) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
478
|
+
const { sortPackageJson } = await import('sort-package-json');
|
|
479
|
+
const pkgJSONPath = path$1.join(scope.rootPath, 'package.json');
|
|
480
|
+
const existingPkg = await fse.readJSON(pkgJSONPath).catch(()=>({}));
|
|
481
|
+
const pkg = {
|
|
482
|
+
name: _.kebabCase(scope.name),
|
|
483
|
+
private: true,
|
|
484
|
+
version: '0.1.0',
|
|
485
|
+
description: 'A Strapi application',
|
|
486
|
+
devDependencies: scope.devDependencies ?? {},
|
|
487
|
+
dependencies: scope.dependencies ?? {},
|
|
488
|
+
strapi: {
|
|
489
|
+
...scope.packageJsonStrapi ?? {},
|
|
490
|
+
uuid: scope.uuid
|
|
491
|
+
},
|
|
492
|
+
engines
|
|
493
|
+
};
|
|
494
|
+
// copy templates
|
|
495
|
+
await fse.writeJSON(pkgJSONPath, sortPackageJson(_.merge(existingPkg, pkg)), {
|
|
496
|
+
spaces: 2
|
|
497
|
+
});
|
|
504
498
|
}
|
|
505
|
-
|
|
499
|
+
|
|
500
|
+
const generateASecret = ()=>crypto.randomBytes(16).toString('base64');
|
|
506
501
|
const envTmpl = `
|
|
507
502
|
# Server
|
|
508
503
|
HOST=0.0.0.0
|
|
@@ -525,77 +520,74 @@ DATABASE_SSL=<%= database.connection.ssl %>
|
|
|
525
520
|
DATABASE_FILENAME=<%= database.connection.filename %>
|
|
526
521
|
`;
|
|
527
522
|
function generateDotEnv(scope) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
523
|
+
const compile = _.template(envTmpl);
|
|
524
|
+
return compile({
|
|
525
|
+
appKeys: new Array(4).fill(null).map(generateASecret).join(','),
|
|
526
|
+
apiTokenSalt: generateASecret(),
|
|
527
|
+
transferTokenSalt: generateASecret(),
|
|
528
|
+
adminJwtToken: generateASecret(),
|
|
529
|
+
database: {
|
|
530
|
+
client: scope.database.client,
|
|
531
|
+
connection: {
|
|
532
|
+
...scope.database.connection,
|
|
533
|
+
ssl: scope.database.connection?.ssl || false
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
});
|
|
542
537
|
}
|
|
538
|
+
|
|
543
539
|
function isStderrError(error) {
|
|
544
|
-
|
|
540
|
+
return typeof error === 'object' && error !== null && 'stderr' in error && typeof error.stderr === 'string';
|
|
545
541
|
}
|
|
542
|
+
|
|
546
543
|
const MAX_PREFIX_LENGTH = 8;
|
|
547
|
-
const badge = (text, bgColor, textColor =
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
544
|
+
const badge = (text, bgColor, textColor = chalk.black)=>{
|
|
545
|
+
const wrappedText = ` ${text} `;
|
|
546
|
+
const repeat = Math.max(0, MAX_PREFIX_LENGTH - wrappedText.length);
|
|
547
|
+
return ' '.repeat(repeat) + bgColor(textColor(wrappedText));
|
|
551
548
|
};
|
|
552
|
-
const textIndent = (text, indentFirst = true, indent = MAX_PREFIX_LENGTH + 2)
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
549
|
+
const textIndent = (text, indentFirst = true, indent = MAX_PREFIX_LENGTH + 2)=>{
|
|
550
|
+
const parts = Array.isArray(text) ? text : [
|
|
551
|
+
text
|
|
552
|
+
];
|
|
553
|
+
return parts.map((part, i)=>{
|
|
554
|
+
if (i === 0 && !indentFirst) {
|
|
555
|
+
return part;
|
|
556
|
+
}
|
|
557
|
+
return ' '.repeat(indent) + part;
|
|
558
|
+
}).join('\n');
|
|
560
559
|
};
|
|
561
560
|
const logger = {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
`);
|
|
591
|
-
},
|
|
592
|
-
warn(message) {
|
|
593
|
-
const prefix = badge("Warn", chalk__default.default.bgYellow);
|
|
594
|
-
console.warn(`
|
|
595
|
-
${prefix} ${textIndent(message, false)}
|
|
596
|
-
`);
|
|
597
|
-
}
|
|
561
|
+
log (message) {
|
|
562
|
+
console.log(textIndent(message));
|
|
563
|
+
},
|
|
564
|
+
title (title, message) {
|
|
565
|
+
const prefix = badge(title, chalk.bgBlueBright);
|
|
566
|
+
console.log(`\n${prefix} ${message}`);
|
|
567
|
+
},
|
|
568
|
+
info (message) {
|
|
569
|
+
console.log(`${' '.repeat(7)}${chalk.cyan('●')} ${message}`);
|
|
570
|
+
},
|
|
571
|
+
success (message) {
|
|
572
|
+
console.log(`\n${' '.repeat(7)}${chalk.green('✓')} ${chalk.green(message)}`);
|
|
573
|
+
},
|
|
574
|
+
fatal (message) {
|
|
575
|
+
const prefix = badge('Error', chalk.bgRed);
|
|
576
|
+
if (message) {
|
|
577
|
+
console.error(`\n${prefix} ${textIndent(message, false)}\n`);
|
|
578
|
+
}
|
|
579
|
+
process.exit(1);
|
|
580
|
+
},
|
|
581
|
+
error (message) {
|
|
582
|
+
const prefix = badge('Error', chalk.bgRed);
|
|
583
|
+
console.error(`\n${prefix} ${textIndent(message, false)}\n`);
|
|
584
|
+
},
|
|
585
|
+
warn (message) {
|
|
586
|
+
const prefix = badge('Warn', chalk.bgYellow);
|
|
587
|
+
console.warn(`\n${prefix} ${textIndent(message, false)}\n`);
|
|
588
|
+
}
|
|
598
589
|
};
|
|
590
|
+
|
|
599
591
|
const baseGitIgnore = `
|
|
600
592
|
############################
|
|
601
593
|
# OS X
|
|
@@ -730,591 +722,743 @@ build
|
|
|
730
722
|
.strapi-cloud.json
|
|
731
723
|
`;
|
|
732
724
|
const gitIgnore = baseGitIgnore.trim();
|
|
733
|
-
|
|
725
|
+
|
|
726
|
+
const installArguments = [
|
|
727
|
+
'install'
|
|
728
|
+
];
|
|
729
|
+
// Set command line options for specific package managers, with full semver ranges
|
|
734
730
|
const installArgumentsMap = {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
731
|
+
npm: {
|
|
732
|
+
'*': [
|
|
733
|
+
'--legacy-peer-deps'
|
|
734
|
+
]
|
|
735
|
+
},
|
|
736
|
+
yarn: {
|
|
737
|
+
'<4': [
|
|
738
|
+
'--network-timeout',
|
|
739
|
+
'1000000'
|
|
740
|
+
],
|
|
741
|
+
'*': []
|
|
742
|
+
},
|
|
743
|
+
pnpm: {
|
|
744
|
+
'*': []
|
|
745
|
+
}
|
|
745
746
|
};
|
|
747
|
+
// Set environment variables for specific package managers, with full semver ranges
|
|
746
748
|
const installEnvMap = {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
try {
|
|
760
|
-
const { stdout } = await execa__default.default(packageManager, ["--version"], options);
|
|
761
|
-
return stdout.trim();
|
|
762
|
-
} catch (err) {
|
|
763
|
-
throw new Error(`Error detecting ${packageManager} version: ${err}`);
|
|
764
|
-
}
|
|
749
|
+
yarn: {
|
|
750
|
+
'>=4': {
|
|
751
|
+
YARN_HTTP_TIMEOUT: '1000000'
|
|
752
|
+
},
|
|
753
|
+
'*': {}
|
|
754
|
+
},
|
|
755
|
+
npm: {
|
|
756
|
+
'*': {}
|
|
757
|
+
},
|
|
758
|
+
pnpm: {
|
|
759
|
+
'*': {}
|
|
760
|
+
}
|
|
765
761
|
};
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
762
|
+
/**
|
|
763
|
+
* Retrieves the version of the specified package manager.
|
|
764
|
+
*
|
|
765
|
+
* Executes the package manager's `--version` command to determine its version.
|
|
766
|
+
*
|
|
767
|
+
* @param packageManager - The name of the package manager (e.g., 'npm', 'yarn', 'pnpm').
|
|
768
|
+
* @param options - Optional execution options to pass to `execa`.
|
|
769
|
+
* @returns A promise that resolves to the trimmed version string of the package manager.
|
|
770
|
+
*
|
|
771
|
+
* @throws Will throw an error if the package manager's version cannot be determined.
|
|
772
|
+
*/ const getPackageManagerVersion = async (packageManager, options)=>{
|
|
773
|
+
try {
|
|
774
|
+
const { stdout } = await execa(packageManager, [
|
|
775
|
+
'--version'
|
|
776
|
+
], options);
|
|
777
|
+
return stdout.trim();
|
|
778
|
+
} catch (err) {
|
|
779
|
+
throw new Error(`Error detecting ${packageManager} version: ${err}`);
|
|
770
780
|
}
|
|
771
|
-
|
|
772
|
-
|
|
781
|
+
};
|
|
782
|
+
/**
|
|
783
|
+
* Merges all matching semver ranges using a custom merge function.
|
|
784
|
+
*
|
|
785
|
+
* Iterates over the `versionMap`, checking if the provided `version` satisfies each semver range.
|
|
786
|
+
* If it does, the corresponding value is merged using the provided `mergeFn`.
|
|
787
|
+
* The merging starts with the value associated with the wildcard '*' key.
|
|
788
|
+
*
|
|
789
|
+
* @param version - The package manager version to check against the ranges.
|
|
790
|
+
* @param versionMap - A map of semver ranges to corresponding values (arguments or environment variables).
|
|
791
|
+
* @param mergeFn - A function that defines how to merge two values (accumulated and current).
|
|
792
|
+
* @returns The merged result of all matching ranges.
|
|
793
|
+
*/ function mergeMatchingVersionRanges(version, versionMap, mergeFn) {
|
|
794
|
+
return Object.keys(versionMap).reduce((acc, range)=>{
|
|
795
|
+
if (semver.satisfies(version, range) || range === '*') {
|
|
796
|
+
return mergeFn(acc, versionMap[range]);
|
|
797
|
+
}
|
|
798
|
+
return acc;
|
|
799
|
+
}, versionMap['*']); // Start with the wildcard entry
|
|
773
800
|
}
|
|
774
801
|
function mergeArguments(acc, curr) {
|
|
775
|
-
|
|
802
|
+
return [
|
|
803
|
+
...acc,
|
|
804
|
+
...curr
|
|
805
|
+
];
|
|
776
806
|
}
|
|
777
807
|
function mergeEnvVars(acc, curr) {
|
|
778
|
-
|
|
808
|
+
return {
|
|
809
|
+
...acc,
|
|
810
|
+
...curr
|
|
811
|
+
};
|
|
779
812
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
813
|
+
/**
|
|
814
|
+
* Retrieves the install arguments and environment variables for a given package manager.
|
|
815
|
+
*
|
|
816
|
+
* This function determines the correct command line arguments and environment variables
|
|
817
|
+
* based on the package manager's version. It uses predefined semver ranges to match
|
|
818
|
+
* the package manager's version and merges all applicable settings.
|
|
819
|
+
*
|
|
820
|
+
* The arguments and environment variables are sourced from:
|
|
821
|
+
* - `installArgumentsMap` for command line arguments.
|
|
822
|
+
* - `installEnvMap` for environment variables.
|
|
823
|
+
*
|
|
824
|
+
* The function ensures that all matching semver ranges are considered and merged appropriately.
|
|
825
|
+
* It always includes the base `installArguments` (e.g., `['install']`) and applies any additional
|
|
826
|
+
* arguments or environment variables as defined by the matched version ranges.
|
|
827
|
+
*
|
|
828
|
+
* @param packageManager - The name of the package manager (e.g., 'npm', 'yarn', 'pnpm').
|
|
829
|
+
* @param options - Optional execution options to pass to `execa`.
|
|
830
|
+
* @returns An object containing:
|
|
831
|
+
* - `cmdArgs`: The full array of install arguments for the given package manager and version.
|
|
832
|
+
* - `envArgs`: The merged environment variables applicable to the package manager and version.
|
|
833
|
+
*
|
|
834
|
+
* @throws Will throw an error if the package manager version cannot be determined.
|
|
835
|
+
*/ const getInstallArgs = async (packageManager, options)=>{
|
|
836
|
+
const packageManagerVersion = await getPackageManagerVersion(packageManager, options);
|
|
837
|
+
// Get environment variables
|
|
838
|
+
const envMap = installEnvMap[packageManager];
|
|
839
|
+
const envArgs = packageManagerVersion ? mergeMatchingVersionRanges(packageManagerVersion, envMap, mergeEnvVars) : envMap['*'];
|
|
840
|
+
// Get install arguments
|
|
841
|
+
const argsMap = installArgumentsMap[packageManager];
|
|
842
|
+
const cmdArgs = packageManagerVersion ? mergeMatchingVersionRanges(packageManagerVersion, argsMap, mergeArguments) : argsMap['*'];
|
|
843
|
+
return {
|
|
844
|
+
envArgs,
|
|
845
|
+
cmdArgs: [
|
|
846
|
+
...installArguments,
|
|
847
|
+
...cmdArgs
|
|
848
|
+
],
|
|
849
|
+
version: packageManagerVersion
|
|
850
|
+
};
|
|
787
851
|
};
|
|
852
|
+
|
|
788
853
|
async function createStrapi(scope) {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
854
|
+
const { rootPath } = scope;
|
|
855
|
+
try {
|
|
856
|
+
await fse.ensureDir(rootPath);
|
|
857
|
+
await createApp(scope);
|
|
858
|
+
} catch (error) {
|
|
859
|
+
await fse.remove(rootPath);
|
|
860
|
+
throw error;
|
|
861
|
+
}
|
|
797
862
|
}
|
|
798
863
|
async function createApp(scope) {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
await trackUsage({ event: "didChooseQuickstart", scope });
|
|
817
|
-
}
|
|
818
|
-
if (!template) {
|
|
819
|
-
let templateName = useExample ? "example" : "vanilla";
|
|
820
|
-
if (!useTypescript) {
|
|
821
|
-
templateName = `${templateName}-js`;
|
|
864
|
+
const { rootPath, useTypescript, useExample, installDependencies, isQuickstart, template, packageManager, gitInit, runApp } = scope;
|
|
865
|
+
const shouldRunSeed = useExample && installDependencies;
|
|
866
|
+
await trackUsage({
|
|
867
|
+
event: 'willCreateProject',
|
|
868
|
+
scope
|
|
869
|
+
});
|
|
870
|
+
logger.title('Strapi', `Creating a new application at ${chalk.green(rootPath)}`);
|
|
871
|
+
if (!isQuickstart) {
|
|
872
|
+
await trackUsage({
|
|
873
|
+
event: 'didChooseCustomDatabase',
|
|
874
|
+
scope
|
|
875
|
+
});
|
|
876
|
+
} else {
|
|
877
|
+
await trackUsage({
|
|
878
|
+
event: 'didChooseQuickstart',
|
|
879
|
+
scope
|
|
880
|
+
});
|
|
822
881
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
882
|
+
if (!template) {
|
|
883
|
+
let templateName = useExample ? 'example' : 'vanilla';
|
|
884
|
+
if (!useTypescript) {
|
|
885
|
+
templateName = `${templateName}-js`;
|
|
886
|
+
}
|
|
887
|
+
const internalTemplatePath = path.join(__dirname, '../templates', templateName);
|
|
888
|
+
if (await fse.exists(internalTemplatePath)) {
|
|
889
|
+
await fse.copy(internalTemplatePath, rootPath);
|
|
890
|
+
}
|
|
891
|
+
} else {
|
|
892
|
+
try {
|
|
893
|
+
logger.info(`${chalk.cyan('Installing template')} ${template}`);
|
|
894
|
+
await copyTemplate(scope, rootPath);
|
|
895
|
+
logger.success('Template copied successfully.');
|
|
896
|
+
} catch (error) {
|
|
897
|
+
if (error instanceof Error) {
|
|
898
|
+
logger.fatal(`Template installation failed: ${error.message}`);
|
|
899
|
+
}
|
|
900
|
+
throw error;
|
|
901
|
+
}
|
|
902
|
+
if (!fse.existsSync(path.join(rootPath, 'package.json'))) {
|
|
903
|
+
logger.fatal(`Missing ${chalk.bold('package.json')} in template`);
|
|
904
|
+
}
|
|
826
905
|
}
|
|
827
|
-
|
|
906
|
+
await trackUsage({
|
|
907
|
+
event: 'didCopyProjectFiles',
|
|
908
|
+
scope
|
|
909
|
+
});
|
|
828
910
|
try {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
911
|
+
await createPackageJSON(scope);
|
|
912
|
+
await trackUsage({
|
|
913
|
+
event: 'didWritePackageJSON',
|
|
914
|
+
scope
|
|
915
|
+
});
|
|
916
|
+
// ensure node_modules is created
|
|
917
|
+
await fse.ensureDir(path.join(rootPath, 'node_modules'));
|
|
918
|
+
// create config/database
|
|
919
|
+
await fse.writeFile(path.join(rootPath, '.env'), generateDotEnv(scope));
|
|
920
|
+
await trackUsage({
|
|
921
|
+
event: 'didCopyConfigurationFiles',
|
|
922
|
+
scope
|
|
923
|
+
});
|
|
924
|
+
} catch (err) {
|
|
925
|
+
await fse.remove(rootPath);
|
|
926
|
+
throw err;
|
|
837
927
|
}
|
|
838
|
-
if (
|
|
839
|
-
|
|
928
|
+
if (installDependencies) {
|
|
929
|
+
try {
|
|
930
|
+
logger.title('deps', `Installing dependencies with ${chalk.cyan(packageManager)}`);
|
|
931
|
+
await trackUsage({
|
|
932
|
+
event: 'willInstallProjectDependencies',
|
|
933
|
+
scope
|
|
934
|
+
});
|
|
935
|
+
await runInstall(scope);
|
|
936
|
+
await trackUsage({
|
|
937
|
+
event: 'didInstallProjectDependencies',
|
|
938
|
+
scope
|
|
939
|
+
});
|
|
940
|
+
logger.success(`Dependencies installed`);
|
|
941
|
+
} catch (error) {
|
|
942
|
+
const stderr = isStderrError(error) ? error.stderr : '';
|
|
943
|
+
await trackUsage({
|
|
944
|
+
event: 'didNotInstallProjectDependencies',
|
|
945
|
+
scope,
|
|
946
|
+
error: stderr.slice(-1024)
|
|
947
|
+
});
|
|
948
|
+
logger.fatal([
|
|
949
|
+
chalk.bold('Oh, it seems that you encountered an error while installing dependencies in your project'),
|
|
950
|
+
'',
|
|
951
|
+
`Don't give up, your project was created correctly`,
|
|
952
|
+
'',
|
|
953
|
+
`Fix the issues mentioned in the installation errors and try to run the following command:`,
|
|
954
|
+
'',
|
|
955
|
+
`cd ${chalk.green(rootPath)} && ${chalk.cyan(packageManager)} install`
|
|
956
|
+
]);
|
|
957
|
+
}
|
|
840
958
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
await
|
|
847
|
-
|
|
848
|
-
await trackUsage({ event: "didCopyConfigurationFiles", scope });
|
|
849
|
-
} catch (err) {
|
|
850
|
-
await fse__default.default.remove(rootPath);
|
|
851
|
-
throw err;
|
|
852
|
-
}
|
|
853
|
-
if (installDependencies2) {
|
|
854
|
-
try {
|
|
855
|
-
logger.title("deps", `Installing dependencies with ${chalk__default.default.cyan(packageManager)}`);
|
|
856
|
-
await trackUsage({ event: "willInstallProjectDependencies", scope });
|
|
857
|
-
await runInstall(scope);
|
|
858
|
-
await trackUsage({ event: "didInstallProjectDependencies", scope });
|
|
859
|
-
logger.success(`Dependencies installed`);
|
|
860
|
-
} catch (error) {
|
|
861
|
-
const stderr = isStderrError(error) ? error.stderr : "";
|
|
862
|
-
await trackUsage({
|
|
863
|
-
event: "didNotInstallProjectDependencies",
|
|
864
|
-
scope,
|
|
865
|
-
error: stderr.slice(-1024)
|
|
866
|
-
});
|
|
867
|
-
logger.fatal([
|
|
868
|
-
chalk__default.default.bold(
|
|
869
|
-
"Oh, it seems that you encountered an error while installing dependencies in your project"
|
|
870
|
-
),
|
|
871
|
-
"",
|
|
872
|
-
`Don't give up, your project was created correctly`,
|
|
873
|
-
"",
|
|
874
|
-
`Fix the issues mentioned in the installation errors and try to run the following command:`,
|
|
875
|
-
"",
|
|
876
|
-
`cd ${chalk__default.default.green(rootPath)} && ${chalk__default.default.cyan(packageManager)} install`
|
|
877
|
-
]);
|
|
959
|
+
await trackUsage({
|
|
960
|
+
event: 'didCreateProject',
|
|
961
|
+
scope
|
|
962
|
+
});
|
|
963
|
+
// make sure a gitignore file is created regardless of the user using git or not
|
|
964
|
+
if (!await fse.exists(path.join(rootPath, '.gitignore'))) {
|
|
965
|
+
await fse.writeFile(path.join(rootPath, '.gitignore'), gitIgnore);
|
|
878
966
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
if (gitInit2) {
|
|
885
|
-
logger.title("git", "Initializing git repository.");
|
|
886
|
-
await tryGitInit(rootPath);
|
|
887
|
-
logger.success("Initialized a git repository.");
|
|
888
|
-
}
|
|
889
|
-
if (shouldRunSeed) {
|
|
890
|
-
if (await fse__default.default.exists(path.join(rootPath, "scripts/seed.js"))) {
|
|
891
|
-
logger.title("Seed", "Seeding your database with sample data");
|
|
892
|
-
try {
|
|
893
|
-
await execa__default.default(packageManager, ["run", "seed:example"], {
|
|
894
|
-
stdio: "inherit",
|
|
895
|
-
cwd: rootPath
|
|
896
|
-
});
|
|
897
|
-
logger.success("Sample data added to your database");
|
|
898
|
-
} catch (error) {
|
|
899
|
-
logger.error("Failed to seed your database. Skipping");
|
|
900
|
-
}
|
|
967
|
+
// Init git
|
|
968
|
+
if (gitInit) {
|
|
969
|
+
logger.title('git', 'Initializing git repository.');
|
|
970
|
+
await tryGitInit(rootPath);
|
|
971
|
+
logger.success('Initialized a git repository.');
|
|
901
972
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
if (useExample) {
|
|
922
|
-
logger.log(["Seed your database with sample data.", `${cmd} seed:example`, ""]);
|
|
923
|
-
}
|
|
924
|
-
logger.log(["Display all available commands.", `${cmd} strapi
|
|
925
|
-
`]);
|
|
926
|
-
if (installDependencies2) {
|
|
973
|
+
if (shouldRunSeed) {
|
|
974
|
+
if (await fse.exists(path.join(rootPath, 'scripts/seed.js'))) {
|
|
975
|
+
logger.title('Seed', 'Seeding your database with sample data');
|
|
976
|
+
try {
|
|
977
|
+
await execa(packageManager, [
|
|
978
|
+
'run',
|
|
979
|
+
'seed:example'
|
|
980
|
+
], {
|
|
981
|
+
stdio: 'inherit',
|
|
982
|
+
cwd: rootPath
|
|
983
|
+
});
|
|
984
|
+
logger.success('Sample data added to your database');
|
|
985
|
+
} catch (error) {
|
|
986
|
+
logger.error('Failed to seed your database. Skipping');
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const cmd = chalk.cyan(`${packageManager} run`);
|
|
991
|
+
logger.title('Strapi', `Your application was created!`);
|
|
927
992
|
logger.log([
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
993
|
+
'Available commands in your project:',
|
|
994
|
+
'',
|
|
995
|
+
'Start Strapi in watch mode. (Changes in Strapi project files will trigger a server restart)',
|
|
996
|
+
`${cmd} develop`,
|
|
997
|
+
'',
|
|
998
|
+
'Start Strapi without watch mode.',
|
|
999
|
+
`${cmd} start`,
|
|
1000
|
+
'',
|
|
1001
|
+
'Build Strapi admin panel.',
|
|
1002
|
+
`${cmd} build`,
|
|
1003
|
+
'',
|
|
1004
|
+
'Deploy Strapi project.',
|
|
1005
|
+
`${cmd} deploy`,
|
|
1006
|
+
''
|
|
932
1007
|
]);
|
|
933
|
-
|
|
1008
|
+
if (useExample) {
|
|
1009
|
+
logger.log([
|
|
1010
|
+
'Seed your database with sample data.',
|
|
1011
|
+
`${cmd} seed:example`,
|
|
1012
|
+
''
|
|
1013
|
+
]);
|
|
1014
|
+
}
|
|
934
1015
|
logger.log([
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
`${chalk__default.default.cyan("cd")} ${rootPath}`,
|
|
938
|
-
`${chalk__default.default.cyan(packageManager)} install`,
|
|
939
|
-
!shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`
|
|
1016
|
+
'Display all available commands.',
|
|
1017
|
+
`${cmd} strapi\n`
|
|
940
1018
|
]);
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1019
|
+
if (installDependencies) {
|
|
1020
|
+
logger.log([
|
|
1021
|
+
'To get started run',
|
|
1022
|
+
'',
|
|
1023
|
+
`${chalk.cyan('cd')} ${rootPath}`,
|
|
1024
|
+
!shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`
|
|
1025
|
+
]);
|
|
1026
|
+
} else {
|
|
1027
|
+
logger.log([
|
|
1028
|
+
'To get started run',
|
|
1029
|
+
'',
|
|
1030
|
+
`${chalk.cyan('cd')} ${rootPath}`,
|
|
1031
|
+
`${chalk.cyan(packageManager)} install`,
|
|
1032
|
+
!shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`
|
|
1033
|
+
]);
|
|
1034
|
+
}
|
|
1035
|
+
if (runApp && installDependencies) {
|
|
1036
|
+
logger.title('Run', 'Running your Strapi application');
|
|
1037
|
+
try {
|
|
1038
|
+
await trackUsage({
|
|
1039
|
+
event: 'willStartServer',
|
|
1040
|
+
scope
|
|
1041
|
+
});
|
|
1042
|
+
await execa(packageManager, [
|
|
1043
|
+
'run',
|
|
1044
|
+
'develop'
|
|
1045
|
+
], {
|
|
1046
|
+
stdio: 'inherit',
|
|
1047
|
+
cwd: rootPath,
|
|
1048
|
+
env: {
|
|
1049
|
+
FORCE_COLOR: '1'
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
} catch (error) {
|
|
1053
|
+
if (typeof error === 'string' || error instanceof Error) {
|
|
1054
|
+
await trackUsage({
|
|
1055
|
+
event: 'didNotStartServer',
|
|
1056
|
+
scope,
|
|
1057
|
+
error
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
logger.fatal('Failed to start your Strapi application');
|
|
951
1061
|
}
|
|
952
|
-
});
|
|
953
|
-
} catch (error) {
|
|
954
|
-
if (typeof error === "string" || error instanceof Error) {
|
|
955
|
-
await trackUsage({
|
|
956
|
-
event: "didNotStartServer",
|
|
957
|
-
scope,
|
|
958
|
-
error
|
|
959
|
-
});
|
|
960
|
-
}
|
|
961
|
-
logger.fatal("Failed to start your Strapi application");
|
|
962
1062
|
}
|
|
963
|
-
}
|
|
964
1063
|
}
|
|
965
1064
|
async function runInstall({ rootPath, packageManager }) {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1065
|
+
// include same cwd and env to ensure version check returns same version we use below
|
|
1066
|
+
const { envArgs, cmdArgs } = await getInstallArgs(packageManager, {
|
|
1067
|
+
cwd: rootPath,
|
|
1068
|
+
env: {
|
|
1069
|
+
...process.env,
|
|
1070
|
+
NODE_ENV: 'development'
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
const options = {
|
|
1074
|
+
cwd: rootPath,
|
|
1075
|
+
stdio: 'inherit',
|
|
1076
|
+
env: {
|
|
1077
|
+
...process.env,
|
|
1078
|
+
...envArgs,
|
|
1079
|
+
NODE_ENV: 'development'
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
const proc = execa(packageManager, cmdArgs, options);
|
|
1083
|
+
return proc;
|
|
984
1084
|
}
|
|
1085
|
+
|
|
985
1086
|
function checkNodeRequirements() {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1087
|
+
const currentNodeVersion = process.versions.node;
|
|
1088
|
+
// error if the node version isn't supported
|
|
1089
|
+
if (!semver.satisfies(currentNodeVersion, engines.node)) {
|
|
1090
|
+
logger.fatal([
|
|
1091
|
+
chalk.red(`You are running ${chalk.bold(`Node.js ${currentNodeVersion}`)}`),
|
|
1092
|
+
`Strapi requires ${chalk.bold(chalk.green(`Node.js ${engines.node}`))}`,
|
|
1093
|
+
'Please make sure to use the right version of Node.'
|
|
1094
|
+
]);
|
|
1095
|
+
} else if (semver.major(currentNodeVersion) % 2 !== 0) {
|
|
1096
|
+
logger.warn([
|
|
1097
|
+
chalk.yellow(`You are running ${chalk.bold(`Node.js ${currentNodeVersion}`)}`),
|
|
1098
|
+
`Strapi only supports ${chalk.bold(chalk.green('LTS versions of Node.js'))}, other versions may not be compatible.`
|
|
1099
|
+
]);
|
|
1100
|
+
}
|
|
999
1101
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
const
|
|
1004
|
-
if (
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
]);
|
|
1102
|
+
|
|
1103
|
+
// Checks if the an empty directory exists at rootPath
|
|
1104
|
+
async function checkInstallPath(directory) {
|
|
1105
|
+
const rootPath = path.resolve(directory);
|
|
1106
|
+
if (await fse.pathExists(rootPath)) {
|
|
1107
|
+
const stat = await fse.stat(rootPath);
|
|
1108
|
+
if (!stat.isDirectory()) {
|
|
1109
|
+
logger.fatal(`${chalk.green(rootPath)} is not a directory. Make sure to create a Strapi application in an empty directory.`);
|
|
1110
|
+
}
|
|
1111
|
+
const files = await fse.readdir(rootPath);
|
|
1112
|
+
if (files.length > 1) {
|
|
1113
|
+
logger.fatal([
|
|
1114
|
+
'You can only create a Strapi app in an empty directory',
|
|
1115
|
+
`Make sure ${chalk.green(rootPath)} is empty.`
|
|
1116
|
+
]);
|
|
1117
|
+
}
|
|
1017
1118
|
}
|
|
1018
|
-
|
|
1019
|
-
return rootPath;
|
|
1119
|
+
return rootPath;
|
|
1020
1120
|
}
|
|
1121
|
+
|
|
1021
1122
|
function machineID() {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1123
|
+
try {
|
|
1124
|
+
const deviceId = nodeMachineId.machineIdSync();
|
|
1125
|
+
return deviceId;
|
|
1126
|
+
} catch (error) {
|
|
1127
|
+
const deviceId = crypto.randomUUID();
|
|
1128
|
+
return deviceId;
|
|
1129
|
+
}
|
|
1029
1130
|
}
|
|
1030
|
-
|
|
1031
|
-
const
|
|
1131
|
+
|
|
1132
|
+
const DBOptions = [
|
|
1133
|
+
'dbclient',
|
|
1134
|
+
'dbhost',
|
|
1135
|
+
'dbport',
|
|
1136
|
+
'dbname',
|
|
1137
|
+
'dbusername',
|
|
1138
|
+
'dbpassword'
|
|
1139
|
+
];
|
|
1140
|
+
const VALID_CLIENTS = [
|
|
1141
|
+
'sqlite',
|
|
1142
|
+
'mysql',
|
|
1143
|
+
'postgres'
|
|
1144
|
+
];
|
|
1032
1145
|
const DEFAULT_CONFIG = {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1146
|
+
client: 'sqlite',
|
|
1147
|
+
connection: {
|
|
1148
|
+
filename: '.tmp/data.db'
|
|
1149
|
+
}
|
|
1037
1150
|
};
|
|
1038
1151
|
async function dbPrompt() {
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1152
|
+
const { useDefault } = await inquirer.prompt([
|
|
1153
|
+
{
|
|
1154
|
+
type: 'confirm',
|
|
1155
|
+
name: 'useDefault',
|
|
1156
|
+
message: 'Do you want to use the default database (sqlite) ?',
|
|
1157
|
+
default: true
|
|
1158
|
+
}
|
|
1159
|
+
]);
|
|
1160
|
+
if (useDefault) {
|
|
1161
|
+
return DEFAULT_CONFIG;
|
|
1162
|
+
}
|
|
1163
|
+
const { client } = await inquirer.prompt([
|
|
1164
|
+
{
|
|
1165
|
+
type: 'list',
|
|
1166
|
+
name: 'client',
|
|
1167
|
+
message: 'Choose your default database client',
|
|
1168
|
+
choices: [
|
|
1169
|
+
'sqlite',
|
|
1170
|
+
'postgres',
|
|
1171
|
+
'mysql'
|
|
1172
|
+
],
|
|
1173
|
+
default: 'sqlite'
|
|
1174
|
+
}
|
|
1175
|
+
]);
|
|
1176
|
+
const questions = dbQuestions[client].map((q)=>q({
|
|
1177
|
+
client
|
|
1178
|
+
}));
|
|
1179
|
+
const responses = await inquirer.prompt(questions);
|
|
1180
|
+
return {
|
|
1181
|
+
client,
|
|
1182
|
+
connection: responses
|
|
1183
|
+
};
|
|
1065
1184
|
}
|
|
1066
1185
|
async function getDatabaseInfos(options) {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}
|
|
1070
|
-
if (options.dbclient && !VALID_CLIENTS.includes(options.dbclient)) {
|
|
1071
|
-
logger.fatal(
|
|
1072
|
-
`Invalid --dbclient: ${options.dbclient}, expected one of ${VALID_CLIENTS.join(", ")}`
|
|
1073
|
-
);
|
|
1074
|
-
}
|
|
1075
|
-
const matchingArgs = DBOptions.filter((key) => key in options);
|
|
1076
|
-
const missingArgs = DBOptions.filter((key) => !(key in options));
|
|
1077
|
-
if (matchingArgs.length > 0 && matchingArgs.length !== DBOptions.length && options.dbclient !== "sqlite") {
|
|
1078
|
-
logger.fatal(`Required database arguments are missing: ${missingArgs.join(", ")}.`);
|
|
1079
|
-
}
|
|
1080
|
-
const hasDBOptions = DBOptions.some((key) => key in options);
|
|
1081
|
-
if (!hasDBOptions) {
|
|
1082
|
-
if (options.quickstart) {
|
|
1083
|
-
return DEFAULT_CONFIG;
|
|
1186
|
+
if (options.skipDb) {
|
|
1187
|
+
return DEFAULT_CONFIG;
|
|
1084
1188
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1189
|
+
if (options.dbclient && !VALID_CLIENTS.includes(options.dbclient)) {
|
|
1190
|
+
logger.fatal(`Invalid --dbclient: ${options.dbclient}, expected one of ${VALID_CLIENTS.join(', ')}`);
|
|
1191
|
+
}
|
|
1192
|
+
const matchingArgs = DBOptions.filter((key)=>key in options);
|
|
1193
|
+
const missingArgs = DBOptions.filter((key)=>!(key in options));
|
|
1194
|
+
if (matchingArgs.length > 0 && matchingArgs.length !== DBOptions.length && options.dbclient !== 'sqlite') {
|
|
1195
|
+
logger.fatal(`Required database arguments are missing: ${missingArgs.join(', ')}.`);
|
|
1196
|
+
}
|
|
1197
|
+
const hasDBOptions = DBOptions.some((key)=>key in options);
|
|
1198
|
+
if (!hasDBOptions) {
|
|
1199
|
+
if (options.quickstart) {
|
|
1200
|
+
return DEFAULT_CONFIG;
|
|
1201
|
+
}
|
|
1202
|
+
return dbPrompt();
|
|
1203
|
+
}
|
|
1204
|
+
if (!options.dbclient) {
|
|
1205
|
+
return logger.fatal('Please specify the database client');
|
|
1206
|
+
}
|
|
1207
|
+
const database = {
|
|
1208
|
+
client: options.dbclient,
|
|
1209
|
+
connection: {
|
|
1210
|
+
host: options.dbhost,
|
|
1211
|
+
port: options.dbport,
|
|
1212
|
+
database: options.dbname,
|
|
1213
|
+
username: options.dbusername,
|
|
1214
|
+
password: options.dbpassword,
|
|
1215
|
+
filename: options.dbfile
|
|
1216
|
+
}
|
|
1217
|
+
};
|
|
1218
|
+
if (options.dbssl !== undefined) {
|
|
1219
|
+
database.connection.ssl = options.dbssl === 'true';
|
|
1220
|
+
}
|
|
1221
|
+
return database;
|
|
1105
1222
|
}
|
|
1106
1223
|
const sqlClientModule = {
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1224
|
+
mysql: {
|
|
1225
|
+
mysql2: '3.9.8'
|
|
1226
|
+
},
|
|
1227
|
+
postgres: {
|
|
1228
|
+
pg: '8.8.0'
|
|
1229
|
+
},
|
|
1230
|
+
sqlite: {
|
|
1231
|
+
'better-sqlite3': '11.3.0'
|
|
1232
|
+
}
|
|
1110
1233
|
};
|
|
1111
1234
|
function addDatabaseDependencies(scope) {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1235
|
+
scope.dependencies = {
|
|
1236
|
+
...scope.dependencies,
|
|
1237
|
+
...sqlClientModule[scope.database.client]
|
|
1238
|
+
};
|
|
1116
1239
|
}
|
|
1117
1240
|
const DEFAULT_PORTS = {
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1241
|
+
postgres: 5432,
|
|
1242
|
+
mysql: 3306,
|
|
1243
|
+
sqlite: undefined
|
|
1121
1244
|
};
|
|
1122
|
-
const database = ()
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
});
|
|
1134
|
-
const host = ()
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
});
|
|
1140
|
-
const port = ({ client })
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
});
|
|
1146
|
-
const username = ()
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
});
|
|
1151
|
-
const password = ()
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
});
|
|
1157
|
-
const ssl = ()
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
});
|
|
1163
|
-
const filename = ()
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
});
|
|
1245
|
+
const database = ()=>({
|
|
1246
|
+
type: 'input',
|
|
1247
|
+
name: 'database',
|
|
1248
|
+
message: 'Database name:',
|
|
1249
|
+
default: 'strapi',
|
|
1250
|
+
validate (value) {
|
|
1251
|
+
if (value.includes('.')) {
|
|
1252
|
+
return `The database name can't contain a "."`;
|
|
1253
|
+
}
|
|
1254
|
+
return true;
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1257
|
+
const host = ()=>({
|
|
1258
|
+
type: 'input',
|
|
1259
|
+
name: 'host',
|
|
1260
|
+
message: 'Host:',
|
|
1261
|
+
default: '127.0.0.1'
|
|
1262
|
+
});
|
|
1263
|
+
const port = ({ client })=>({
|
|
1264
|
+
type: 'input',
|
|
1265
|
+
name: 'port',
|
|
1266
|
+
message: 'Port:',
|
|
1267
|
+
default: DEFAULT_PORTS[client]
|
|
1268
|
+
});
|
|
1269
|
+
const username = ()=>({
|
|
1270
|
+
type: 'input',
|
|
1271
|
+
name: 'username',
|
|
1272
|
+
message: 'Username:'
|
|
1273
|
+
});
|
|
1274
|
+
const password = ()=>({
|
|
1275
|
+
type: 'password',
|
|
1276
|
+
name: 'password',
|
|
1277
|
+
message: 'Password:',
|
|
1278
|
+
mask: '*'
|
|
1279
|
+
});
|
|
1280
|
+
const ssl = ()=>({
|
|
1281
|
+
type: 'confirm',
|
|
1282
|
+
name: 'ssl',
|
|
1283
|
+
message: 'Enable SSL connection:',
|
|
1284
|
+
default: false
|
|
1285
|
+
});
|
|
1286
|
+
const filename = ()=>({
|
|
1287
|
+
type: 'input',
|
|
1288
|
+
name: 'filename',
|
|
1289
|
+
message: 'Filename:',
|
|
1290
|
+
default: '.tmp/data.db'
|
|
1291
|
+
});
|
|
1169
1292
|
const dbQuestions = {
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1293
|
+
sqlite: [
|
|
1294
|
+
filename
|
|
1295
|
+
],
|
|
1296
|
+
postgres: [
|
|
1297
|
+
database,
|
|
1298
|
+
host,
|
|
1299
|
+
port,
|
|
1300
|
+
username,
|
|
1301
|
+
password,
|
|
1302
|
+
ssl
|
|
1303
|
+
],
|
|
1304
|
+
mysql: [
|
|
1305
|
+
database,
|
|
1306
|
+
host,
|
|
1307
|
+
port,
|
|
1308
|
+
username,
|
|
1309
|
+
password,
|
|
1310
|
+
ssl
|
|
1311
|
+
]
|
|
1173
1312
|
};
|
|
1174
|
-
|
|
1175
|
-
const
|
|
1313
|
+
|
|
1314
|
+
const { version } = fse.readJSONSync(path.join(__dirname, '..', 'package.json'));
|
|
1315
|
+
const command = new commander.Command('create-strapi-app').version(version).arguments('[directory]').usage('[directory] [options]').option('--quickstart', 'Quickstart app creation (deprecated)').option('--no-run', 'Do not start the application after it is created.')// setup options
|
|
1316
|
+
.option('--ts, --typescript', 'Initialize the project with TypeScript (default)').option('--js, --javascript', 'Initialize the project with Javascript')// Package manager options
|
|
1317
|
+
.option('--use-npm', 'Use npm as the project package manager').option('--use-yarn', 'Use yarn as the project package manager').option('--use-pnpm', 'Use pnpm as the project package manager')// dependencies options
|
|
1318
|
+
.option('--install', 'Install dependencies').option('--no-install', 'Do not install dependencies')// Cloud options
|
|
1319
|
+
.option('--skip-cloud', 'Skip cloud login and project creation')// Example app
|
|
1320
|
+
.option('--example', 'Use an example app').option('--no-example', 'Do not use an example app')// git options
|
|
1321
|
+
.option('--git-init', 'Initialize a git repository').option('--no-git-init', 'Do no initialize a git repository')// Database options
|
|
1322
|
+
.option('--dbclient <dbclient>', 'Database client').option('--dbhost <dbhost>', 'Database host').option('--dbport <dbport>', 'Database port').option('--dbname <dbname>', 'Database name').option('--dbusername <dbusername>', 'Database username').option('--dbpassword <dbpassword>', 'Database password').option('--dbssl <dbssl>', 'Database SSL').option('--dbfile <dbfile>', 'Database file path for sqlite').option('--skip-db', 'Skip database configuration').option('--template <template>', 'Specify a Strapi template').option('--template-branch <templateBranch>', 'Specify a branch for the template').option('--template-path <templatePath>', 'Specify a path to the template inside the repository').description('create a new application');
|
|
1176
1323
|
async function run(args) {
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
)
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
);
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
"@strapi/plugin-cloud": version,
|
|
1242
|
-
// third party
|
|
1243
|
-
react: "^18.0.0",
|
|
1244
|
-
"react-dom": "^18.0.0",
|
|
1245
|
-
"react-router-dom": "^6.0.0",
|
|
1246
|
-
"styled-components": "^6.0.0"
|
|
1247
|
-
}
|
|
1248
|
-
};
|
|
1249
|
-
if (options.template !== void 0) {
|
|
1250
|
-
scope.useExample = false;
|
|
1251
|
-
} else if (options.example === true) {
|
|
1252
|
-
scope.useExample = true;
|
|
1253
|
-
} else if (options.example === false || options.quickstart === true) {
|
|
1254
|
-
scope.useExample = false;
|
|
1255
|
-
} else {
|
|
1256
|
-
scope.useExample = await example();
|
|
1257
|
-
}
|
|
1258
|
-
if (options.javascript === true) {
|
|
1259
|
-
scope.useTypescript = false;
|
|
1260
|
-
} else if (options.typescript === true || options.quickstart) {
|
|
1261
|
-
scope.useTypescript = true;
|
|
1262
|
-
} else if (!options.template) {
|
|
1263
|
-
scope.useTypescript = await typescript();
|
|
1264
|
-
}
|
|
1265
|
-
if (options.install === true || options.quickstart) {
|
|
1266
|
-
scope.installDependencies = true;
|
|
1267
|
-
} else if (options.install === false) {
|
|
1268
|
-
scope.installDependencies = false;
|
|
1269
|
-
} else {
|
|
1270
|
-
scope.installDependencies = await installDependencies(scope.packageManager);
|
|
1271
|
-
}
|
|
1272
|
-
if (scope.useTypescript) {
|
|
1273
|
-
scope.devDependencies = {
|
|
1274
|
-
...scope.devDependencies,
|
|
1275
|
-
typescript: "^5",
|
|
1276
|
-
"@types/node": "^20",
|
|
1277
|
-
"@types/react": "^18",
|
|
1278
|
-
"@types/react-dom": "^18"
|
|
1324
|
+
const options = command.parse(args).opts();
|
|
1325
|
+
const directory$1 = command.args[0];
|
|
1326
|
+
logger.title('Strapi', `${chalk.green(chalk.bold(`v${version}`))} ${chalk.bold("🚀 Let's create your new project")}\n`);
|
|
1327
|
+
if ((options.javascript !== undefined || options.typescript !== undefined) && options.template !== undefined) {
|
|
1328
|
+
logger.fatal(`You cannot use ${chalk.bold('--javascript')} or ${chalk.bold('--typescript')} with ${chalk.bold('--template')}`);
|
|
1329
|
+
}
|
|
1330
|
+
if (options.javascript === true && options.typescript === true) {
|
|
1331
|
+
logger.fatal(`You cannot use both ${chalk.bold('--typescript')} (--ts) and ${chalk.bold('--javascript')} (--js) flags together`);
|
|
1332
|
+
}
|
|
1333
|
+
// Only prompt the example app option if there is no template option
|
|
1334
|
+
if (options.example === true && options.template !== undefined) {
|
|
1335
|
+
logger.fatal(`You cannot use ${chalk.bold('--example')} with ${chalk.bold('--template')}`);
|
|
1336
|
+
}
|
|
1337
|
+
if (options.template !== undefined && options.template.startsWith('-')) {
|
|
1338
|
+
logger.fatal(`Template name ${chalk.bold(`"${options.template}"`)} is invalid`);
|
|
1339
|
+
}
|
|
1340
|
+
if ([
|
|
1341
|
+
options.useNpm,
|
|
1342
|
+
options.usePnpm,
|
|
1343
|
+
options.useYarn
|
|
1344
|
+
].filter(Boolean).length > 1) {
|
|
1345
|
+
logger.fatal(`You cannot specify multiple package managers at the same time ${chalk.bold('(--use-npm, --use-pnpm, --use-yarn)')}`);
|
|
1346
|
+
}
|
|
1347
|
+
if (options.quickstart && !directory$1) {
|
|
1348
|
+
logger.fatal(`Please specify the ${chalk.bold('<directory>')} of your project when using ${chalk.bold('--quickstart')}`);
|
|
1349
|
+
}
|
|
1350
|
+
checkNodeRequirements();
|
|
1351
|
+
const appDirectory = directory$1 || await directory();
|
|
1352
|
+
const rootPath = await checkInstallPath(appDirectory);
|
|
1353
|
+
if (!options.skipCloud) {
|
|
1354
|
+
await handleCloudLogin();
|
|
1355
|
+
}
|
|
1356
|
+
const tmpPath = path.join(os$1.tmpdir(), `strapi${crypto.randomBytes(6).toString('hex')}`);
|
|
1357
|
+
const scope = {
|
|
1358
|
+
rootPath,
|
|
1359
|
+
name: path.basename(rootPath),
|
|
1360
|
+
packageManager: getPkgManager(options),
|
|
1361
|
+
database: await getDatabaseInfos(options),
|
|
1362
|
+
template: options.template,
|
|
1363
|
+
templateBranch: options.templateBranch,
|
|
1364
|
+
templatePath: options.templatePath,
|
|
1365
|
+
isQuickstart: options.quickstart,
|
|
1366
|
+
useExample: false,
|
|
1367
|
+
runApp: options.quickstart === true && options.run !== false,
|
|
1368
|
+
strapiVersion: version,
|
|
1369
|
+
packageJsonStrapi: {
|
|
1370
|
+
template: options.template
|
|
1371
|
+
},
|
|
1372
|
+
uuid: (process.env.STRAPI_UUID_PREFIX || '') + crypto.randomUUID(),
|
|
1373
|
+
docker: process.env.DOCKER === 'true',
|
|
1374
|
+
deviceId: machineID(),
|
|
1375
|
+
tmpPath,
|
|
1376
|
+
gitInit: true,
|
|
1377
|
+
devDependencies: {},
|
|
1378
|
+
dependencies: {
|
|
1379
|
+
'@strapi/strapi': version,
|
|
1380
|
+
'@strapi/plugin-users-permissions': version,
|
|
1381
|
+
'@strapi/plugin-cloud': version,
|
|
1382
|
+
// third party
|
|
1383
|
+
react: '^18.0.0',
|
|
1384
|
+
'react-dom': '^18.0.0',
|
|
1385
|
+
'react-router-dom': '^6.0.0',
|
|
1386
|
+
'styled-components': '^6.0.0'
|
|
1387
|
+
}
|
|
1279
1388
|
};
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1389
|
+
if (options.template !== undefined) {
|
|
1390
|
+
scope.useExample = false;
|
|
1391
|
+
} else if (options.example === true) {
|
|
1392
|
+
scope.useExample = true;
|
|
1393
|
+
} else if (options.example === false || options.quickstart === true) {
|
|
1394
|
+
scope.useExample = false;
|
|
1395
|
+
} else {
|
|
1396
|
+
scope.useExample = await example();
|
|
1397
|
+
}
|
|
1398
|
+
if (options.javascript === true) {
|
|
1399
|
+
scope.useTypescript = false;
|
|
1400
|
+
} else if (options.typescript === true || options.quickstart) {
|
|
1401
|
+
scope.useTypescript = true;
|
|
1402
|
+
} else if (!options.template) {
|
|
1403
|
+
scope.useTypescript = await typescript();
|
|
1404
|
+
}
|
|
1405
|
+
if (options.install === true || options.quickstart) {
|
|
1406
|
+
scope.installDependencies = true;
|
|
1407
|
+
} else if (options.install === false) {
|
|
1408
|
+
scope.installDependencies = false;
|
|
1409
|
+
} else {
|
|
1410
|
+
scope.installDependencies = await installDependencies(scope.packageManager);
|
|
1411
|
+
}
|
|
1412
|
+
if (scope.useTypescript) {
|
|
1413
|
+
scope.devDependencies = {
|
|
1414
|
+
...scope.devDependencies,
|
|
1415
|
+
typescript: '^5',
|
|
1416
|
+
'@types/node': '^20',
|
|
1417
|
+
'@types/react': '^18',
|
|
1418
|
+
'@types/react-dom': '^18'
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
if (options.gitInit === true || options.quickstart) {
|
|
1422
|
+
scope.gitInit = true;
|
|
1423
|
+
} else if (options.gitInit === false) {
|
|
1424
|
+
scope.gitInit = false;
|
|
1425
|
+
} else {
|
|
1426
|
+
scope.gitInit = await gitInit();
|
|
1427
|
+
}
|
|
1428
|
+
addDatabaseDependencies(scope);
|
|
1429
|
+
try {
|
|
1430
|
+
await createStrapi(scope);
|
|
1431
|
+
} catch (error) {
|
|
1432
|
+
if (!(error instanceof Error)) {
|
|
1433
|
+
throw error;
|
|
1434
|
+
}
|
|
1435
|
+
await trackError({
|
|
1436
|
+
scope,
|
|
1437
|
+
error
|
|
1438
|
+
});
|
|
1439
|
+
logger.fatal(error.message);
|
|
1440
|
+
}
|
|
1298
1441
|
}
|
|
1299
1442
|
function getPkgManager(options) {
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1443
|
+
if (options.useNpm === true) {
|
|
1444
|
+
return 'npm';
|
|
1445
|
+
}
|
|
1446
|
+
if (options.usePnpm === true) {
|
|
1447
|
+
return 'pnpm';
|
|
1448
|
+
}
|
|
1449
|
+
if (options.useYarn === true) {
|
|
1450
|
+
return 'yarn';
|
|
1451
|
+
}
|
|
1452
|
+
const userAgent = process.env.npm_config_user_agent || '';
|
|
1453
|
+
if (userAgent.startsWith('yarn')) {
|
|
1454
|
+
return 'yarn';
|
|
1455
|
+
}
|
|
1456
|
+
if (userAgent.startsWith('pnpm')) {
|
|
1457
|
+
return 'pnpm';
|
|
1458
|
+
}
|
|
1459
|
+
return 'npm';
|
|
1317
1460
|
}
|
|
1461
|
+
|
|
1318
1462
|
exports.createStrapi = createStrapi;
|
|
1319
1463
|
exports.run = run;
|
|
1320
1464
|
//# sourceMappingURL=index.js.map
|