create-expo 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/{205.index.js → 589.index.js} +442 -128
- package/build/601.index.js +20 -11
- package/build/{525.index.js → 870.index.js} +423 -334
- package/build/Examples.d.ts +38 -0
- package/build/Template.d.ts +98 -0
- package/build/__mocks__/fs.d.ts +1 -0
- package/build/__mocks__/ora.d.ts +1 -0
- package/build/__tests__/Examples.test.d.ts +1 -0
- package/build/__tests__/Template.test.d.ts +1 -0
- package/build/__tests__/configureWorkspaces.test.d.ts +1 -0
- package/build/__tests__/createAsync.test.d.ts +1 -0
- package/build/__tests__/createExpoConfig.test.d.ts +1 -0
- package/build/__tests__/createFileTransformer.test.d.ts +1 -0
- package/build/__tests__/generateAgentFiles.test.d.ts +1 -0
- package/build/__tests__/promptSdkVersion.test.d.ts +1 -0
- package/build/__tests__/resolvePackageManager.test.d.ts +1 -0
- package/build/__tests__/sanitizeTemplate.test.d.ts +1 -0
- package/build/__tests__/telemetry.test.d.ts +1 -0
- package/build/agent-files/AGENTS.md +41 -0
- package/build/agent-files/CLAUDE.md +1 -0
- package/build/cli.d.ts +1 -0
- package/build/configureWorkspaces.d.ts +9 -0
- package/build/createAsync.d.ts +11 -0
- package/build/createExpoConfig.d.ts +38 -0
- package/build/createFileTransform.d.ts +5 -0
- package/build/error.d.ts +9 -0
- package/build/generateAgentFiles.d.ts +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +38 -10
- package/build/legacyTemplates.d.ts +7 -0
- package/build/log.d.ts +12 -0
- package/build/paths.d.ts +2 -0
- package/build/promptSdkVersion.d.ts +23 -0
- package/build/resolvePackageManager.d.ts +12 -0
- package/build/resolveProjectRoot.d.ts +3 -0
- package/build/sessionStorage.d.ts +8 -0
- package/build/telemetry.d.ts +29 -0
- package/build/utils/__tests__/args.test.d.ts +1 -0
- package/build/utils/__tests__/array.test.d.ts +1 -0
- package/build/utils/__tests__/log.test.d.ts +1 -0
- package/build/utils/__tests__/npm.test.d.ts +1 -0
- package/build/utils/__tests__/obj.test.d.ts +1 -0
- package/build/utils/args.d.ts +33 -0
- package/build/utils/array.d.ts +1 -0
- package/build/utils/dir.d.ts +1 -0
- package/build/utils/env.d.ts +14 -0
- package/build/utils/fetch.d.ts +2 -0
- package/build/utils/git.d.ts +1 -0
- package/build/utils/github.d.ts +2 -0
- package/build/utils/log.d.ts +6 -0
- package/build/utils/npm.d.ts +52 -0
- package/build/utils/obj.d.ts +1 -0
- package/build/utils/tar.d.ts +10 -0
- package/build/utils/update-check.d.ts +2 -0
- package/package.json +33 -21
- package/template/agent-files/AGENTS.md +41 -0
- package/template/agent-files/CLAUDE.md +1 -0
- package/build/517.index.js +0 -1380
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
exports.id =
|
|
3
|
-
exports.ids = [
|
|
2
|
+
exports.id = 589;
|
|
3
|
+
exports.ids = [589,601];
|
|
4
4
|
exports.modules = {
|
|
5
5
|
|
|
6
|
-
/***/
|
|
6
|
+
/***/ 589:
|
|
7
7
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
8
8
|
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
12
12
|
createAsync: () => (/* binding */ createAsync)
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
// UNUSED EXPORTS: logNodeInstallWarning
|
|
15
|
+
// UNUSED EXPORTS: logNodeInstallWarning, setupDependenciesAsync
|
|
16
16
|
|
|
17
17
|
// EXTERNAL MODULE: ../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/source/index.js
|
|
18
18
|
var source = __webpack_require__(2314);
|
|
@@ -25,7 +25,6 @@ var external_path_ = __webpack_require__(6928);
|
|
|
25
25
|
var external_path_default = /*#__PURE__*/__webpack_require__.n(external_path_);
|
|
26
26
|
// EXTERNAL MODULE: ../@expo/json-file/build/JsonFile.js
|
|
27
27
|
var JsonFile = __webpack_require__(3064);
|
|
28
|
-
var JsonFile_default = /*#__PURE__*/__webpack_require__.n(JsonFile);
|
|
29
28
|
// EXTERNAL MODULE: ../../node_modules/.pnpm/prompts@2.4.2/node_modules/prompts/index.js
|
|
30
29
|
var prompts = __webpack_require__(6133);
|
|
31
30
|
var prompts_default = /*#__PURE__*/__webpack_require__.n(prompts);
|
|
@@ -36,8 +35,69 @@ var index_min = __webpack_require__(9337);
|
|
|
36
35
|
// EXTERNAL MODULE: ../../node_modules/.pnpm/ora@3.4.0/node_modules/ora/index.js
|
|
37
36
|
var ora = __webpack_require__(5344);
|
|
38
37
|
var ora_default = /*#__PURE__*/__webpack_require__.n(ora);
|
|
39
|
-
// EXTERNAL MODULE:
|
|
40
|
-
var
|
|
38
|
+
// EXTERNAL MODULE: ./src/log.ts
|
|
39
|
+
var log = __webpack_require__(1545);
|
|
40
|
+
;// CONCATENATED MODULE: ./src/createExpoConfig.ts
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
const debug = __webpack_require__(6675)('expo:init:monorepo-config');
|
|
45
|
+
const CREATE_EXPO_CONFIG_NAME = '.create-expo.json';
|
|
46
|
+
/**
|
|
47
|
+
* Read `.create-expo.json` from the project root and immediately
|
|
48
|
+
* delete the file from disk so it doesn't leak into the user's project.
|
|
49
|
+
* Returns the parsed config (or `undefined` if there's no file / it's
|
|
50
|
+
* malformed). This is the "use it once" entry point that template-extraction
|
|
51
|
+
* code paths should call — every downstream consumer takes the parsed
|
|
52
|
+
* object in memory.
|
|
53
|
+
*/
|
|
54
|
+
async function consumeMonorepoConfigAsync(projectRoot) {
|
|
55
|
+
const config = await loadMonorepoConfigAsync(projectRoot);
|
|
56
|
+
await external_fs_default().promises
|
|
57
|
+
.rm(external_path_default().join(projectRoot, CREATE_EXPO_CONFIG_NAME), { force: true })
|
|
58
|
+
.catch(() => undefined);
|
|
59
|
+
return config;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Reads `.create-expo.json` from the project root without touching
|
|
63
|
+
* the file. Returns `undefined` if the file is missing, unreadable, or
|
|
64
|
+
* malformed — a missing file is the common case (single-app templates) and
|
|
65
|
+
* shouldn't warn.
|
|
66
|
+
*
|
|
67
|
+
* Prefer `consumeMonorepoConfigAsync` for the create-expo flow so the
|
|
68
|
+
* template-only config doesn't leak into the user's project. This function
|
|
69
|
+
* stays exported for tests and any other read-only callers.
|
|
70
|
+
*/
|
|
71
|
+
async function loadMonorepoConfigAsync(projectRoot) {
|
|
72
|
+
const configPath = external_path_default().join(projectRoot, CREATE_EXPO_CONFIG_NAME);
|
|
73
|
+
let contents;
|
|
74
|
+
try {
|
|
75
|
+
contents = await external_fs_default().promises.readFile(configPath, { encoding: 'utf-8' });
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (error?.code !== 'ENOENT') {
|
|
79
|
+
log/* Log */.tG.log(`Could not read ${CREATE_EXPO_CONFIG_NAME}; ignoring: ${error?.message ?? error}`);
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
let parsed;
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(contents);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
log/* Log */.tG.log(`${CREATE_EXPO_CONFIG_NAME} could not be parsed as JSON; ignoring: ${error?.message ?? error}`);
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
92
|
+
log/* Log */.tG.log(`${CREATE_EXPO_CONFIG_NAME} did not parse as a JSON object; ignoring.`);
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
debug(`Loaded ${CREATE_EXPO_CONFIG_NAME}`);
|
|
96
|
+
return parsed;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// EXTERNAL MODULE: ../../node_modules/.pnpm/multitars@1.0.2/node_modules/multitars/dist/multitars.mjs
|
|
100
|
+
var multitars = __webpack_require__(6378);
|
|
41
101
|
// EXTERNAL MODULE: ../../node_modules/.pnpm/picomatch@2.3.2/node_modules/picomatch/index.js
|
|
42
102
|
var picomatch = __webpack_require__(3268);
|
|
43
103
|
var picomatch_default = /*#__PURE__*/__webpack_require__.n(picomatch);
|
|
@@ -45,7 +105,7 @@ var picomatch_default = /*#__PURE__*/__webpack_require__.n(picomatch);
|
|
|
45
105
|
|
|
46
106
|
|
|
47
107
|
|
|
48
|
-
const
|
|
108
|
+
const createFileTransform_debug = __webpack_require__(6675)('expo:init:fileTransform');
|
|
49
109
|
function sanitizedName(name) {
|
|
50
110
|
return name
|
|
51
111
|
.replace(/[\W_]+/g, '')
|
|
@@ -87,16 +147,14 @@ function createEntryRenamer(name) {
|
|
|
87
147
|
}
|
|
88
148
|
function createGlobFilter(globPattern, options) {
|
|
89
149
|
const matcher = picomatch_default()(globPattern, options);
|
|
90
|
-
|
|
150
|
+
createFileTransform_debug('filter: created for pattern %s (%s)', globPattern);
|
|
91
151
|
return (path) => {
|
|
92
152
|
const included = matcher(path);
|
|
93
|
-
|
|
153
|
+
createFileTransform_debug('filter: %s - %s', included ? 'include' : 'exclude', path);
|
|
94
154
|
return included;
|
|
95
155
|
};
|
|
96
156
|
}
|
|
97
157
|
|
|
98
|
-
// EXTERNAL MODULE: ./src/log.ts
|
|
99
|
-
var log = __webpack_require__(1545);
|
|
100
158
|
// EXTERNAL MODULE: ./src/resolvePackageManager.ts
|
|
101
159
|
var resolvePackageManager = __webpack_require__(9560);
|
|
102
160
|
// EXTERNAL MODULE: ./src/utils/env.ts
|
|
@@ -131,6 +189,57 @@ var external_os_ = __webpack_require__(857);
|
|
|
131
189
|
var external_os_default = /*#__PURE__*/__webpack_require__.n(external_os_);
|
|
132
190
|
// EXTERNAL MODULE: external "stream"
|
|
133
191
|
var external_stream_ = __webpack_require__(2203);
|
|
192
|
+
;// CONCATENATED MODULE: ./src/legacyTemplates.ts
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
const LEGACY_TEMPLATES = [
|
|
197
|
+
{
|
|
198
|
+
title: 'Default',
|
|
199
|
+
value: 'expo-template-default',
|
|
200
|
+
description: 'includes tools recommended for most app developers',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
title: 'Blank',
|
|
204
|
+
value: 'expo-template-blank',
|
|
205
|
+
description: 'a minimal app as clean as an empty canvas',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
title: 'Blank (TypeScript)',
|
|
209
|
+
value: 'expo-template-blank-typescript',
|
|
210
|
+
description: 'blank app with TypeScript enabled',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
title: 'Navigation (TypeScript)',
|
|
214
|
+
value: 'expo-template-tabs',
|
|
215
|
+
description: 'File-based routing with TypeScript enabled',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
title: 'Blank (Bare)',
|
|
219
|
+
value: 'expo-template-bare-minimum',
|
|
220
|
+
description: 'blank app with the native code exposed (expo prebuild)',
|
|
221
|
+
},
|
|
222
|
+
];
|
|
223
|
+
const ALIASES = LEGACY_TEMPLATES.map(({ value }) => value);
|
|
224
|
+
async function promptTemplateAsync() {
|
|
225
|
+
if (env.env.CI) {
|
|
226
|
+
throw new Error('Cannot prompt for template in CI');
|
|
227
|
+
}
|
|
228
|
+
const { answer } = await prompts_default()({
|
|
229
|
+
type: 'select',
|
|
230
|
+
name: 'answer',
|
|
231
|
+
message: 'Choose a template:',
|
|
232
|
+
choices: LEGACY_TEMPLATES,
|
|
233
|
+
});
|
|
234
|
+
if (!answer) {
|
|
235
|
+
console.log();
|
|
236
|
+
console.log(source_default() `Specify the template name, example: {cyan --template expo-template-blank}`);
|
|
237
|
+
console.log();
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
return answer;
|
|
241
|
+
}
|
|
242
|
+
|
|
134
243
|
// EXTERNAL MODULE: external "node:crypto"
|
|
135
244
|
var external_node_crypto_ = __webpack_require__(5217);
|
|
136
245
|
var external_node_crypto_default = /*#__PURE__*/__webpack_require__.n(external_node_crypto_);
|
|
@@ -262,57 +371,6 @@ async function extractAsync(input, output, options) {
|
|
|
262
371
|
await extractStream(Readable.toWeb(fs.createReadStream(input)), output, options);
|
|
263
372
|
}
|
|
264
373
|
|
|
265
|
-
;// CONCATENATED MODULE: ./src/legacyTemplates.ts
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const LEGACY_TEMPLATES = [
|
|
270
|
-
{
|
|
271
|
-
title: 'Default',
|
|
272
|
-
value: 'expo-template-default',
|
|
273
|
-
description: 'includes tools recommended for most app developers',
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
title: 'Blank',
|
|
277
|
-
value: 'expo-template-blank',
|
|
278
|
-
description: 'a minimal app as clean as an empty canvas',
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
title: 'Blank (TypeScript)',
|
|
282
|
-
value: 'expo-template-blank-typescript',
|
|
283
|
-
description: 'blank app with TypeScript enabled',
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
title: 'Navigation (TypeScript)',
|
|
287
|
-
value: 'expo-template-tabs',
|
|
288
|
-
description: 'File-based routing with TypeScript enabled',
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
title: 'Blank (Bare)',
|
|
292
|
-
value: 'expo-template-bare-minimum',
|
|
293
|
-
description: 'blank app with the native code exposed (expo prebuild)',
|
|
294
|
-
},
|
|
295
|
-
];
|
|
296
|
-
const ALIASES = LEGACY_TEMPLATES.map(({ value }) => value);
|
|
297
|
-
async function promptTemplateAsync() {
|
|
298
|
-
if (env.env.CI) {
|
|
299
|
-
throw new Error('Cannot prompt for template in CI');
|
|
300
|
-
}
|
|
301
|
-
const { answer } = await prompts_default()({
|
|
302
|
-
type: 'select',
|
|
303
|
-
name: 'answer',
|
|
304
|
-
message: 'Choose a template:',
|
|
305
|
-
choices: LEGACY_TEMPLATES,
|
|
306
|
-
});
|
|
307
|
-
if (!answer) {
|
|
308
|
-
console.log();
|
|
309
|
-
console.log(source_default() `Specify the template name, example: {cyan --template expo-template-blank}`);
|
|
310
|
-
console.log();
|
|
311
|
-
process.exit(1);
|
|
312
|
-
}
|
|
313
|
-
return answer;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
374
|
;// CONCATENATED MODULE: ./src/utils/npm.ts
|
|
317
375
|
|
|
318
376
|
|
|
@@ -424,8 +482,9 @@ async function npmPackAsync(packageName, cwd = undefined, ...props) {
|
|
|
424
482
|
}
|
|
425
483
|
try {
|
|
426
484
|
const json = JSON.parse(results);
|
|
427
|
-
|
|
428
|
-
|
|
485
|
+
const packages = normalizeNpmPackResult(json);
|
|
486
|
+
if (packages?.every(isNpmPackageInfo)) {
|
|
487
|
+
return packages.map(sanitizeNpmPackageFilename);
|
|
429
488
|
}
|
|
430
489
|
else {
|
|
431
490
|
throw new Error(`Invalid response from npm: ${results}`);
|
|
@@ -435,6 +494,18 @@ async function npmPackAsync(packageName, cwd = undefined, ...props) {
|
|
|
435
494
|
throw new Error(`Could not parse JSON returned from "${cmdString}".\n\n${results}\n\nError: ${error.message}`);
|
|
436
495
|
}
|
|
437
496
|
}
|
|
497
|
+
/** Normalize the npm pack JSON formats used before and after npm 12 */
|
|
498
|
+
function normalizeNpmPackResult(result) {
|
|
499
|
+
if (Array.isArray(result)) {
|
|
500
|
+
return result;
|
|
501
|
+
}
|
|
502
|
+
else if (result && typeof result === 'object') {
|
|
503
|
+
return Object.values(result);
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
438
509
|
function getNpmBin() {
|
|
439
510
|
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
440
511
|
}
|
|
@@ -507,6 +578,7 @@ async function downloadAndExtractNpmModuleAsync(npmName, output, props) {
|
|
|
507
578
|
|
|
508
579
|
|
|
509
580
|
|
|
581
|
+
|
|
510
582
|
const github_debug = __webpack_require__(6675)('expo:init:github');
|
|
511
583
|
// See: https://github.com/expo/expo/blob/a5a6eecb082b2c7a7fc9956141738231c7df473f/packages/%40expo/cli/src/prebuild/resolveTemplate.ts#L60-L84
|
|
512
584
|
async function getGitHubRepoAsync(url) {
|
|
@@ -552,9 +624,15 @@ async function extractRemoteGitHubTarballAsync(url, repo, output, props) {
|
|
|
552
624
|
const strip = directory.length + 1;
|
|
553
625
|
// Only extract the relevant (sub)directories, ignoring irrelevant files
|
|
554
626
|
// The filter auto-ignores dotfiles, unless explicitly included
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
627
|
+
const subDirPrefix = directory.length ? `*/${directory.join('/')}` : '*';
|
|
628
|
+
const filter = createGlobFilter([
|
|
629
|
+
`${subDirPrefix}/**`,
|
|
630
|
+
`${subDirPrefix}/ios/.xcode.env`,
|
|
631
|
+
// Templates ship their monorepo config as a root-level dotfile; without
|
|
632
|
+
// an explicit allow-list entry, picomatch's default `dot: false` drops
|
|
633
|
+
// it during extraction so downstream consumers see no config at all.
|
|
634
|
+
`${subDirPrefix}/${CREATE_EXPO_CONFIG_NAME}`,
|
|
635
|
+
], {
|
|
558
636
|
// Always ignore the `.xcworkspace` folder
|
|
559
637
|
ignore: ['**/ios/*.xcworkspace/**'],
|
|
560
638
|
});
|
|
@@ -569,7 +647,7 @@ async function downloadAndExtractGitHubRepositoryAsync(repoUrl, output, props) {
|
|
|
569
647
|
const info = await getGitHubRepoAsync(repoUrl);
|
|
570
648
|
const isValid = await isValidGitHubRepoAsync(info);
|
|
571
649
|
if (!isValid) {
|
|
572
|
-
throw new Error(`Could not
|
|
650
|
+
throw new Error(`Could not locate repository for "${repoUrl}", ensure this repository exists`);
|
|
573
651
|
}
|
|
574
652
|
const url = `https://codeload.github.com/${info.owner}/${info.name}/tar.gz/${info.branch}`;
|
|
575
653
|
github_debug('Resolved GitHub repository', info);
|
|
@@ -591,6 +669,7 @@ async function downloadAndExtractGitHubRepositoryAsync(repoUrl, output, props) {
|
|
|
591
669
|
|
|
592
670
|
|
|
593
671
|
|
|
672
|
+
|
|
594
673
|
const Template_debug = __webpack_require__(6675)('expo:init:template');
|
|
595
674
|
const isMacOS = process.platform === 'darwin';
|
|
596
675
|
// keep this list in sync with the validation helper in WWW: src/utils/experienceParser.ts
|
|
@@ -675,6 +754,11 @@ function resolvePackageModuleId(moduleId) {
|
|
|
675
754
|
/**
|
|
676
755
|
* Extract a template app to a given file path and clean up any properties left over from npm to
|
|
677
756
|
* prepare it for usage.
|
|
757
|
+
*
|
|
758
|
+
* If the template ships a `.create-expo.json`, its `renamePatterns`
|
|
759
|
+
* field overrides the default rename config used by the HelloWorld
|
|
760
|
+
* find-and-replace pass. The config file is read once and deleted from disk
|
|
761
|
+
* immediately so it can never leak into the user's project.
|
|
678
762
|
*/
|
|
679
763
|
async function extractAndPrepareTemplateAppAsync(projectRoot, { npmPackage }) {
|
|
680
764
|
const projectName = external_path_default().basename(projectRoot);
|
|
@@ -692,8 +776,12 @@ async function extractAndPrepareTemplateAppAsync(projectRoot, { npmPackage }) {
|
|
|
692
776
|
disableCache: type === 'file',
|
|
693
777
|
});
|
|
694
778
|
}
|
|
779
|
+
const monorepoConfig = await consumeMonorepoConfigAsync(projectRoot);
|
|
695
780
|
try {
|
|
696
|
-
const files = await getTemplateFilesToRenameAsync({
|
|
781
|
+
const files = await getTemplateFilesToRenameAsync({
|
|
782
|
+
cwd: projectRoot,
|
|
783
|
+
renameConfig: monorepoConfig?.renamePatterns,
|
|
784
|
+
});
|
|
697
785
|
await renameTemplateAppNameAsync({
|
|
698
786
|
cwd: projectRoot,
|
|
699
787
|
files,
|
|
@@ -745,8 +833,8 @@ function escapeXMLCharacters(original) {
|
|
|
745
833
|
* Whitespace is trimmed and whitespace-only lines are ignored.
|
|
746
834
|
*
|
|
747
835
|
* If no rename config has been passed directly to
|
|
748
|
-
* `getTemplateFilesToRenameAsync()
|
|
749
|
-
* used instead.
|
|
836
|
+
* `getTemplateFilesToRenameAsync()`, then this default
|
|
837
|
+
* rename config will be used instead.
|
|
750
838
|
*/
|
|
751
839
|
const defaultRenameConfig = [
|
|
752
840
|
// Common
|
|
@@ -805,7 +893,9 @@ async function renameTemplateAppNameAsync({ cwd, name, files, }) {
|
|
|
805
893
|
const absoluteFilePath = external_path_default().resolve(cwd, file);
|
|
806
894
|
let contents;
|
|
807
895
|
try {
|
|
808
|
-
contents = await external_fs_default().promises.readFile(absoluteFilePath, {
|
|
896
|
+
contents = await external_fs_default().promises.readFile(absoluteFilePath, {
|
|
897
|
+
encoding: 'utf-8',
|
|
898
|
+
});
|
|
809
899
|
}
|
|
810
900
|
catch (error) {
|
|
811
901
|
throw new Error(`Failed to read template file: "${absoluteFilePath}". Was it removed mid-operation?`, { cause: error });
|
|
@@ -861,12 +951,14 @@ async function sanitizeTemplateAsync(projectRoot) {
|
|
|
861
951
|
name: projectName,
|
|
862
952
|
slug: projectName,
|
|
863
953
|
};
|
|
864
|
-
const appFile = new (
|
|
954
|
+
const appFile = new JsonFile["default"](external_path_default().join(projectRoot, 'app.json'), {
|
|
955
|
+
default: {},
|
|
956
|
+
});
|
|
865
957
|
const appContent = (await appFile.readAsync());
|
|
866
958
|
const appJson = deepMerge(appContent, 'expo' in appContent ? { expo: defaultConfig } : defaultConfig);
|
|
867
959
|
await appFile.writeAsync(appJson);
|
|
868
960
|
Template_debug(`Created app.json:\n%O`, appJson);
|
|
869
|
-
const packageFile = new (
|
|
961
|
+
const packageFile = new JsonFile["default"](external_path_default().join(projectRoot, 'package.json'));
|
|
870
962
|
const packageJson = await packageFile.readAsync();
|
|
871
963
|
// name and version are required for yarn workspaces (monorepos)
|
|
872
964
|
const inputName = 'name' in appJson ? appJson.name : appJson.expo.name;
|
|
@@ -1011,6 +1103,7 @@ function logNewSection(title) {
|
|
|
1011
1103
|
|
|
1012
1104
|
|
|
1013
1105
|
|
|
1106
|
+
|
|
1014
1107
|
const Examples_debug = __webpack_require__(6675)('expo:init:template');
|
|
1015
1108
|
/** List all existing examples directory from https://github.com/expo/examples. */
|
|
1016
1109
|
async function listExamplesAsync() {
|
|
@@ -1066,7 +1159,14 @@ async function promptExamplesAsync() {
|
|
|
1066
1159
|
}
|
|
1067
1160
|
return answer;
|
|
1068
1161
|
}
|
|
1069
|
-
/**
|
|
1162
|
+
/**
|
|
1163
|
+
* Download and move the selected example from https://github.com/expo/examples.
|
|
1164
|
+
*
|
|
1165
|
+
* If the example ships a `.create-expo.json`, its `renamePatterns`
|
|
1166
|
+
* field overrides the default rename config used by the HelloWorld
|
|
1167
|
+
* find-and-replace pass. The config file is read once and deleted from disk
|
|
1168
|
+
* immediately so it can never leak into the user's project.
|
|
1169
|
+
*/
|
|
1070
1170
|
async function downloadAndExtractExampleAsync(root, name) {
|
|
1071
1171
|
const projectName = external_path_default().basename(root);
|
|
1072
1172
|
const response = await fetch_fetch('https://codeload.github.com/expo/examples/tar.gz/master');
|
|
@@ -1084,7 +1184,11 @@ async function downloadAndExtractExampleAsync(root, name) {
|
|
|
1084
1184
|
strip: 2,
|
|
1085
1185
|
filter: (entryName) => entryName.startsWith(prefix),
|
|
1086
1186
|
});
|
|
1087
|
-
const
|
|
1187
|
+
const monorepoConfig = await consumeMonorepoConfigAsync(root);
|
|
1188
|
+
const files = await getTemplateFilesToRenameAsync({
|
|
1189
|
+
cwd: root,
|
|
1190
|
+
renameConfig: monorepoConfig?.renamePatterns,
|
|
1191
|
+
});
|
|
1088
1192
|
await renameTemplateAppNameAsync({
|
|
1089
1193
|
cwd: root,
|
|
1090
1194
|
files,
|
|
@@ -1110,61 +1214,235 @@ async function sanitizeScriptsAsync(root) {
|
|
|
1110
1214
|
ios: 'expo start --ios',
|
|
1111
1215
|
web: 'expo start --web',
|
|
1112
1216
|
};
|
|
1113
|
-
const packageFile = new (
|
|
1217
|
+
const packageFile = new JsonFile["default"](external_path_default().join(root, 'package.json'));
|
|
1114
1218
|
const packageJson = await packageFile.readAsync();
|
|
1115
1219
|
const scripts = (packageJson.scripts ?? {});
|
|
1116
1220
|
packageJson.scripts = { ...defaultScripts, ...scripts };
|
|
1117
1221
|
await packageFile.writeAsync(packageJson);
|
|
1118
1222
|
}
|
|
1119
1223
|
|
|
1120
|
-
|
|
1224
|
+
// EXTERNAL MODULE: ../../node_modules/.pnpm/resolve-workspace-root@2.0.1/node_modules/resolve-workspace-root/build/index.js
|
|
1225
|
+
var resolve_workspace_root_build = __webpack_require__(8665);
|
|
1226
|
+
;// CONCATENATED MODULE: ./src/configureWorkspaces.ts
|
|
1121
1227
|
|
|
1122
1228
|
|
|
1123
|
-
|
|
1229
|
+
|
|
1230
|
+
const configureWorkspaces_debug = __webpack_require__(6675)('expo:init:workspaces');
|
|
1231
|
+
const PNPM_WORKSPACE_FILENAME = 'pnpm-workspace.yaml';
|
|
1232
|
+
const WORKSPACE_DEP_FIELDS = [
|
|
1233
|
+
'dependencies',
|
|
1234
|
+
'devDependencies',
|
|
1235
|
+
'peerDependencies',
|
|
1236
|
+
'optionalDependencies',
|
|
1237
|
+
];
|
|
1238
|
+
/**
|
|
1239
|
+
* Normalize a monorepo template's workspace-package dependency specs to the
|
|
1240
|
+
* chosen package manager's convention, and — for pnpm — write a
|
|
1241
|
+
* `pnpm-workspace.yaml` listing the workspace packages so they're picked up
|
|
1242
|
+
* regardless of the root `package.json` `workspaces` field.
|
|
1243
|
+
*/
|
|
1244
|
+
async function configureWorkspacesAsync(projectRoot, packageManager) {
|
|
1245
|
+
const workspacePatterns = (await (0,resolve_workspace_root_build.getWorkspaceGlobsAsync)(projectRoot)) ?? [];
|
|
1246
|
+
if (!workspacePatterns.length) {
|
|
1247
|
+
configureWorkspaces_debug(`No workspaces declared at ${projectRoot}; skipping workspace configuration`);
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
const memberPaths = await resolveWorkspaceMemberPathsAsync(projectRoot, workspacePatterns);
|
|
1251
|
+
configureWorkspaces_debug(`Found ${memberPaths.length} workspace member(s): ${memberPaths.join(', ')}`);
|
|
1252
|
+
const targetSpec = packageManager === 'npm' ? '*' : 'workspace:*';
|
|
1253
|
+
for (const memberPath of memberPaths) {
|
|
1254
|
+
await normalizeWorkspaceDepsAsync(memberPath, targetSpec);
|
|
1255
|
+
}
|
|
1256
|
+
if (packageManager === 'pnpm') {
|
|
1257
|
+
await ensurePnpmWorkspaceYamlAsync(projectRoot, workspacePatterns);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
async function resolveWorkspaceMemberPathsAsync(projectRoot, patterns) {
|
|
1261
|
+
const members = [];
|
|
1262
|
+
const seen = new Set();
|
|
1263
|
+
for (const pattern of patterns) {
|
|
1264
|
+
const expanded = await expandPatternAsync(projectRoot, pattern);
|
|
1265
|
+
for (const member of expanded) {
|
|
1266
|
+
if (!seen.has(member)) {
|
|
1267
|
+
seen.add(member);
|
|
1268
|
+
members.push(member);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
return members;
|
|
1273
|
+
}
|
|
1274
|
+
async function expandPatternAsync(projectRoot, pattern) {
|
|
1275
|
+
const segments = pattern.split('/').filter((s) => s.length > 0);
|
|
1276
|
+
if (segments.length === 0) {
|
|
1277
|
+
return [];
|
|
1278
|
+
}
|
|
1279
|
+
// Literal path (no wildcards anywhere) — return it if its package.json exists.
|
|
1280
|
+
if (!segments.some((s) => s.includes('*'))) {
|
|
1281
|
+
const memberDir = external_path_default().resolve(projectRoot, ...segments);
|
|
1282
|
+
return (await packageJsonExistsAsync(memberDir)) ? [memberDir] : [];
|
|
1283
|
+
}
|
|
1284
|
+
// Single trailing wildcard segment — read the parent dir, keep children
|
|
1285
|
+
// whose package.json exists.
|
|
1286
|
+
if (segments[segments.length - 1] === '*' &&
|
|
1287
|
+
!segments.slice(0, -1).some((s) => s.includes('*'))) {
|
|
1288
|
+
const parentDir = external_path_default().resolve(projectRoot, ...segments.slice(0, -1));
|
|
1289
|
+
let entries;
|
|
1290
|
+
try {
|
|
1291
|
+
entries = await external_fs_default().promises.readdir(parentDir, { withFileTypes: true });
|
|
1292
|
+
}
|
|
1293
|
+
catch (error) {
|
|
1294
|
+
configureWorkspaces_debug(`Could not read workspace parent ${parentDir}: ${error?.message ?? error}`);
|
|
1295
|
+
return [];
|
|
1296
|
+
}
|
|
1297
|
+
const matches = [];
|
|
1298
|
+
for (const entry of entries) {
|
|
1299
|
+
if (!entry.isDirectory())
|
|
1300
|
+
continue;
|
|
1301
|
+
const memberDir = external_path_default().join(parentDir, entry.name);
|
|
1302
|
+
if (await packageJsonExistsAsync(memberDir)) {
|
|
1303
|
+
matches.push(memberDir);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
return matches;
|
|
1307
|
+
}
|
|
1308
|
+
configureWorkspaces_debug(`Unsupported workspace pattern "${pattern}" (only literal paths and trailing /* are handled)`);
|
|
1309
|
+
return [];
|
|
1310
|
+
}
|
|
1311
|
+
async function packageJsonExistsAsync(memberDir) {
|
|
1124
1312
|
try {
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1127
|
-
if (!expoVersion)
|
|
1128
|
-
return null;
|
|
1129
|
-
const match = expoVersion.match(/(\d+)\./);
|
|
1130
|
-
return match?.[1] ?? null;
|
|
1313
|
+
const stat = await external_fs_default().promises.stat(external_path_default().join(memberDir, 'package.json'));
|
|
1314
|
+
return stat.isFile();
|
|
1131
1315
|
}
|
|
1132
1316
|
catch {
|
|
1133
|
-
return
|
|
1317
|
+
return false;
|
|
1134
1318
|
}
|
|
1135
1319
|
}
|
|
1136
|
-
function
|
|
1137
|
-
const
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1320
|
+
async function normalizeWorkspaceDepsAsync(memberDir, targetSpec) {
|
|
1321
|
+
const pkgPath = external_path_default().join(memberDir, 'package.json');
|
|
1322
|
+
const pkg = await readJsonFileAsync(pkgPath);
|
|
1323
|
+
if (!pkg) {
|
|
1324
|
+
configureWorkspaces_debug(`Skipping ${pkgPath} (not readable)`);
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
let changed = false;
|
|
1328
|
+
for (const field of WORKSPACE_DEP_FIELDS) {
|
|
1329
|
+
const deps = pkg[field];
|
|
1330
|
+
if (!deps) {
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
for (const [name, spec] of Object.entries(deps)) {
|
|
1334
|
+
if ((spec === 'workspace:*' || spec === '*') && spec !== targetSpec) {
|
|
1335
|
+
deps[name] = targetSpec;
|
|
1336
|
+
changed = true;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
if (changed) {
|
|
1341
|
+
await external_fs_default().promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
1342
|
+
configureWorkspaces_debug(`Normalized workspace deps in ${pkgPath} → "${targetSpec}"`);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
async function readJsonFileAsync(filePath) {
|
|
1346
|
+
try {
|
|
1347
|
+
const contents = await external_fs_default().promises.readFile(filePath, 'utf-8');
|
|
1348
|
+
return JSON.parse(contents);
|
|
1349
|
+
}
|
|
1350
|
+
catch {
|
|
1351
|
+
return undefined;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Ensure `pnpm-workspace.yaml` contains a `packages:` block listing our
|
|
1356
|
+
* workspace patterns. If the file doesn't exist we write it from scratch. If
|
|
1357
|
+
* it does exist (e.g. the template ships its own with extra pnpm settings),
|
|
1358
|
+
* we preserve all existing content and only append `packages:`
|
|
1359
|
+
*/
|
|
1360
|
+
async function ensurePnpmWorkspaceYamlAsync(projectRoot, patterns) {
|
|
1361
|
+
if (patterns.length === 0) {
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
const yamlPath = external_path_default().join(projectRoot, PNPM_WORKSPACE_FILENAME);
|
|
1365
|
+
let existing;
|
|
1366
|
+
try {
|
|
1367
|
+
existing = await external_fs_default().promises.readFile(yamlPath, 'utf-8');
|
|
1368
|
+
}
|
|
1369
|
+
catch (error) {
|
|
1370
|
+
if (error?.code !== 'ENOENT') {
|
|
1371
|
+
configureWorkspaces_debug(`Could not read existing ${yamlPath}: ${error?.message ?? error}`);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
const packagesBlock = [
|
|
1375
|
+
'packages:',
|
|
1376
|
+
...patterns.map((pattern) => ` - ${quoteIfNeeded(pattern)}`),
|
|
1377
|
+
].join('\n');
|
|
1378
|
+
if (existing === undefined) {
|
|
1379
|
+
await external_fs_default().promises.writeFile(yamlPath, `${packagesBlock}\n`, 'utf-8');
|
|
1380
|
+
configureWorkspaces_debug(`Wrote ${yamlPath}`);
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
if (/^packages:/m.test(existing)) {
|
|
1384
|
+
configureWorkspaces_debug(`Existing ${yamlPath} already declares packages; leaving it alone`);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
const needsLeadingNewline = existing.length > 0 && !existing.endsWith('\n');
|
|
1388
|
+
const updated = `${existing}${needsLeadingNewline ? '\n' : ''}${packagesBlock}\n`;
|
|
1389
|
+
await external_fs_default().promises.writeFile(yamlPath, updated, 'utf-8');
|
|
1390
|
+
configureWorkspaces_debug(`Appended packages: to existing ${yamlPath}`);
|
|
1391
|
+
}
|
|
1392
|
+
function quoteIfNeeded(value) {
|
|
1393
|
+
// Quote glob patterns that begin with `*`, `?`, `!`, or `&` so YAML doesn't
|
|
1394
|
+
// mis-parse them as tags or anchors.
|
|
1395
|
+
return /^[!*?&]/.test(value) ? `"${value}"` : value;
|
|
1396
|
+
}
|
|
1141
1397
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1398
|
+
;// CONCATENATED MODULE: ./src/generateAgentFiles.ts
|
|
1399
|
+
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
const AGENT_TEMPLATE_FILE_NAMES = (/* unused pure expression or super */ null && (['AGENTS.md', 'CLAUDE.md']));
|
|
1403
|
+
// Agent templates are synced from `expo/llm-configs` at publish time (see
|
|
1404
|
+
// `scripts/sync-agent-templates.js`) and bundled under `template/agent-files`, so project
|
|
1405
|
+
// creation works offline. `__dirname` is the build output directory, one level below the
|
|
1406
|
+
// package root in both the source tree and the published package.
|
|
1407
|
+
const AGENT_TEMPLATES_DIR = __webpack_require__.ab + "agent-files";
|
|
1408
|
+
function resolveAgentTemplatePath(fileName) {
|
|
1409
|
+
return __webpack_require__.ab + "agent-files/" + fileName;
|
|
1144
1410
|
}
|
|
1145
|
-
const CLAUDE_MD_CONTENT = `@AGENTS.md
|
|
1146
|
-
`;
|
|
1147
1411
|
const CLAUDE_SETTINGS_CONTENT = `{
|
|
1148
1412
|
"enabledPlugins": {
|
|
1149
1413
|
"expo@claude-plugins-official": true
|
|
1150
1414
|
}
|
|
1151
1415
|
}
|
|
1152
1416
|
`;
|
|
1153
|
-
function
|
|
1154
|
-
const
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1417
|
+
function isClaudeCodeInstalled() {
|
|
1418
|
+
const home = external_os_default().homedir();
|
|
1419
|
+
return (!!home &&
|
|
1420
|
+
(external_fs_default().existsSync(external_path_default().join(home, '.claude.json')) || external_fs_default().existsSync(external_path_default().join(home, '.claude'))));
|
|
1421
|
+
}
|
|
1422
|
+
async function copyFileIfMissing(sourcePath, destinationPath) {
|
|
1423
|
+
if (external_fs_default().existsSync(destinationPath)) {
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
const dir = external_path_default().dirname(destinationPath);
|
|
1427
|
+
await external_fs_default().promises.mkdir(dir, { recursive: true });
|
|
1428
|
+
await external_fs_default().promises.copyFile(sourcePath, destinationPath);
|
|
1429
|
+
}
|
|
1430
|
+
async function writeFileIfMissing(filePath, content) {
|
|
1431
|
+
if (external_fs_default().existsSync(filePath)) {
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
const dir = external_path_default().dirname(filePath);
|
|
1435
|
+
await external_fs_default().promises.mkdir(dir, { recursive: true });
|
|
1436
|
+
await external_fs_default().promises.writeFile(filePath, content);
|
|
1437
|
+
}
|
|
1438
|
+
async function generateAgentFiles(root) {
|
|
1439
|
+
const tasks = [
|
|
1440
|
+
copyFileIfMissing(resolveAgentTemplatePath('AGENTS.md'), external_path_default().join(root, 'AGENTS.md')),
|
|
1159
1441
|
];
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
continue;
|
|
1163
|
-
}
|
|
1164
|
-
const dir = external_path_default().dirname(filePath);
|
|
1165
|
-
external_fs_default().mkdirSync(dir, { recursive: true });
|
|
1166
|
-
external_fs_default().writeFileSync(filePath, content);
|
|
1442
|
+
if (isClaudeCodeInstalled()) {
|
|
1443
|
+
tasks.push(copyFileIfMissing(resolveAgentTemplatePath('CLAUDE.md'), external_path_default().join(root, 'CLAUDE.md')), writeFileIfMissing(external_path_default().join(root, '.claude', 'settings.json'), CLAUDE_SETTINGS_CONTENT));
|
|
1167
1444
|
}
|
|
1445
|
+
await Promise.all(tasks);
|
|
1168
1446
|
}
|
|
1169
1447
|
|
|
1170
1448
|
;// CONCATENATED MODULE: ./src/promptSdkVersion.ts
|
|
@@ -1433,12 +1711,23 @@ async function resolveProjectRootAsync(input) {
|
|
|
1433
1711
|
|
|
1434
1712
|
// EXTERNAL MODULE: ./src/telemetry.ts + 2 modules
|
|
1435
1713
|
var telemetry = __webpack_require__(601);
|
|
1714
|
+
// EXTERNAL MODULE: ./src/utils/update-check.ts
|
|
1715
|
+
var update_check = __webpack_require__(7517);
|
|
1436
1716
|
;// CONCATENATED MODULE: ./src/utils/git.ts
|
|
1437
1717
|
|
|
1438
1718
|
|
|
1439
1719
|
|
|
1440
1720
|
|
|
1721
|
+
|
|
1441
1722
|
const git_debug = __webpack_require__(6675)('expo:init:git');
|
|
1723
|
+
const getPackageJson = () => {
|
|
1724
|
+
try {
|
|
1725
|
+
return __webpack_require__(8330);
|
|
1726
|
+
}
|
|
1727
|
+
catch {
|
|
1728
|
+
return null;
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1442
1731
|
/** Check if the given directory is inside an existing git repository */
|
|
1443
1732
|
async function isInsideGitRepoAsync(root) {
|
|
1444
1733
|
try {
|
|
@@ -1487,12 +1776,12 @@ async function initGitRepoAsync(root) {
|
|
|
1487
1776
|
// User explicitly chose not to skip, proceed with git init (creates nested repo)
|
|
1488
1777
|
git_debug(source_default().dim('User chose to initialize git inside existing repo.'));
|
|
1489
1778
|
}
|
|
1490
|
-
const packageJSON =
|
|
1779
|
+
const packageJSON = getPackageJson();
|
|
1491
1780
|
// not in git tree, so let's init
|
|
1492
1781
|
try {
|
|
1493
1782
|
await spawnAsync_default()('git', ['init'], { stdio: 'ignore', cwd: root });
|
|
1494
1783
|
await spawnAsync_default()('git', ['add', '-A'], { stdio: 'ignore', cwd: root });
|
|
1495
|
-
const commitMsg = `Initial commit\n\nGenerated by ${packageJSON.
|
|
1784
|
+
const commitMsg = `Initial commit\n\nGenerated by ${packageJSON?.name ?? update_check.PACKAGE_NAME} ${packageJSON?.version ?? '0.0.0'}.`;
|
|
1496
1785
|
await spawnAsync_default()('git', ['commit', '-m', commitMsg], {
|
|
1497
1786
|
stdio: 'ignore',
|
|
1498
1787
|
cwd: root,
|
|
@@ -1544,6 +1833,7 @@ function withSectionLog(action, message) {
|
|
|
1544
1833
|
|
|
1545
1834
|
|
|
1546
1835
|
|
|
1836
|
+
|
|
1547
1837
|
const createAsync_debug = __webpack_require__(6675)('expo:init:create');
|
|
1548
1838
|
async function resolveProjectRootArgAsync(inputPath, { yes }) {
|
|
1549
1839
|
if (!inputPath && yes) {
|
|
@@ -1560,13 +1850,18 @@ async function resolveProjectRootArgAsync(inputPath, { yes }) {
|
|
|
1560
1850
|
async function setupDependenciesAsync(projectRoot, props) {
|
|
1561
1851
|
const shouldInstall = props.install;
|
|
1562
1852
|
const packageManager = (0,resolvePackageManager/* resolvePackageManager */._c)();
|
|
1853
|
+
// For monorepo templates: normalize workspace-package dependency specs to
|
|
1854
|
+
// the chosen package manager's convention, and write a `pnpm-workspace.yaml`
|
|
1855
|
+
// when pnpm is the resolved manager. No-op for single-app templates.
|
|
1856
|
+
await configureWorkspacesAsync(projectRoot, packageManager);
|
|
1563
1857
|
// Configure package manager, which is unrelated to installing or not
|
|
1564
1858
|
await configureNodeDependenciesAsync(projectRoot, packageManager);
|
|
1565
1859
|
// Install dependencies
|
|
1566
1860
|
let podsInstalled = false;
|
|
1861
|
+
let nodeModulesInstalled = false;
|
|
1567
1862
|
const needsPodsInstalled = await external_fs_default().existsSync(external_path_default().join(projectRoot, 'ios'));
|
|
1568
1863
|
if (shouldInstall) {
|
|
1569
|
-
await installNodeDependenciesAsync(projectRoot, packageManager);
|
|
1864
|
+
nodeModulesInstalled = await installNodeDependenciesAsync(projectRoot, packageManager);
|
|
1570
1865
|
if (needsPodsInstalled) {
|
|
1571
1866
|
podsInstalled = await installCocoaPodsAsync(projectRoot);
|
|
1572
1867
|
}
|
|
@@ -1574,7 +1869,8 @@ async function setupDependenciesAsync(projectRoot, props) {
|
|
|
1574
1869
|
const cdPath = getChangeDirectoryPath(projectRoot);
|
|
1575
1870
|
console.log();
|
|
1576
1871
|
logProjectReady({ cdPath, packageManager });
|
|
1577
|
-
|
|
1872
|
+
// The install can also fail without stopping the command, so check the result and not the flag.
|
|
1873
|
+
if (!nodeModulesInstalled) {
|
|
1578
1874
|
logNodeInstallWarning(cdPath, packageManager, needsPodsInstalled && !podsInstalled);
|
|
1579
1875
|
}
|
|
1580
1876
|
}
|
|
@@ -1612,14 +1908,18 @@ async function createTemplateAsync(inputPath, props) {
|
|
|
1612
1908
|
event: telemetry.AnalyticsEventTypes.CREATE_EXPO_APP,
|
|
1613
1909
|
properties: { phase: telemetry.AnalyticsEventPhases.ATTEMPT, template: resolvedTemplate },
|
|
1614
1910
|
});
|
|
1615
|
-
await withSectionLog(() =>
|
|
1911
|
+
await withSectionLog(async () => {
|
|
1912
|
+
await extractAndPrepareTemplateAppAsync(projectRoot, {
|
|
1913
|
+
npmPackage: resolvedTemplate,
|
|
1914
|
+
});
|
|
1915
|
+
}, {
|
|
1616
1916
|
pending: source_default().bold('Locating project files.'),
|
|
1617
1917
|
success: 'Downloaded and extracted project files.',
|
|
1618
1918
|
error: (error) => `Something went wrong in downloading and extracting the project files: ${error.message}`,
|
|
1619
1919
|
});
|
|
1620
1920
|
await setupDependenciesAsync(projectRoot, props);
|
|
1621
1921
|
if (props.agentsMd) {
|
|
1622
|
-
generateAgentFiles(projectRoot);
|
|
1922
|
+
await generateAgentFiles(projectRoot);
|
|
1623
1923
|
}
|
|
1624
1924
|
// for now, we will just init a git repo if they have git installed and the
|
|
1625
1925
|
// project is not inside an existing git tree, and do it silently. we should
|
|
@@ -1686,14 +1986,16 @@ async function createExampleAsync(inputPath, props) {
|
|
|
1686
1986
|
event: telemetry.AnalyticsEventTypes.CREATE_EXPO_APP,
|
|
1687
1987
|
properties: { phase: telemetry.AnalyticsEventPhases.ATTEMPT, example: resolvedExample },
|
|
1688
1988
|
});
|
|
1689
|
-
await withSectionLog(() =>
|
|
1989
|
+
await withSectionLog(async () => {
|
|
1990
|
+
await downloadAndExtractExampleAsync(projectRoot, resolvedExample);
|
|
1991
|
+
}, {
|
|
1690
1992
|
pending: source_default().bold('Locating example files...'),
|
|
1691
1993
|
success: 'Downloaded and extracted example files.',
|
|
1692
1994
|
error: (error) => `Something went wrong in downloading and extracting the example files: ${error.message}`,
|
|
1693
1995
|
});
|
|
1694
1996
|
await setupDependenciesAsync(projectRoot, props);
|
|
1695
1997
|
if (props.agentsMd) {
|
|
1696
|
-
generateAgentFiles(projectRoot);
|
|
1998
|
+
await generateAgentFiles(projectRoot);
|
|
1697
1999
|
}
|
|
1698
2000
|
// for now, we will just init a git repo if they have git installed and the
|
|
1699
2001
|
// project is not inside an existing git tree, and do it silently. we should
|
|
@@ -1726,14 +2028,17 @@ async function configureNodeDependenciesAsync(projectRoot, packageManager) {
|
|
|
1726
2028
|
log/* Log */.tG.exception(error);
|
|
1727
2029
|
}
|
|
1728
2030
|
}
|
|
2031
|
+
/** Install the node modules. Returns `false` when the package manager failed. */
|
|
1729
2032
|
async function installNodeDependenciesAsync(projectRoot, packageManager) {
|
|
1730
2033
|
try {
|
|
1731
2034
|
await (0,resolvePackageManager/* installDependenciesAsync */.DC)(projectRoot, packageManager, { silent: false });
|
|
2035
|
+
return true;
|
|
1732
2036
|
}
|
|
1733
2037
|
catch (error) {
|
|
1734
2038
|
createAsync_debug(`Error installing node modules: %O`, error);
|
|
1735
2039
|
log/* Log */.tG.error(`Something went wrong installing JavaScript dependencies. Check your ${packageManager} logs. Continuing to create the app.`);
|
|
1736
2040
|
log/* Log */.tG.exception(error);
|
|
2041
|
+
return false;
|
|
1737
2042
|
}
|
|
1738
2043
|
}
|
|
1739
2044
|
async function installCocoaPodsAsync(projectRoot) {
|
|
@@ -1788,7 +2093,6 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1788
2093
|
|
|
1789
2094
|
// EXTERNAL MODULE: ../@expo/json-file/build/JsonFile.js
|
|
1790
2095
|
var JsonFile = __webpack_require__(3064);
|
|
1791
|
-
var JsonFile_default = /*#__PURE__*/__webpack_require__.n(JsonFile);
|
|
1792
2096
|
// EXTERNAL MODULE: external "crypto"
|
|
1793
2097
|
var external_crypto_ = __webpack_require__(6982);
|
|
1794
2098
|
var external_crypto_default = /*#__PURE__*/__webpack_require__.n(external_crypto_);
|
|
@@ -1830,7 +2134,7 @@ const getStateJsonPath = () => external_path_default().join(dotExpoHomeDirectory
|
|
|
1830
2134
|
|
|
1831
2135
|
function getSession() {
|
|
1832
2136
|
try {
|
|
1833
|
-
return
|
|
2137
|
+
return JsonFile["default"].read(getStateJsonPath())?.auth ?? null;
|
|
1834
2138
|
}
|
|
1835
2139
|
catch (error) {
|
|
1836
2140
|
if (error.code === 'ENOENT') {
|
|
@@ -1842,6 +2146,8 @@ function getSession() {
|
|
|
1842
2146
|
|
|
1843
2147
|
// EXTERNAL MODULE: ./src/utils/env.ts
|
|
1844
2148
|
var utils_env = __webpack_require__(4342);
|
|
2149
|
+
// EXTERNAL MODULE: ./src/utils/update-check.ts
|
|
2150
|
+
var update_check = __webpack_require__(7517);
|
|
1845
2151
|
;// CONCATENATED MODULE: ./src/telemetry.ts
|
|
1846
2152
|
|
|
1847
2153
|
|
|
@@ -1850,11 +2156,19 @@ var utils_env = __webpack_require__(4342);
|
|
|
1850
2156
|
|
|
1851
2157
|
|
|
1852
2158
|
|
|
1853
|
-
|
|
2159
|
+
|
|
2160
|
+
const getPackageJson = () => {
|
|
2161
|
+
try {
|
|
2162
|
+
return __webpack_require__(8330);
|
|
2163
|
+
}
|
|
2164
|
+
catch {
|
|
2165
|
+
return null;
|
|
2166
|
+
}
|
|
2167
|
+
};
|
|
1854
2168
|
const xdlUnifiedWriteKey = '1wabJGd5IiuF9Q8SGlcI90v8WTs';
|
|
1855
2169
|
const analyticsEndpoint = 'https://cdp.expo.dev/v1/batch';
|
|
1856
2170
|
const version = '1.0.0';
|
|
1857
|
-
const library =
|
|
2171
|
+
const library = update_check.PACKAGE_NAME;
|
|
1858
2172
|
const messageBatch = [];
|
|
1859
2173
|
let analyticsIdentity = null;
|
|
1860
2174
|
// jest does not clear global variables inbetween tests so we need this helper
|
|
@@ -1911,7 +2225,7 @@ function enqueue(type, message) {
|
|
|
1911
2225
|
message.originalTimestamp = new Date();
|
|
1912
2226
|
}
|
|
1913
2227
|
if (!message.messageId) {
|
|
1914
|
-
// We md5 the
|
|
2228
|
+
// We md5 the message to add more randomness. This is primarily meant
|
|
1915
2229
|
// for use in the browser where the uuid package falls back to Math.random()
|
|
1916
2230
|
// which is not a great source of randomness.
|
|
1917
2231
|
// Borrowed from analytics.js (https://github.com/segment-integrations/analytics.js-integration-segmentio/blob/a20d2a2d222aeb3ab2a8c7e72280f1df2618440e/lib/index.js#L255-L256).
|
|
@@ -1921,7 +2235,7 @@ function enqueue(type, message) {
|
|
|
1921
2235
|
}
|
|
1922
2236
|
messageBatch.push(message);
|
|
1923
2237
|
}
|
|
1924
|
-
// very barebones
|
|
2238
|
+
// very barebones implementation...
|
|
1925
2239
|
// does not support multiple concurrent flushes or large numbers of messages
|
|
1926
2240
|
async function flushAsync() {
|
|
1927
2241
|
if (utils_env.env.EXPO_NO_TELEMETRY)
|
|
@@ -1947,7 +2261,7 @@ async function flushAsync() {
|
|
|
1947
2261
|
await fetch(analyticsEndpoint, request);
|
|
1948
2262
|
}
|
|
1949
2263
|
catch {
|
|
1950
|
-
//
|
|
2264
|
+
// suppress errors - likely due to network connectivity or endpoint health
|
|
1951
2265
|
}
|
|
1952
2266
|
// clear array so we don't resend events in subsequent flushes
|
|
1953
2267
|
messageBatch.splice(0, messageBatch.length);
|
|
@@ -1964,7 +2278,7 @@ function getAnalyticsContext() {
|
|
|
1964
2278
|
return {
|
|
1965
2279
|
os: { name: platform, version: external_os_default().release() },
|
|
1966
2280
|
device: { type: platform, model: platform },
|
|
1967
|
-
app: { name: library, version:
|
|
2281
|
+
app: { name: library, version: getPackageJson()?.version ?? undefined },
|
|
1968
2282
|
};
|
|
1969
2283
|
}
|
|
1970
2284
|
//#endregion
|
|
@@ -1975,7 +2289,7 @@ function uuidv4() {
|
|
|
1975
2289
|
return external_crypto_default().randomUUID();
|
|
1976
2290
|
}
|
|
1977
2291
|
catch {
|
|
1978
|
-
//
|
|
2292
|
+
// suppress errors due to node 13 or less not having randomUUID
|
|
1979
2293
|
return null;
|
|
1980
2294
|
}
|
|
1981
2295
|
}
|
|
@@ -1996,14 +2310,14 @@ async function getAnalyticsIdentityAsync() {
|
|
|
1996
2310
|
if (!external_fs_default().existsSync(getStateJsonPath())) {
|
|
1997
2311
|
external_fs_default().writeFileSync(getStateJsonPath(), JSON.stringify({}));
|
|
1998
2312
|
}
|
|
1999
|
-
const savedDeviceId = await
|
|
2313
|
+
const savedDeviceId = await JsonFile["default"].getAsync(getStateJsonPath(), 'analyticsDeviceId', null);
|
|
2000
2314
|
const deviceId = savedDeviceId ?? uuidv4();
|
|
2001
2315
|
if (!deviceId) {
|
|
2002
2316
|
// unable to generate an id or load one from disk
|
|
2003
2317
|
return null;
|
|
2004
2318
|
}
|
|
2005
2319
|
if (!savedDeviceId) {
|
|
2006
|
-
await
|
|
2320
|
+
await JsonFile["default"].setAsync(getStateJsonPath(), 'analyticsDeviceId', deviceId);
|
|
2007
2321
|
}
|
|
2008
2322
|
const userId = getSession()?.userId ?? null;
|
|
2009
2323
|
return userId ? { anonymousId: deviceId, userId } : { anonymousId: deviceId };
|