create-expo-super-stack 0.1.8 → 0.1.9
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/cli.d.ts +10 -16
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +599 -570
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from
|
|
3
|
-
import { access, mkdir, readdir, readFile, rename, rm, writeFile } from
|
|
4
|
-
import path from
|
|
5
|
-
import { fileURLToPath, pathToFileURL } from
|
|
6
|
-
import { cancel, isCancel, log, text } from
|
|
7
|
-
import { SUPER_STACK_SUCCESS_MESSAGE, collectOnboardPlan, defaultOnboardPlan, savePersonalOnboardDefaults, } from
|
|
8
|
-
import { scaffoldProjectMemory } from
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const CURRENT_EXPO_SDK_VERSION = '~56.0.6';
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { access, mkdir, readdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { cancel, isCancel, log, text } from "@clack/prompts";
|
|
7
|
+
import { SUPER_STACK_SUCCESS_MESSAGE, collectOnboardPlan, defaultOnboardPlan, savePersonalOnboardDefaults, } from "@mr.dj2u/cli/onboarding";
|
|
8
|
+
import { scaffoldProjectMemory } from "@mr.dj2u/cli/project-memory";
|
|
9
|
+
import { generateProjectRoadmap, } from "@mr.dj2u/cli/roadmap";
|
|
10
|
+
const DEFAULT_PROJECT_NAME = "my-expo-app";
|
|
12
11
|
const STYLIST_SYNC_API_ROUTES = [
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
"app/exposition/stylist-sync+api.ts",
|
|
13
|
+
"src/app/exposition/stylist-sync+api.ts",
|
|
15
14
|
];
|
|
16
15
|
export async function main() {
|
|
17
16
|
const initialParsed = parseArgs(process.argv.slice(2));
|
|
@@ -29,7 +28,7 @@ export async function main() {
|
|
|
29
28
|
await runCreateExpoStack(createExpoStackArgs, parsed.mds.createExpoStackBin, projectParentDir);
|
|
30
29
|
}
|
|
31
30
|
else {
|
|
32
|
-
console.log(
|
|
31
|
+
console.log("Skipping create-expo-stack because --mds-skip-create was passed.");
|
|
33
32
|
}
|
|
34
33
|
const projectPath = await resolveGeneratedProjectPath(projectParentDir, projectName);
|
|
35
34
|
const easSelected = await detectEasSetup(projectPath, parsed.createExpoStackArgs);
|
|
@@ -37,13 +36,15 @@ export async function main() {
|
|
|
37
36
|
const plan = parsed.mds.yes
|
|
38
37
|
? defaultOnboardPlan(onboardArgv, projectPath)
|
|
39
38
|
: await collectOnboardPlan(onboardArgv, projectPath);
|
|
40
|
-
const movedAppDir = !parsed.mds.skipCreate && plan.answers.appDirectory ===
|
|
39
|
+
const movedAppDir = !parsed.mds.skipCreate && plan.answers.appDirectory === "src"
|
|
41
40
|
? await moveRootAppIntoSrc(projectPath)
|
|
42
41
|
: null;
|
|
43
|
-
const consolidatedSourceRepairs = !parsed.mds.skipCreate && plan.answers.appDirectory ===
|
|
42
|
+
const consolidatedSourceRepairs = !parsed.mds.skipCreate && plan.answers.appDirectory === "src"
|
|
44
43
|
? await consolidateRootSourceFolders(projectPath)
|
|
45
44
|
: [];
|
|
46
|
-
const movedImportRepairs = movedAppDir
|
|
45
|
+
const movedImportRepairs = movedAppDir
|
|
46
|
+
? await repairMovedSrcAppImports(projectPath)
|
|
47
|
+
: [];
|
|
47
48
|
const written = await scaffoldProjectMemory(projectPath, plan.answers, {
|
|
48
49
|
force: parsed.mds.force,
|
|
49
50
|
guidelinesTemplate: plan.guidelinesTemplate,
|
|
@@ -51,21 +52,24 @@ export async function main() {
|
|
|
51
52
|
manageUniwind: parsed.mds.skipCreate,
|
|
52
53
|
richBoilerplate: plan.richBoilerplate,
|
|
53
54
|
});
|
|
54
|
-
const postScaffoldImportRepairs = movedAppDir
|
|
55
|
+
const postScaffoldImportRepairs = movedAppDir
|
|
56
|
+
? await repairMovedSrcAppImports(projectPath)
|
|
57
|
+
: [];
|
|
55
58
|
const identifierRepairs = await repairExpoProjectIdentifiers(projectPath, projectName, plan.answers.targetPlatforms);
|
|
56
|
-
const stylistWebOutputRepairs = plan.answers.targetPlatforms.includes(
|
|
59
|
+
const stylistWebOutputRepairs = plan.answers.targetPlatforms.includes("web")
|
|
57
60
|
? await repairExpoWebOutputForStylistLifecycle(projectPath, plan.answers.webOutput)
|
|
58
61
|
: [];
|
|
59
62
|
const hasStylistSyncRoute = await hasStylistSyncApiRoute(projectPath);
|
|
60
63
|
const typeSupportRepairs = await repairGeneratedTypeSupport(projectPath, {
|
|
61
|
-
needsNodeTypes:
|
|
62
|
-
needsUniwindTypes: plan.answers.defaults.includes(
|
|
64
|
+
needsNodeTypes: hasStylistSyncRoute,
|
|
65
|
+
needsUniwindTypes: plan.answers.defaults.includes("uniwind"),
|
|
63
66
|
});
|
|
64
67
|
const nativeWindUiPickerRepairs = await repairGeneratedNativeWindUiPicker(projectPath);
|
|
68
|
+
const eslintConfigRepairs = await repairGeneratedEslintConfig(projectPath);
|
|
65
69
|
console.log();
|
|
66
|
-
console.log(
|
|
70
|
+
console.log("MDS onboarding complete.");
|
|
67
71
|
for (const result of written) {
|
|
68
|
-
console.log(`${result.wrote ?
|
|
72
|
+
console.log(`${result.wrote ? "CREATED" : "KEPT"} ${path.relative(process.cwd(), result.filePath)}`);
|
|
69
73
|
}
|
|
70
74
|
if (movedAppDir) {
|
|
71
75
|
console.log(`MOVED ${path.relative(process.cwd(), movedAppDir.from)} -> ${path.relative(process.cwd(), movedAppDir.to)}`);
|
|
@@ -91,42 +95,60 @@ export async function main() {
|
|
|
91
95
|
for (const result of nativeWindUiPickerRepairs) {
|
|
92
96
|
console.log(`UPDATED ${path.relative(process.cwd(), result)}`);
|
|
93
97
|
}
|
|
98
|
+
for (const result of eslintConfigRepairs) {
|
|
99
|
+
console.log(`UPDATED ${path.relative(process.cwd(), result)}`);
|
|
100
|
+
}
|
|
94
101
|
if (plan.saveDefaults) {
|
|
95
102
|
const defaultsPath = savePersonalOnboardDefaults(plan.answers);
|
|
96
103
|
if (defaultsPath) {
|
|
97
104
|
console.log(`Saved personal onboarding defaults: ${defaultsPath}`);
|
|
98
105
|
}
|
|
99
106
|
}
|
|
107
|
+
const roadmapStatus = await generateProjectRoadmap(projectPath, {
|
|
108
|
+
write: false,
|
|
109
|
+
preserveStatus: true,
|
|
110
|
+
});
|
|
111
|
+
if (roadmapStatus.blockedByMarkers) {
|
|
112
|
+
console.log();
|
|
113
|
+
console.log("Roadmap note:");
|
|
114
|
+
console.log("Unresolved # TodoForContext(optional): markers are still present in project/info.md, so MDS intentionally left the scaffolded phase template in place.");
|
|
115
|
+
console.log("Resolve those project/info.md markers first, then run `mds roadmap` or let your agent refresh project/todo.md from project/info.md.");
|
|
116
|
+
}
|
|
117
|
+
else if (roadmapStatus.needsClarification) {
|
|
118
|
+
console.log();
|
|
119
|
+
console.log("Roadmap note:");
|
|
120
|
+
console.log("The project docs are still too generic for a high-confidence derived roadmap, so have your agent ask clarifying questions and then rerun `mds roadmap`.");
|
|
121
|
+
}
|
|
100
122
|
const packageManager = await detectPackageManager(projectPath, parsed.createExpoStackArgs);
|
|
101
123
|
const noInstallRequested = hasNoInstallFlag(parsed.createExpoStackArgs);
|
|
102
124
|
if (shouldRunExpoProjectChecks(parsed, noInstallRequested)) {
|
|
103
|
-
await runExpoProjectChecks(projectPath, packageManager
|
|
104
|
-
useLatestExpoSdk: plan.answers.useLatestExpoSdk,
|
|
105
|
-
});
|
|
125
|
+
await runExpoProjectChecks(projectPath, packageManager);
|
|
106
126
|
}
|
|
107
127
|
else if (noInstallRequested) {
|
|
108
128
|
console.log();
|
|
109
|
-
console.log(
|
|
129
|
+
console.log("Skipped install and Expo dependency repair because create-expo-stack was run with --no-install.");
|
|
110
130
|
}
|
|
111
131
|
console.log();
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
const nextStepsCommands = [
|
|
133
|
+
`cd ${quoteDisplayArg(path.relative(process.cwd(), projectPath) || ".")}`,
|
|
134
|
+
];
|
|
114
135
|
if (noInstallRequested || parsed.mds.skipExpoFix || parsed.mds.skipCreate) {
|
|
115
|
-
|
|
116
|
-
if (
|
|
117
|
-
|
|
136
|
+
nextStepsCommands.push(buildInstallCommand(packageManager).display);
|
|
137
|
+
if (await shouldRunExpoLatestSdkCommand(projectPath)) {
|
|
138
|
+
nextStepsCommands.push(buildExpoLatestSdkCommand(packageManager).display);
|
|
118
139
|
}
|
|
119
|
-
|
|
140
|
+
nextStepsCommands.push(buildExpoInstallFixCommand(packageManager).display);
|
|
120
141
|
if (await shouldInstallExpoFontPeer(projectPath)) {
|
|
121
|
-
|
|
142
|
+
nextStepsCommands.push(buildExpoFontInstallCommand(packageManager).display);
|
|
122
143
|
}
|
|
123
|
-
|
|
144
|
+
nextStepsCommands.push(buildExpoDoctorCommand(packageManager).display);
|
|
124
145
|
}
|
|
125
|
-
|
|
146
|
+
nextStepsCommands.push(buildRunScriptCommand(packageManager, "clear-expo-start"));
|
|
147
|
+
printCopyableCommands("Next steps", nextStepsCommands);
|
|
126
148
|
console.log();
|
|
127
149
|
console.log(SUPER_STACK_SUCCESS_MESSAGE);
|
|
128
150
|
console.log();
|
|
129
|
-
console.log(
|
|
151
|
+
console.log("For the full dev-suite locally, use the generated scripts or install @mr.dj2u/cli in the app.");
|
|
130
152
|
}
|
|
131
153
|
export function prepareCreateExpoStackArgsForWrapper(args, _skipExpoFix = false) {
|
|
132
154
|
return args;
|
|
@@ -146,8 +168,8 @@ export function parseArgs(args) {
|
|
|
146
168
|
if (!arg) {
|
|
147
169
|
continue;
|
|
148
170
|
}
|
|
149
|
-
if (!arg.startsWith(
|
|
150
|
-
if (arg ===
|
|
171
|
+
if (!arg.startsWith("--") && !projectName) {
|
|
172
|
+
if (arg === "-h") {
|
|
151
173
|
helpRequested = true;
|
|
152
174
|
continue;
|
|
153
175
|
}
|
|
@@ -155,192 +177,191 @@ export function parseArgs(args) {
|
|
|
155
177
|
createExpoStackArgs.push(arg);
|
|
156
178
|
continue;
|
|
157
179
|
}
|
|
158
|
-
if (arg ===
|
|
180
|
+
if (arg === "--help" || arg === "-h" || arg === "--mds-help") {
|
|
159
181
|
helpRequested = true;
|
|
160
182
|
continue;
|
|
161
183
|
}
|
|
162
|
-
if (arg ===
|
|
184
|
+
if (arg === "--mds-force") {
|
|
163
185
|
mds.force = true;
|
|
164
186
|
continue;
|
|
165
187
|
}
|
|
166
|
-
if (arg ===
|
|
188
|
+
if (arg === "--mds-no-rich") {
|
|
167
189
|
mds.rich = false;
|
|
168
190
|
continue;
|
|
169
191
|
}
|
|
170
|
-
if (arg ===
|
|
192
|
+
if (arg === "--mds-rich") {
|
|
171
193
|
mds.rich = true;
|
|
172
194
|
continue;
|
|
173
195
|
}
|
|
174
|
-
if (arg ===
|
|
196
|
+
if (arg === "--mds-save-defaults") {
|
|
175
197
|
mds.saveDefaults = true;
|
|
176
198
|
continue;
|
|
177
199
|
}
|
|
178
|
-
if (arg ===
|
|
200
|
+
if (arg === "--mds-no-save-defaults") {
|
|
179
201
|
mds.saveDefaults = false;
|
|
180
202
|
continue;
|
|
181
203
|
}
|
|
182
|
-
if (arg ===
|
|
204
|
+
if (arg === "--mds-yes" || arg === "--mds-non-interactive") {
|
|
183
205
|
mds.yes = true;
|
|
184
206
|
continue;
|
|
185
207
|
}
|
|
186
|
-
if (arg ===
|
|
208
|
+
if (arg === "--mds-skip-create") {
|
|
187
209
|
mds.skipCreate = true;
|
|
188
210
|
continue;
|
|
189
211
|
}
|
|
190
|
-
if (arg ===
|
|
212
|
+
if (arg === "--mds-skip-expo-fix" || arg === "--mds-no-expo-fix") {
|
|
191
213
|
mds.skipExpoFix = true;
|
|
192
214
|
continue;
|
|
193
215
|
}
|
|
194
|
-
if (arg.startsWith(
|
|
195
|
-
mds.createExpoStackBin = arg.slice(
|
|
216
|
+
if (arg.startsWith("--mds-create-expo-stack-bin=")) {
|
|
217
|
+
mds.createExpoStackBin = arg.slice("--mds-create-expo-stack-bin=".length);
|
|
196
218
|
continue;
|
|
197
219
|
}
|
|
198
|
-
if (arg ===
|
|
220
|
+
if (arg === "--mds-guidelines-template") {
|
|
199
221
|
mds.guidelinesTemplate = true;
|
|
200
222
|
continue;
|
|
201
223
|
}
|
|
202
|
-
if (arg ===
|
|
224
|
+
if (arg === "--mds-no-guidelines-template" ||
|
|
225
|
+
arg === "--mds-guidelines-template=false") {
|
|
203
226
|
mds.guidelinesTemplate = false;
|
|
204
227
|
continue;
|
|
205
228
|
}
|
|
206
|
-
if (arg.startsWith(
|
|
229
|
+
if (arg.startsWith("--mds-guidelines-template=")) {
|
|
207
230
|
mds.guidelinesTemplate = true;
|
|
208
|
-
mds.guidelinesTemplatePath = arg.slice(
|
|
231
|
+
mds.guidelinesTemplatePath = arg.slice("--mds-guidelines-template=".length);
|
|
209
232
|
continue;
|
|
210
233
|
}
|
|
211
|
-
if (arg.startsWith(
|
|
234
|
+
if (arg.startsWith("--mds-guidelines-template-path=")) {
|
|
212
235
|
mds.guidelinesTemplate = true;
|
|
213
|
-
mds.guidelinesTemplatePath = arg.slice(
|
|
236
|
+
mds.guidelinesTemplatePath = arg.slice("--mds-guidelines-template-path=".length);
|
|
214
237
|
continue;
|
|
215
238
|
}
|
|
216
|
-
if (arg.startsWith(
|
|
217
|
-
mds.defaults = splitList(arg.slice(
|
|
239
|
+
if (arg.startsWith("--mds-defaults=")) {
|
|
240
|
+
mds.defaults = splitList(arg.slice("--mds-defaults=".length));
|
|
218
241
|
continue;
|
|
219
242
|
}
|
|
220
|
-
if (arg.startsWith(
|
|
221
|
-
mds.appName = arg.slice(
|
|
243
|
+
if (arg.startsWith("--mds-app-name=")) {
|
|
244
|
+
mds.appName = arg.slice("--mds-app-name=".length);
|
|
222
245
|
continue;
|
|
223
246
|
}
|
|
224
|
-
if (arg.startsWith(
|
|
225
|
-
mds.audience = arg.slice(
|
|
247
|
+
if (arg.startsWith("--mds-audience=")) {
|
|
248
|
+
mds.audience = arg.slice("--mds-audience=".length);
|
|
226
249
|
continue;
|
|
227
250
|
}
|
|
228
|
-
if (arg.startsWith(
|
|
229
|
-
mds.coreFlows = arg.slice(
|
|
251
|
+
if (arg.startsWith("--mds-core-flows=")) {
|
|
252
|
+
mds.coreFlows = arg.slice("--mds-core-flows=".length);
|
|
230
253
|
continue;
|
|
231
254
|
}
|
|
232
|
-
if (arg.startsWith(
|
|
233
|
-
mds.screens = arg.slice(
|
|
255
|
+
if (arg.startsWith("--mds-screens=")) {
|
|
256
|
+
mds.screens = arg.slice("--mds-screens=".length);
|
|
234
257
|
continue;
|
|
235
258
|
}
|
|
236
|
-
if (arg.startsWith(
|
|
237
|
-
mds.dataNeeds = arg.slice(
|
|
259
|
+
if (arg.startsWith("--mds-data-needs=")) {
|
|
260
|
+
mds.dataNeeds = arg.slice("--mds-data-needs=".length);
|
|
238
261
|
continue;
|
|
239
262
|
}
|
|
240
|
-
if (arg.startsWith(
|
|
241
|
-
const value = arg.slice(
|
|
242
|
-
if (value ===
|
|
263
|
+
if (arg.startsWith("--mds-data-start=")) {
|
|
264
|
+
const value = arg.slice("--mds-data-start=".length);
|
|
265
|
+
if (value === "local" || value === "supabase") {
|
|
243
266
|
mds.dataStart = value;
|
|
244
267
|
}
|
|
245
268
|
continue;
|
|
246
269
|
}
|
|
247
|
-
if (arg.startsWith(
|
|
248
|
-
mds.deploymentTarget = arg.slice(
|
|
270
|
+
if (arg.startsWith("--mds-deployment-target=")) {
|
|
271
|
+
mds.deploymentTarget = arg.slice("--mds-deployment-target=".length);
|
|
249
272
|
continue;
|
|
250
273
|
}
|
|
251
|
-
if (arg ===
|
|
274
|
+
if (arg === "--mds-test-to-main") {
|
|
252
275
|
mds.testToMain = true;
|
|
253
276
|
continue;
|
|
254
277
|
}
|
|
255
|
-
if (arg ===
|
|
278
|
+
if (arg === "--mds-no-test-to-main") {
|
|
256
279
|
mds.testToMain = false;
|
|
257
280
|
continue;
|
|
258
281
|
}
|
|
259
|
-
if (arg.startsWith(
|
|
260
|
-
mds.platforms = splitList(arg.slice(
|
|
282
|
+
if (arg.startsWith("--mds-platforms=")) {
|
|
283
|
+
mds.platforms = splitList(arg.slice("--mds-platforms=".length));
|
|
261
284
|
continue;
|
|
262
285
|
}
|
|
263
|
-
if (arg.startsWith(
|
|
264
|
-
mds.firstPlatform = arg.slice(
|
|
286
|
+
if (arg.startsWith("--mds-first-platform=")) {
|
|
287
|
+
mds.firstPlatform = arg.slice("--mds-first-platform=".length);
|
|
265
288
|
continue;
|
|
266
289
|
}
|
|
267
|
-
if (arg.startsWith(
|
|
268
|
-
const value = arg.slice(
|
|
269
|
-
if (value ===
|
|
290
|
+
if (arg.startsWith("--mds-platform-strategy=")) {
|
|
291
|
+
const value = arg.slice("--mds-platform-strategy=".length);
|
|
292
|
+
if (value === "folders" || value === "files-only") {
|
|
270
293
|
mds.platformStrategy = value;
|
|
271
294
|
}
|
|
272
295
|
continue;
|
|
273
296
|
}
|
|
274
|
-
if (arg.startsWith(
|
|
275
|
-
const value = arg.slice(
|
|
276
|
-
if (value ===
|
|
297
|
+
if (arg.startsWith("--mds-app-directory=")) {
|
|
298
|
+
const value = arg.slice("--mds-app-directory=".length);
|
|
299
|
+
if (value === "src" || value === "root") {
|
|
277
300
|
mds.appDirectory = value;
|
|
278
301
|
}
|
|
279
302
|
continue;
|
|
280
303
|
}
|
|
281
|
-
if (arg.startsWith(
|
|
282
|
-
const value = arg.slice(
|
|
283
|
-
if (value ===
|
|
304
|
+
if (arg.startsWith("--mds-platform-layouts=")) {
|
|
305
|
+
const value = arg.slice("--mds-platform-layouts=".length);
|
|
306
|
+
if (value === "shared" || value === "platform-specific") {
|
|
284
307
|
mds.platformLayouts = value;
|
|
285
308
|
}
|
|
286
309
|
continue;
|
|
287
310
|
}
|
|
288
|
-
if (arg.startsWith(
|
|
289
|
-
const value = arg.slice(
|
|
290
|
-
if (value ===
|
|
311
|
+
if (arg.startsWith("--mds-web-output=")) {
|
|
312
|
+
const value = arg.slice("--mds-web-output=".length);
|
|
313
|
+
if (value === "static" ||
|
|
314
|
+
value === "server" ||
|
|
315
|
+
value === "spa" ||
|
|
316
|
+
value === "none") {
|
|
291
317
|
mds.webOutput = value;
|
|
292
318
|
}
|
|
293
319
|
continue;
|
|
294
320
|
}
|
|
295
|
-
if (arg.startsWith(
|
|
296
|
-
const value = arg.slice(
|
|
297
|
-
if (value ===
|
|
321
|
+
if (arg.startsWith("--mds-deployed-server=")) {
|
|
322
|
+
const value = arg.slice("--mds-deployed-server=".length);
|
|
323
|
+
if (value === "standard-expo" || value === "custom" || value === "none") {
|
|
298
324
|
mds.deployedServer = value;
|
|
299
325
|
}
|
|
300
326
|
continue;
|
|
301
327
|
}
|
|
302
|
-
if (arg ===
|
|
328
|
+
if (arg === "--mds-create-expo-components") {
|
|
303
329
|
mds.createExpoComponents = true;
|
|
304
330
|
continue;
|
|
305
331
|
}
|
|
306
|
-
if (arg ===
|
|
332
|
+
if (arg === "--mds-no-create-expo-components") {
|
|
307
333
|
mds.createExpoComponents = false;
|
|
308
334
|
continue;
|
|
309
335
|
}
|
|
310
|
-
if (arg ===
|
|
311
|
-
mds.latestExpoSdk = true;
|
|
336
|
+
if (arg === "--mds-latest-expo-sdk" || arg === "--mds-no-latest-expo-sdk") {
|
|
312
337
|
continue;
|
|
313
338
|
}
|
|
314
|
-
if (arg ===
|
|
315
|
-
mds.latestExpoSdk = false;
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
if (arg === '--mds-expo-ui') {
|
|
339
|
+
if (arg === "--mds-expo-ui") {
|
|
319
340
|
mds.expoUi = true;
|
|
320
341
|
continue;
|
|
321
342
|
}
|
|
322
|
-
if (arg ===
|
|
343
|
+
if (arg === "--mds-no-expo-ui") {
|
|
323
344
|
mds.expoUi = false;
|
|
324
345
|
continue;
|
|
325
346
|
}
|
|
326
|
-
if (arg ===
|
|
347
|
+
if (arg === "--mds-expo-ui-universal") {
|
|
327
348
|
mds.expoUiUniversal = true;
|
|
328
349
|
continue;
|
|
329
350
|
}
|
|
330
|
-
if (arg ===
|
|
351
|
+
if (arg === "--mds-no-expo-ui-universal") {
|
|
331
352
|
mds.expoUiUniversal = false;
|
|
332
353
|
continue;
|
|
333
354
|
}
|
|
334
|
-
if (arg ===
|
|
355
|
+
if (arg === "--mds-expo-native-tabs") {
|
|
335
356
|
mds.expoNativeTabs = true;
|
|
336
357
|
continue;
|
|
337
358
|
}
|
|
338
|
-
if (arg ===
|
|
359
|
+
if (arg === "--mds-no-expo-native-tabs") {
|
|
339
360
|
mds.expoNativeTabs = false;
|
|
340
361
|
continue;
|
|
341
362
|
}
|
|
342
|
-
if (arg.startsWith(
|
|
343
|
-
mds.easUses = splitList(arg.slice(
|
|
363
|
+
if (arg.startsWith("--mds-eas-uses=")) {
|
|
364
|
+
mds.easUses = splitList(arg.slice("--mds-eas-uses=".length));
|
|
344
365
|
continue;
|
|
345
366
|
}
|
|
346
367
|
createExpoStackArgs.push(arg);
|
|
@@ -354,33 +375,33 @@ export function parseArgs(args) {
|
|
|
354
375
|
}
|
|
355
376
|
export function renderHelpText() {
|
|
356
377
|
return [
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
].join(
|
|
378
|
+
"create-expo-super-stack",
|
|
379
|
+
"",
|
|
380
|
+
"Usage:",
|
|
381
|
+
" create-expo-super-stack [project-name] [create-expo-stack options] [mds options]",
|
|
382
|
+
"",
|
|
383
|
+
"Examples:",
|
|
384
|
+
" create-expo-super-stack my-app --expo-router --uniwind",
|
|
385
|
+
" create-expo-super-stack ../MyApp --expo-router --mds-yes",
|
|
386
|
+
"",
|
|
387
|
+
"Common mds options:",
|
|
388
|
+
" --mds-yes Run non-interactive onboarding defaults",
|
|
389
|
+
" --mds-save-defaults Save onboarding answers as personal defaults",
|
|
390
|
+
" --mds-no-save-defaults Do not save onboarding answers as personal defaults",
|
|
391
|
+
" --mds-skip-create Skip create-expo-stack and only run onboarding in an existing app",
|
|
392
|
+
" --mds-skip-expo-fix Skip dependency install/fix/doctor repair pass",
|
|
393
|
+
" --mds-guidelines-template Use bundled MDS project/guidelines template",
|
|
394
|
+
" --mds-no-guidelines-template Do not use the bundled MDS project/guidelines template",
|
|
395
|
+
" --mds-app-name=<name> Set display app name for project memory",
|
|
396
|
+
" --mds-screens= List must-include screens for project memory",
|
|
397
|
+
" --mds-expo-ui-universal Use Expo UI Universal components when Expo UI is selected",
|
|
398
|
+
"",
|
|
399
|
+
"Help:",
|
|
400
|
+
" -h, --help Show this help and exit",
|
|
401
|
+
"",
|
|
402
|
+
"Note:",
|
|
403
|
+
" Unknown non-mds flags are forwarded to create-expo-stack.",
|
|
404
|
+
].join("\n");
|
|
384
405
|
}
|
|
385
406
|
export function withResolvedProjectName(parsed, projectName) {
|
|
386
407
|
const target = resolveProjectTarget(parsed.projectName ?? projectName);
|
|
@@ -419,18 +440,18 @@ async function promptForMissingProjectName(parsed) {
|
|
|
419
440
|
return DEFAULT_PROJECT_NAME;
|
|
420
441
|
}
|
|
421
442
|
const answer = await text({
|
|
422
|
-
message:
|
|
443
|
+
message: "What do you want to name your Expo app?",
|
|
423
444
|
placeholder: DEFAULT_PROJECT_NAME,
|
|
424
445
|
defaultValue: DEFAULT_PROJECT_NAME,
|
|
425
446
|
validate: (value) => {
|
|
426
447
|
if (!value.trim()) {
|
|
427
|
-
return
|
|
448
|
+
return "Please enter an app name, or press Enter to use the visible default.";
|
|
428
449
|
}
|
|
429
450
|
return undefined;
|
|
430
451
|
},
|
|
431
452
|
});
|
|
432
453
|
if (isCancel(answer)) {
|
|
433
|
-
cancel(
|
|
454
|
+
cancel("Cancelled. You can rerun create-expo-super-stack whenever you are ready.");
|
|
434
455
|
process.exit(0);
|
|
435
456
|
}
|
|
436
457
|
const projectName = answer.trim() || DEFAULT_PROJECT_NAME;
|
|
@@ -438,9 +459,9 @@ async function promptForMissingProjectName(parsed) {
|
|
|
438
459
|
return projectName;
|
|
439
460
|
}
|
|
440
461
|
function printIntro(projectName, createExpoStackArgs, projectParentDir = process.cwd()) {
|
|
441
|
-
console.log(
|
|
462
|
+
console.log("create-expo-super-stack");
|
|
442
463
|
console.log();
|
|
443
|
-
console.log(
|
|
464
|
+
console.log("This uses create-expo-stack under the hood, then applies MDS onboarding.");
|
|
444
465
|
console.log(`Delegating: create-expo-stack ${formatDisplayArgs(createExpoStackArgs)}`);
|
|
445
466
|
console.log(`Target app: ${projectName}`);
|
|
446
467
|
if (projectParentDir !== process.cwd()) {
|
|
@@ -454,25 +475,27 @@ async function runCreateExpoStack(args, overrideBin, cwd = process.cwd()) {
|
|
|
454
475
|
await new Promise((resolve, reject) => {
|
|
455
476
|
const child = spawn(command.command, [...command.args, ...args], {
|
|
456
477
|
cwd,
|
|
457
|
-
shell: command.shell ?? process.platform ===
|
|
458
|
-
stdio:
|
|
478
|
+
shell: command.shell ?? process.platform === "win32",
|
|
479
|
+
stdio: "inherit",
|
|
459
480
|
windowsHide: true,
|
|
460
481
|
});
|
|
461
|
-
child.on(
|
|
462
|
-
child.on(
|
|
482
|
+
child.on("error", reject);
|
|
483
|
+
child.on("close", (code) => {
|
|
463
484
|
if (code === 0) {
|
|
464
485
|
resolve();
|
|
465
486
|
}
|
|
466
487
|
else {
|
|
467
|
-
reject(new Error(`create-expo-stack exited with code ${code ??
|
|
488
|
+
reject(new Error(`create-expo-stack exited with code ${code ?? "unknown"}.`));
|
|
468
489
|
}
|
|
469
490
|
});
|
|
470
491
|
});
|
|
471
492
|
}
|
|
472
493
|
export function resolveProjectTarget(rawProjectName, cwd = process.cwd()) {
|
|
473
494
|
const trimmed = rawProjectName.trim();
|
|
474
|
-
const normalized = trimmed.replace(/[\\/]+$/u,
|
|
475
|
-
const hasPathSyntax = path.isAbsolute(normalized) ||
|
|
495
|
+
const normalized = trimmed.replace(/[\\/]+$/u, "") || DEFAULT_PROJECT_NAME;
|
|
496
|
+
const hasPathSyntax = path.isAbsolute(normalized) ||
|
|
497
|
+
normalized.includes("/") ||
|
|
498
|
+
normalized.includes("\\");
|
|
476
499
|
if (!hasPathSyntax) {
|
|
477
500
|
return {
|
|
478
501
|
projectName: normalized,
|
|
@@ -488,7 +511,7 @@ export function resolveProjectTarget(rawProjectName, cwd = process.cwd()) {
|
|
|
488
511
|
}
|
|
489
512
|
function replaceProjectArg(args, projectName) {
|
|
490
513
|
const nextArgs = [...args];
|
|
491
|
-
const projectArgIndex = nextArgs.findIndex((arg) => !arg.startsWith(
|
|
514
|
+
const projectArgIndex = nextArgs.findIndex((arg) => !arg.startsWith("--"));
|
|
492
515
|
if (projectArgIndex >= 0) {
|
|
493
516
|
nextArgs[projectArgIndex] = projectName;
|
|
494
517
|
return nextArgs;
|
|
@@ -496,27 +519,24 @@ function replaceProjectArg(args, projectName) {
|
|
|
496
519
|
return [projectName, ...nextArgs];
|
|
497
520
|
}
|
|
498
521
|
export function validateCreateExpoStackArgs(args) {
|
|
499
|
-
const authFlags = [
|
|
522
|
+
const authFlags = ["--supabase", "--firebase"].filter((flag) => args.some((arg) => arg === flag || arg.startsWith(`${flag}=`)));
|
|
500
523
|
if (authFlags.length > 1) {
|
|
501
|
-
throw new Error(`Choose one create-expo-stack auth provider, not ${authFlags.join(
|
|
524
|
+
throw new Error(`Choose one create-expo-stack auth provider, not ${authFlags.join(" and ")}. create-expo-stack scaffolds a single auth slice; Super Stack can still document future data/backend plans in project/.`);
|
|
502
525
|
}
|
|
503
526
|
}
|
|
504
|
-
export async function runExpoProjectChecks(projectPath, packageManager
|
|
527
|
+
export async function runExpoProjectChecks(projectPath, packageManager) {
|
|
505
528
|
console.log();
|
|
506
|
-
console.log(
|
|
529
|
+
console.log("Installing MDS-added dependencies, then running Expo dependency repair and doctor.");
|
|
507
530
|
await runProjectCommand(projectPath, buildInstallCommand(packageManager));
|
|
508
531
|
const missingWindowsOxideBinding = await resolveMissingWindowsTailwindOxideBinding(projectPath);
|
|
509
532
|
if (missingWindowsOxideBinding) {
|
|
510
533
|
await runProjectCommand(projectPath, buildAddDevDependencyCommand(packageManager, missingWindowsOxideBinding));
|
|
511
534
|
}
|
|
512
|
-
if (
|
|
535
|
+
if (await shouldRunExpoLatestSdkCommand(projectPath)) {
|
|
513
536
|
await runProjectCommand(projectPath, buildExpoLatestSdkCommand(packageManager));
|
|
514
537
|
}
|
|
515
|
-
else
|
|
516
|
-
console.log(
|
|
517
|
-
}
|
|
518
|
-
if (await shouldRunExpoPinnedSdkCommand(projectPath)) {
|
|
519
|
-
await runProjectCommand(projectPath, buildExpoPinnedSdkCommand(packageManager));
|
|
538
|
+
else {
|
|
539
|
+
console.log(" Expo already uses the latest release channel; skipping expo@latest.");
|
|
520
540
|
}
|
|
521
541
|
await runProjectCommand(projectPath, buildExpoInstallFixCommand(packageManager));
|
|
522
542
|
if (await shouldInstallExpoFontPeer(projectPath)) {
|
|
@@ -530,26 +550,30 @@ async function runProjectCommand(projectPath, spec) {
|
|
|
530
550
|
await new Promise((resolve, reject) => {
|
|
531
551
|
const child = spawn(spec.command, spec.args, {
|
|
532
552
|
cwd: projectPath,
|
|
533
|
-
shell: spec.shell ?? process.platform ===
|
|
534
|
-
stdio:
|
|
553
|
+
shell: spec.shell ?? process.platform === "win32",
|
|
554
|
+
stdio: "inherit",
|
|
535
555
|
env: spec.env ? { ...process.env, ...spec.env } : process.env,
|
|
536
556
|
windowsHide: true,
|
|
537
557
|
});
|
|
538
|
-
child.on(
|
|
539
|
-
child.on(
|
|
558
|
+
child.on("error", reject);
|
|
559
|
+
child.on("close", (code) => {
|
|
540
560
|
if (code === 0) {
|
|
541
561
|
resolve();
|
|
542
562
|
}
|
|
543
563
|
else {
|
|
544
|
-
reject(new Error(`${spec.display} exited with code ${code ??
|
|
564
|
+
reject(new Error(`${spec.display} exited with code ${code ?? "unknown"}.`));
|
|
545
565
|
}
|
|
546
566
|
});
|
|
547
567
|
});
|
|
548
568
|
}
|
|
549
569
|
async function resolveCreateExpoStackCommand(overrideBin) {
|
|
550
|
-
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)),
|
|
551
|
-
const executable = process.platform ===
|
|
552
|
-
|
|
570
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
571
|
+
const executable = process.platform === "win32"
|
|
572
|
+
? "create-expo-stack.cmd"
|
|
573
|
+
: "create-expo-stack";
|
|
574
|
+
const override = overrideBin ??
|
|
575
|
+
process.env.MRDJ_CREATE_EXPO_STACK_BIN ??
|
|
576
|
+
process.env.CREATE_EXPO_STACK_BIN;
|
|
553
577
|
if (override) {
|
|
554
578
|
const overridePath = path.resolve(override);
|
|
555
579
|
return {
|
|
@@ -559,8 +583,8 @@ async function resolveCreateExpoStackCommand(overrideBin) {
|
|
|
559
583
|
shell: false,
|
|
560
584
|
};
|
|
561
585
|
}
|
|
562
|
-
const localForkCliRoot = path.join(packageRoot,
|
|
563
|
-
const localForkBin = path.join(localForkCliRoot,
|
|
586
|
+
const localForkCliRoot = path.join(packageRoot, "..", "..", "..", "create-expo-stack", "cli");
|
|
587
|
+
const localForkBin = path.join(localForkCliRoot, "bin", "create-expo-stack.js");
|
|
564
588
|
if (await pathExists(localForkBin)) {
|
|
565
589
|
await ensureLocalCreateExpoStackBuild(localForkCliRoot);
|
|
566
590
|
return {
|
|
@@ -571,8 +595,8 @@ async function resolveCreateExpoStackCommand(overrideBin) {
|
|
|
571
595
|
};
|
|
572
596
|
}
|
|
573
597
|
const scopedForkCandidates = [
|
|
574
|
-
path.join(packageRoot,
|
|
575
|
-
path.join(packageRoot,
|
|
598
|
+
path.join(packageRoot, "node_modules", "@mr.dj2u", "create-expo-stack", "bin", "create-expo-stack.js"),
|
|
599
|
+
path.join(packageRoot, "..", "..", "node_modules", "@mr.dj2u", "create-expo-stack", "bin", "create-expo-stack.js"),
|
|
576
600
|
];
|
|
577
601
|
for (const candidate of scopedForkCandidates) {
|
|
578
602
|
if (await pathExists(candidate)) {
|
|
@@ -585,8 +609,8 @@ async function resolveCreateExpoStackCommand(overrideBin) {
|
|
|
585
609
|
}
|
|
586
610
|
}
|
|
587
611
|
const candidates = [
|
|
588
|
-
path.join(packageRoot,
|
|
589
|
-
path.join(packageRoot,
|
|
612
|
+
path.join(packageRoot, "node_modules", ".bin", executable),
|
|
613
|
+
path.join(packageRoot, "..", "..", "node_modules", ".bin", executable),
|
|
590
614
|
];
|
|
591
615
|
for (const candidate of candidates) {
|
|
592
616
|
if (await pathExists(candidate)) {
|
|
@@ -598,58 +622,65 @@ async function resolveCreateExpoStackCommand(overrideBin) {
|
|
|
598
622
|
}
|
|
599
623
|
}
|
|
600
624
|
return {
|
|
601
|
-
command:
|
|
625
|
+
command: "create-expo-stack",
|
|
602
626
|
args: [],
|
|
603
|
-
display:
|
|
627
|
+
display: "create-expo-stack",
|
|
604
628
|
};
|
|
605
629
|
}
|
|
606
630
|
async function ensureLocalCreateExpoStackBuild(localForkCliRoot) {
|
|
607
|
-
const buildEntry = path.join(localForkCliRoot,
|
|
631
|
+
const buildEntry = path.join(localForkCliRoot, "build", "cli.js");
|
|
608
632
|
if (await pathExists(buildEntry)) {
|
|
609
633
|
return;
|
|
610
634
|
}
|
|
611
635
|
console.log(`Building local create-expo-stack fork: ${localForkCliRoot}`);
|
|
612
|
-
if (await commandExists(
|
|
636
|
+
if (await commandExists("bun")) {
|
|
613
637
|
await runProjectCommand(localForkCliRoot, {
|
|
614
|
-
command:
|
|
615
|
-
args: [
|
|
616
|
-
display:
|
|
638
|
+
command: "bun",
|
|
639
|
+
args: ["run", "build"],
|
|
640
|
+
display: "bun run build",
|
|
617
641
|
});
|
|
618
642
|
return;
|
|
619
643
|
}
|
|
620
|
-
console.log(
|
|
621
|
-
if (!(await pathExists(path.join(localForkCliRoot,
|
|
644
|
+
console.log("Bun was not found, so using npm to build the local fork.");
|
|
645
|
+
if (!(await pathExists(path.join(localForkCliRoot, "node_modules")))) {
|
|
622
646
|
await runProjectCommand(localForkCliRoot, {
|
|
623
|
-
command:
|
|
624
|
-
args: [
|
|
625
|
-
display:
|
|
647
|
+
command: "npm",
|
|
648
|
+
args: ["install"],
|
|
649
|
+
display: "npm install",
|
|
626
650
|
});
|
|
627
651
|
}
|
|
628
652
|
await runProjectCommand(localForkCliRoot, {
|
|
629
|
-
command:
|
|
630
|
-
args: [
|
|
631
|
-
display:
|
|
653
|
+
command: "npx",
|
|
654
|
+
args: ["tsc", "-p", "."],
|
|
655
|
+
display: "npx tsc -p .",
|
|
632
656
|
});
|
|
633
657
|
await runProjectCommand(localForkCliRoot, {
|
|
634
|
-
command:
|
|
635
|
-
args: [
|
|
658
|
+
command: "npx",
|
|
659
|
+
args: [
|
|
660
|
+
"copyfiles",
|
|
661
|
+
"-u",
|
|
662
|
+
"2",
|
|
663
|
+
"-a",
|
|
664
|
+
"./src/templates/**/*",
|
|
665
|
+
"./build/templates",
|
|
666
|
+
],
|
|
636
667
|
display: 'npx copyfiles -u 2 -a "./src/templates/**/*" ./build/templates',
|
|
637
668
|
});
|
|
638
669
|
}
|
|
639
670
|
async function commandExists(command) {
|
|
640
671
|
return new Promise((resolve) => {
|
|
641
|
-
const child = spawn(command, [
|
|
642
|
-
shell: process.platform ===
|
|
643
|
-
stdio:
|
|
672
|
+
const child = spawn(command, ["--version"], {
|
|
673
|
+
shell: process.platform === "win32",
|
|
674
|
+
stdio: "ignore",
|
|
644
675
|
windowsHide: true,
|
|
645
676
|
});
|
|
646
|
-
child.on(
|
|
647
|
-
child.on(
|
|
677
|
+
child.on("error", () => resolve(false));
|
|
678
|
+
child.on("close", (code) => resolve(code === 0));
|
|
648
679
|
});
|
|
649
680
|
}
|
|
650
681
|
async function resolveGeneratedProjectPath(cwd, projectName) {
|
|
651
682
|
const directPath = path.resolve(cwd, projectName);
|
|
652
|
-
if (await pathExists(path.join(directPath,
|
|
683
|
+
if (await pathExists(path.join(directPath, "package.json"))) {
|
|
653
684
|
return directPath;
|
|
654
685
|
}
|
|
655
686
|
const fromCesConfig = await findProjectFromCesConfig(cwd, projectName);
|
|
@@ -659,8 +690,8 @@ async function resolveGeneratedProjectPath(cwd, projectName) {
|
|
|
659
690
|
return directPath;
|
|
660
691
|
}
|
|
661
692
|
async function moveRootAppIntoSrc(projectPath) {
|
|
662
|
-
const rootAppDir = path.join(projectPath,
|
|
663
|
-
const srcAppDir = path.join(projectPath,
|
|
693
|
+
const rootAppDir = path.join(projectPath, "app");
|
|
694
|
+
const srcAppDir = path.join(projectPath, "src", "app");
|
|
664
695
|
if (!(await pathExists(rootAppDir)) || (await pathExists(srcAppDir))) {
|
|
665
696
|
return null;
|
|
666
697
|
}
|
|
@@ -669,14 +700,14 @@ async function moveRootAppIntoSrc(projectPath) {
|
|
|
669
700
|
return { from: rootAppDir, to: srcAppDir };
|
|
670
701
|
}
|
|
671
702
|
async function consolidateRootSourceFolders(projectPath) {
|
|
672
|
-
const folderNames = [
|
|
703
|
+
const folderNames = ["components", "theme", "lib"];
|
|
673
704
|
const updatedPaths = [];
|
|
674
705
|
for (const folderName of folderNames) {
|
|
675
706
|
const rootDir = path.join(projectPath, folderName);
|
|
676
707
|
if (!(await pathExists(rootDir))) {
|
|
677
708
|
continue;
|
|
678
709
|
}
|
|
679
|
-
const srcDir = path.join(projectPath,
|
|
710
|
+
const srcDir = path.join(projectPath, "src", folderName);
|
|
680
711
|
if (!(await pathExists(srcDir))) {
|
|
681
712
|
await mkdir(path.dirname(srcDir), { recursive: true });
|
|
682
713
|
await rename(rootDir, srcDir);
|
|
@@ -710,7 +741,7 @@ async function mergeDirectoryInto(sourceDir, targetDir) {
|
|
|
710
741
|
export async function repairMovedSrcAppImports(projectPath) {
|
|
711
742
|
const layoutPaths = [
|
|
712
743
|
{
|
|
713
|
-
filePath: path.join(projectPath,
|
|
744
|
+
filePath: path.join(projectPath, "src", "app", "(tabs)", "_layout.tsx"),
|
|
714
745
|
replacements: [
|
|
715
746
|
['"../components/HeaderButton"', '"../../components/HeaderButton"'],
|
|
716
747
|
['"../components/TabBarIcon"', '"../../components/TabBarIcon"'],
|
|
@@ -719,7 +750,7 @@ export async function repairMovedSrcAppImports(projectPath) {
|
|
|
719
750
|
],
|
|
720
751
|
},
|
|
721
752
|
{
|
|
722
|
-
filePath: path.join(projectPath,
|
|
753
|
+
filePath: path.join(projectPath, "src", "app", "(drawer)", "_layout.tsx"),
|
|
723
754
|
replacements: [
|
|
724
755
|
['"../components/HeaderButton"', '"../../components/HeaderButton"'],
|
|
725
756
|
['"../components/TabBarIcon"', '"../../components/TabBarIcon"'],
|
|
@@ -728,11 +759,17 @@ export async function repairMovedSrcAppImports(projectPath) {
|
|
|
728
759
|
],
|
|
729
760
|
},
|
|
730
761
|
{
|
|
731
|
-
filePath: path.join(projectPath,
|
|
762
|
+
filePath: path.join(projectPath, "src", "app", "(drawer)", "(tabs)", "_layout.tsx"),
|
|
732
763
|
replacements: [
|
|
733
|
-
[
|
|
764
|
+
[
|
|
765
|
+
'"../../components/HeaderButton"',
|
|
766
|
+
'"../../../components/HeaderButton"',
|
|
767
|
+
],
|
|
734
768
|
['"../../components/TabBarIcon"', '"../../../components/TabBarIcon"'],
|
|
735
|
-
[
|
|
769
|
+
[
|
|
770
|
+
"'../../components/HeaderButton'",
|
|
771
|
+
"'../../../components/HeaderButton'",
|
|
772
|
+
],
|
|
736
773
|
["'../../components/TabBarIcon'", "'../../../components/TabBarIcon'"],
|
|
737
774
|
],
|
|
738
775
|
},
|
|
@@ -750,7 +787,7 @@ export async function repairMovedSrcAppImports(projectPath) {
|
|
|
750
787
|
if (updated === raw) {
|
|
751
788
|
continue;
|
|
752
789
|
}
|
|
753
|
-
await writeFile(layout.filePath, updated,
|
|
790
|
+
await writeFile(layout.filePath, updated, "utf8");
|
|
754
791
|
updatedPaths.push(layout.filePath);
|
|
755
792
|
}
|
|
756
793
|
return updatedPaths;
|
|
@@ -759,8 +796,10 @@ export async function repairGeneratedTypeSupport(projectPath, options = {}) {
|
|
|
759
796
|
const updatedPaths = new Set();
|
|
760
797
|
let shouldIncludeUniwindTypes = false;
|
|
761
798
|
if (options.needsUniwindTypes) {
|
|
762
|
-
const packageJson = await readJson(path.join(projectPath,
|
|
763
|
-
const dependencies = isRecord(packageJson.dependencies)
|
|
799
|
+
const packageJson = await readJson(path.join(projectPath, "package.json"));
|
|
800
|
+
const dependencies = isRecord(packageJson.dependencies)
|
|
801
|
+
? packageJson.dependencies
|
|
802
|
+
: {};
|
|
764
803
|
const devDependencies = isRecord(packageJson.devDependencies)
|
|
765
804
|
? packageJson.devDependencies
|
|
766
805
|
: {};
|
|
@@ -768,95 +807,97 @@ export async function repairGeneratedTypeSupport(projectPath, options = {}) {
|
|
|
768
807
|
? packageJson.optionalDependencies
|
|
769
808
|
: {};
|
|
770
809
|
shouldIncludeUniwindTypes =
|
|
771
|
-
typeof dependencies.uniwind ===
|
|
772
|
-
typeof devDependencies.uniwind ===
|
|
773
|
-
typeof optionalDependencies.uniwind ===
|
|
774
|
-
(await pathExists(path.join(projectPath,
|
|
775
|
-
(await pathExists(path.join(projectPath,
|
|
810
|
+
typeof dependencies.uniwind === "string" ||
|
|
811
|
+
typeof devDependencies.uniwind === "string" ||
|
|
812
|
+
typeof optionalDependencies.uniwind === "string" ||
|
|
813
|
+
(await pathExists(path.join(projectPath, "node_modules", "uniwind", "types.d.ts"))) ||
|
|
814
|
+
(await pathExists(path.join(projectPath, "node_modules", "uniwind", "types", "index.d.ts")));
|
|
776
815
|
}
|
|
777
816
|
if (options.needsUniwindTypes) {
|
|
778
|
-
const cssEnvPath = path.join(projectPath,
|
|
779
|
-
const raw = (await readOptionalText(cssEnvPath)) ??
|
|
780
|
-
if (shouldIncludeUniwindTypes && !raw.includes(
|
|
781
|
-
await writeFile(cssEnvPath, `/// <reference types="uniwind/types" />\n\n${raw}`,
|
|
817
|
+
const cssEnvPath = path.join(projectPath, "css-env.d.ts");
|
|
818
|
+
const raw = (await readOptionalText(cssEnvPath)) ?? "";
|
|
819
|
+
if (shouldIncludeUniwindTypes && !raw.includes("uniwind/types")) {
|
|
820
|
+
await writeFile(cssEnvPath, `/// <reference types="uniwind/types" />\n\n${raw}`, "utf8");
|
|
782
821
|
updatedPaths.add(cssEnvPath);
|
|
783
822
|
}
|
|
784
|
-
else if (!shouldIncludeUniwindTypes && raw.includes(
|
|
823
|
+
else if (!shouldIncludeUniwindTypes && raw.includes("uniwind/types")) {
|
|
785
824
|
const updated = raw
|
|
786
|
-
.replace(/^\/\/\/ <reference types="uniwind\/types" \/>\r?\n\r?\n?/m,
|
|
825
|
+
.replace(/^\/\/\/ <reference types="uniwind\/types" \/>\r?\n\r?\n?/m, "")
|
|
787
826
|
.trimStart();
|
|
788
|
-
await writeFile(cssEnvPath, updated,
|
|
827
|
+
await writeFile(cssEnvPath, updated, "utf8");
|
|
789
828
|
updatedPaths.add(cssEnvPath);
|
|
790
829
|
}
|
|
791
830
|
}
|
|
792
831
|
if (options.needsNodeTypes || options.needsUniwindTypes) {
|
|
793
|
-
const tsconfigPath = path.join(projectPath,
|
|
832
|
+
const tsconfigPath = path.join(projectPath, "tsconfig.json");
|
|
794
833
|
const tsconfig = await readJson(tsconfigPath);
|
|
795
|
-
const compilerOptions = isRecord(tsconfig.compilerOptions)
|
|
796
|
-
|
|
797
|
-
|
|
834
|
+
const compilerOptions = isRecord(tsconfig.compilerOptions)
|
|
835
|
+
? tsconfig.compilerOptions
|
|
836
|
+
: {};
|
|
837
|
+
const pathsConfig = isRecord(compilerOptions.paths)
|
|
838
|
+
? compilerOptions.paths
|
|
839
|
+
: {};
|
|
840
|
+
const usingSrcApp = await pathExists(path.join(projectPath, "src", "app"));
|
|
798
841
|
const normalizedPathsConfig = usingSrcApp
|
|
799
842
|
? await normalizeTsconfigPathsForSrcDirectory(projectPath, pathsConfig)
|
|
800
843
|
: pathsConfig;
|
|
801
|
-
const hasAliasPaths = Object.keys(pathsConfig).some((key) => key.includes('@'));
|
|
802
844
|
const existingTypes = Array.isArray(compilerOptions.types)
|
|
803
|
-
? compilerOptions.types.filter((item) => typeof item ===
|
|
845
|
+
? compilerOptions.types.filter((item) => typeof item === "string")
|
|
804
846
|
: [];
|
|
805
847
|
const currentTypes = existingTypes
|
|
806
|
-
? existingTypes.filter((item) => shouldIncludeUniwindTypes || item !==
|
|
848
|
+
? existingTypes.filter((item) => shouldIncludeUniwindTypes || item !== "uniwind/types")
|
|
807
849
|
: [];
|
|
808
850
|
const desiredTypes = [
|
|
809
851
|
...currentTypes,
|
|
810
|
-
...(options.needsNodeTypes ? [
|
|
811
|
-
...(shouldIncludeUniwindTypes ? [
|
|
852
|
+
...(options.needsNodeTypes ? ["node"] : []),
|
|
853
|
+
...(shouldIncludeUniwindTypes ? ["uniwind/types"] : []),
|
|
812
854
|
];
|
|
813
855
|
const nextTypes = Array.from(new Set(desiredTypes));
|
|
814
|
-
const
|
|
815
|
-
const shouldSetIgnoreDeprecations = (shouldSetBaseUrl || typeof compilerOptions.baseUrl === 'string') &&
|
|
816
|
-
compilerOptions.ignoreDeprecations !== '6.0';
|
|
856
|
+
const shouldRemoveDeprecatedTsconfigOptions = "baseUrl" in compilerOptions || "ignoreDeprecations" in compilerOptions;
|
|
817
857
|
const shouldUpdatePaths = JSON.stringify(pathsConfig) !== JSON.stringify(normalizedPathsConfig);
|
|
818
858
|
const shouldUpdateTypes = JSON.stringify(existingTypes) !== JSON.stringify(nextTypes);
|
|
819
|
-
if (shouldUpdateTypes ||
|
|
859
|
+
if (shouldUpdateTypes ||
|
|
860
|
+
shouldRemoveDeprecatedTsconfigOptions ||
|
|
861
|
+
shouldUpdatePaths) {
|
|
862
|
+
const { baseUrl: _baseUrl, ignoreDeprecations: _ignoreDeprecations, ...compilerOptionsWithoutDeprecatedOptions } = compilerOptions;
|
|
820
863
|
tsconfig.compilerOptions = {
|
|
821
|
-
...
|
|
864
|
+
...compilerOptionsWithoutDeprecatedOptions,
|
|
822
865
|
...(shouldUpdatePaths ? { paths: normalizedPathsConfig } : {}),
|
|
823
866
|
types: shouldUpdateTypes ? nextTypes : currentTypes,
|
|
824
|
-
...(shouldSetBaseUrl ? { baseUrl: '.' } : {}),
|
|
825
|
-
...(shouldSetIgnoreDeprecations ? { ignoreDeprecations: '6.0' } : {}),
|
|
826
867
|
};
|
|
827
|
-
await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`,
|
|
868
|
+
await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`, "utf8");
|
|
828
869
|
updatedPaths.add(tsconfigPath);
|
|
829
870
|
}
|
|
830
871
|
}
|
|
831
872
|
if (options.needsNodeTypes) {
|
|
832
|
-
const packageJsonPath = path.join(projectPath,
|
|
873
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
833
874
|
const packageJson = await readJson(packageJsonPath);
|
|
834
875
|
const devDependencies = isRecord(packageJson.devDependencies)
|
|
835
876
|
? packageJson.devDependencies
|
|
836
877
|
: {};
|
|
837
|
-
if (devDependencies[
|
|
878
|
+
if (devDependencies["@types/node"] !== "^25.9.1") {
|
|
838
879
|
packageJson.devDependencies = {
|
|
839
880
|
...devDependencies,
|
|
840
|
-
|
|
881
|
+
"@types/node": "^25.9.1",
|
|
841
882
|
};
|
|
842
|
-
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`,
|
|
883
|
+
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8");
|
|
843
884
|
updatedPaths.add(packageJsonPath);
|
|
844
885
|
}
|
|
845
886
|
}
|
|
846
887
|
const tabBarIconPaths = [
|
|
847
|
-
path.join(projectPath,
|
|
848
|
-
path.join(projectPath,
|
|
888
|
+
path.join(projectPath, "components", "TabBarIcon.tsx"),
|
|
889
|
+
path.join(projectPath, "src", "components", "TabBarIcon.tsx"),
|
|
849
890
|
];
|
|
850
891
|
for (const tabBarIconPath of tabBarIconPaths) {
|
|
851
892
|
const tabBarIconRaw = await readOptionalText(tabBarIconPath);
|
|
852
|
-
if (!tabBarIconRaw || !tabBarIconRaw.includes(
|
|
893
|
+
if (!tabBarIconRaw || !tabBarIconRaw.includes("color: string")) {
|
|
853
894
|
continue;
|
|
854
895
|
}
|
|
855
896
|
const updated = tabBarIconRaw
|
|
856
897
|
.replace("import { StyleSheet } from 'react-native';", "import type { ColorValue } from 'react-native';\nimport { StyleSheet } from 'react-native';")
|
|
857
|
-
.replace(
|
|
898
|
+
.replace("color: string;", "color: ColorValue;");
|
|
858
899
|
if (updated !== tabBarIconRaw) {
|
|
859
|
-
await writeFile(tabBarIconPath, updated,
|
|
900
|
+
await writeFile(tabBarIconPath, updated, "utf8");
|
|
860
901
|
updatedPaths.add(tabBarIconPath);
|
|
861
902
|
}
|
|
862
903
|
}
|
|
@@ -871,7 +912,7 @@ async function normalizeTsconfigPathsForSrcDirectory(projectPath, pathsConfig) {
|
|
|
871
912
|
}
|
|
872
913
|
const nextTargets = [];
|
|
873
914
|
for (const target of targets) {
|
|
874
|
-
if (typeof target !==
|
|
915
|
+
if (typeof target !== "string") {
|
|
875
916
|
nextTargets.push(target);
|
|
876
917
|
continue;
|
|
877
918
|
}
|
|
@@ -883,23 +924,27 @@ async function normalizeTsconfigPathsForSrcDirectory(projectPath, pathsConfig) {
|
|
|
883
924
|
return nextPaths;
|
|
884
925
|
}
|
|
885
926
|
async function normalizeAliasTargetForSrcDirectory(projectPath, alias, target) {
|
|
886
|
-
const normalizedTarget = target.replace(/\\/g,
|
|
887
|
-
if (normalizedTarget.startsWith(
|
|
927
|
+
const normalizedTarget = target.replace(/\\/g, "/").trim();
|
|
928
|
+
if (normalizedTarget.startsWith("./src/") ||
|
|
929
|
+
normalizedTarget.startsWith("src/")) {
|
|
888
930
|
return target;
|
|
889
931
|
}
|
|
890
|
-
if (alias ===
|
|
891
|
-
|
|
932
|
+
if (alias === "@/*" &&
|
|
933
|
+
(normalizedTarget === "./*" || normalizedTarget === "*")) {
|
|
934
|
+
return "./src/*";
|
|
892
935
|
}
|
|
893
|
-
const relativeTarget = normalizedTarget.startsWith(
|
|
936
|
+
const relativeTarget = normalizedTarget.startsWith("./")
|
|
894
937
|
? normalizedTarget.slice(2)
|
|
895
938
|
: normalizedTarget;
|
|
896
|
-
const wildcardSuffix = relativeTarget.endsWith(
|
|
897
|
-
const relativeBase = wildcardSuffix
|
|
898
|
-
|
|
939
|
+
const wildcardSuffix = relativeTarget.endsWith("/*") ? "/*" : "";
|
|
940
|
+
const relativeBase = wildcardSuffix
|
|
941
|
+
? relativeTarget.slice(0, -2)
|
|
942
|
+
: relativeTarget;
|
|
943
|
+
if (!relativeBase || relativeBase === "*") {
|
|
899
944
|
return target;
|
|
900
945
|
}
|
|
901
946
|
const rootCandidate = path.join(projectPath, relativeBase);
|
|
902
|
-
const srcCandidate = path.join(projectPath,
|
|
947
|
+
const srcCandidate = path.join(projectPath, "src", relativeBase);
|
|
903
948
|
const rootExists = await pathExists(rootCandidate);
|
|
904
949
|
const srcExists = await pathExists(srcCandidate);
|
|
905
950
|
if (!rootExists && srcExists) {
|
|
@@ -909,28 +954,41 @@ async function normalizeAliasTargetForSrcDirectory(projectPath, alias, target) {
|
|
|
909
954
|
}
|
|
910
955
|
export async function repairGeneratedNativeWindUiPicker(projectPath) {
|
|
911
956
|
const pickerPaths = [
|
|
912
|
-
path.join(projectPath,
|
|
913
|
-
path.join(projectPath,
|
|
957
|
+
path.join(projectPath, "components", "nativewindui", "Picker.tsx"),
|
|
958
|
+
path.join(projectPath, "src", "components", "nativewindui", "Picker.tsx"),
|
|
914
959
|
];
|
|
915
960
|
const updatedPaths = [];
|
|
916
961
|
for (const pickerPath of pickerPaths) {
|
|
917
962
|
const raw = await readOptionalText(pickerPath);
|
|
918
|
-
if (!raw || !raw.includes(
|
|
963
|
+
if (!raw || !raw.includes("dropdownIconRippleColor=")) {
|
|
919
964
|
continue;
|
|
920
965
|
}
|
|
921
966
|
let updated = raw;
|
|
922
967
|
updated = updated.replace("import { View } from 'react-native';", "import { Platform, View } from 'react-native';");
|
|
923
|
-
updated = updated.replace(
|
|
968
|
+
updated = updated.replace(" dropdownIconRippleColor={dropdownIconRippleColor ?? colors.foreground}", " {...(Platform.OS === 'web' ? {} : { dropdownIconRippleColor: dropdownIconRippleColor ?? colors.foreground })}");
|
|
924
969
|
if (updated === raw) {
|
|
925
970
|
continue;
|
|
926
971
|
}
|
|
927
|
-
await writeFile(pickerPath, updated,
|
|
972
|
+
await writeFile(pickerPath, updated, "utf8");
|
|
928
973
|
updatedPaths.push(pickerPath);
|
|
929
974
|
}
|
|
930
975
|
return updatedPaths;
|
|
931
976
|
}
|
|
977
|
+
export async function repairGeneratedEslintConfig(projectPath) {
|
|
978
|
+
const eslintConfigPath = path.join(projectPath, "eslint.config.js");
|
|
979
|
+
const raw = await readOptionalText(eslintConfigPath);
|
|
980
|
+
if (!raw) {
|
|
981
|
+
return [];
|
|
982
|
+
}
|
|
983
|
+
const updated = raw.replace(/^\/\* eslint-env node \*\/\r?\n/, "");
|
|
984
|
+
if (updated === raw) {
|
|
985
|
+
return [];
|
|
986
|
+
}
|
|
987
|
+
await writeFile(eslintConfigPath, updated, "utf8");
|
|
988
|
+
return [eslintConfigPath];
|
|
989
|
+
}
|
|
932
990
|
export async function repairExpoProjectIdentifiers(projectPath, projectName, targetPlatforms = []) {
|
|
933
|
-
const appJsonPath = path.join(projectPath,
|
|
991
|
+
const appJsonPath = path.join(projectPath, "app.json");
|
|
934
992
|
const raw = await readOptionalText(appJsonPath);
|
|
935
993
|
if (!raw) {
|
|
936
994
|
return [];
|
|
@@ -949,7 +1007,7 @@ export async function repairExpoProjectIdentifiers(projectPath, projectName, tar
|
|
|
949
1007
|
}
|
|
950
1008
|
const nextSlug = toExpoSlug(readString(expo.slug) ?? projectName);
|
|
951
1009
|
const currentScheme = expo.scheme;
|
|
952
|
-
const hasScheme = Object.prototype.hasOwnProperty.call(expo,
|
|
1010
|
+
const hasScheme = Object.prototype.hasOwnProperty.call(expo, "scheme");
|
|
953
1011
|
const nextScheme = hasScheme
|
|
954
1012
|
? Array.isArray(currentScheme)
|
|
955
1013
|
? currentScheme.map((item) => toExpoScheme(readString(item) ?? projectName))
|
|
@@ -960,54 +1018,59 @@ export async function repairExpoProjectIdentifiers(projectPath, projectName, tar
|
|
|
960
1018
|
expo.slug = nextSlug;
|
|
961
1019
|
changed = true;
|
|
962
1020
|
}
|
|
963
|
-
if (hasScheme &&
|
|
1021
|
+
if (hasScheme &&
|
|
1022
|
+
JSON.stringify(currentScheme) !== JSON.stringify(nextScheme)) {
|
|
964
1023
|
expo.scheme = nextScheme;
|
|
965
1024
|
changed = true;
|
|
966
1025
|
}
|
|
967
|
-
const shouldIncludeWeb = targetPlatforms.includes('web');
|
|
968
1026
|
const currentPlatforms = Array.isArray(expo.platforms) ? expo.platforms : [];
|
|
969
|
-
|
|
970
|
-
|
|
1027
|
+
const normalizedTargetPlatforms = Array.from(new Set(targetPlatforms
|
|
1028
|
+
.map((platform) => readString(platform) ?? platform)
|
|
1029
|
+
.filter((platform) => Boolean(platform))));
|
|
1030
|
+
if (normalizedTargetPlatforms.length > 0 &&
|
|
1031
|
+
JSON.stringify(currentPlatforms) !== JSON.stringify(normalizedTargetPlatforms)) {
|
|
1032
|
+
expo.platforms = normalizedTargetPlatforms;
|
|
971
1033
|
changed = true;
|
|
972
1034
|
}
|
|
973
|
-
const shouldIncludeAndroid = targetPlatforms.includes(
|
|
1035
|
+
const shouldIncludeAndroid = targetPlatforms.includes("android");
|
|
974
1036
|
if (shouldIncludeAndroid) {
|
|
975
|
-
if (readString(expo.backgroundColor) !==
|
|
976
|
-
expo.backgroundColor =
|
|
1037
|
+
if (readString(expo.backgroundColor) !== "#f1f0f8") {
|
|
1038
|
+
expo.backgroundColor = "#f1f0f8";
|
|
977
1039
|
changed = true;
|
|
978
1040
|
}
|
|
979
1041
|
const androidConfig = isRecord(expo.android) ? { ...expo.android } : {};
|
|
980
|
-
if (readString(androidConfig.backgroundColor) !==
|
|
981
|
-
androidConfig.backgroundColor =
|
|
1042
|
+
if (readString(androidConfig.backgroundColor) !== "#f1f0f8") {
|
|
1043
|
+
androidConfig.backgroundColor = "#f1f0f8";
|
|
982
1044
|
expo.android = androidConfig;
|
|
983
1045
|
changed = true;
|
|
984
1046
|
}
|
|
985
1047
|
const desiredAndroidStatusBar = {
|
|
986
|
-
backgroundColor:
|
|
987
|
-
barStyle:
|
|
1048
|
+
backgroundColor: "#f1f0f8",
|
|
1049
|
+
barStyle: "dark-content",
|
|
988
1050
|
translucent: false,
|
|
989
1051
|
};
|
|
990
|
-
if (JSON.stringify(expo.androidStatusBar) !==
|
|
1052
|
+
if (JSON.stringify(expo.androidStatusBar) !==
|
|
1053
|
+
JSON.stringify(desiredAndroidStatusBar)) {
|
|
991
1054
|
expo.androidStatusBar = desiredAndroidStatusBar;
|
|
992
1055
|
changed = true;
|
|
993
1056
|
}
|
|
994
|
-
if (Object.prototype.hasOwnProperty.call(expo,
|
|
1057
|
+
if (Object.prototype.hasOwnProperty.call(expo, "androidNavigationBar")) {
|
|
995
1058
|
delete expo.androidNavigationBar;
|
|
996
1059
|
changed = true;
|
|
997
1060
|
}
|
|
998
1061
|
const desiredNavigationBarPlugin = [
|
|
999
|
-
|
|
1062
|
+
"expo-navigation-bar",
|
|
1000
1063
|
{
|
|
1001
|
-
style:
|
|
1064
|
+
style: "dark",
|
|
1002
1065
|
enforceContrast: false,
|
|
1003
1066
|
},
|
|
1004
1067
|
];
|
|
1005
1068
|
const plugins = Array.isArray(expo.plugins) ? [...expo.plugins] : [];
|
|
1006
1069
|
const existingNavigationBarPluginIndex = plugins.findIndex((plugin) => {
|
|
1007
|
-
if (readString(plugin) ===
|
|
1070
|
+
if (readString(plugin) === "expo-navigation-bar") {
|
|
1008
1071
|
return true;
|
|
1009
1072
|
}
|
|
1010
|
-
return Array.isArray(plugin) && readString(plugin[0]) ===
|
|
1073
|
+
return (Array.isArray(plugin) && readString(plugin[0]) === "expo-navigation-bar");
|
|
1011
1074
|
});
|
|
1012
1075
|
if (existingNavigationBarPluginIndex === -1 ||
|
|
1013
1076
|
JSON.stringify(plugins[existingNavigationBarPluginIndex]) !==
|
|
@@ -1021,13 +1084,13 @@ export async function repairExpoProjectIdentifiers(projectPath, projectName, tar
|
|
|
1021
1084
|
changed = true;
|
|
1022
1085
|
}
|
|
1023
1086
|
const hasSystemUiPlugin = plugins.some((plugin) => {
|
|
1024
|
-
if (readString(plugin) ===
|
|
1087
|
+
if (readString(plugin) === "expo-system-ui") {
|
|
1025
1088
|
return true;
|
|
1026
1089
|
}
|
|
1027
|
-
return Array.isArray(plugin) && readString(plugin[0]) ===
|
|
1090
|
+
return (Array.isArray(plugin) && readString(plugin[0]) === "expo-system-ui");
|
|
1028
1091
|
});
|
|
1029
1092
|
if (!hasSystemUiPlugin) {
|
|
1030
|
-
plugins.push(
|
|
1093
|
+
plugins.push("expo-system-ui");
|
|
1031
1094
|
changed = true;
|
|
1032
1095
|
}
|
|
1033
1096
|
if (JSON.stringify(expo.plugins) !== JSON.stringify(plugins)) {
|
|
@@ -1036,34 +1099,35 @@ export async function repairExpoProjectIdentifiers(projectPath, projectName, tar
|
|
|
1036
1099
|
}
|
|
1037
1100
|
}
|
|
1038
1101
|
else {
|
|
1039
|
-
if (Object.prototype.hasOwnProperty.call(expo,
|
|
1102
|
+
if (Object.prototype.hasOwnProperty.call(expo, "androidNavigationBar")) {
|
|
1040
1103
|
delete expo.androidNavigationBar;
|
|
1041
1104
|
changed = true;
|
|
1042
1105
|
}
|
|
1043
|
-
if (Object.prototype.hasOwnProperty.call(expo,
|
|
1106
|
+
if (Object.prototype.hasOwnProperty.call(expo, "androidStatusBar")) {
|
|
1044
1107
|
delete expo.androidStatusBar;
|
|
1045
1108
|
changed = true;
|
|
1046
1109
|
}
|
|
1047
1110
|
}
|
|
1048
1111
|
if (shouldIncludeAndroid) {
|
|
1049
1112
|
const deprecatedNavigationBar = {
|
|
1050
|
-
position:
|
|
1051
|
-
backgroundColor:
|
|
1052
|
-
style:
|
|
1113
|
+
position: "absolute",
|
|
1114
|
+
backgroundColor: "#00000000",
|
|
1115
|
+
style: "dark",
|
|
1053
1116
|
enforceContrast: false,
|
|
1054
1117
|
};
|
|
1055
|
-
if (JSON.stringify(expo.androidNavigationBar) ===
|
|
1118
|
+
if (JSON.stringify(expo.androidNavigationBar) ===
|
|
1119
|
+
JSON.stringify(deprecatedNavigationBar)) {
|
|
1056
1120
|
delete expo.androidNavigationBar;
|
|
1057
1121
|
}
|
|
1058
1122
|
}
|
|
1059
1123
|
if (!changed) {
|
|
1060
1124
|
return [];
|
|
1061
1125
|
}
|
|
1062
|
-
await writeFile(appJsonPath, `${JSON.stringify(parsed, null, 2)}\n`,
|
|
1126
|
+
await writeFile(appJsonPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
|
|
1063
1127
|
return [appJsonPath];
|
|
1064
1128
|
}
|
|
1065
|
-
export async function repairExpoWebOutputForStylistLifecycle(projectPath, preferredWebOutput =
|
|
1066
|
-
const appJsonPath = path.join(projectPath,
|
|
1129
|
+
export async function repairExpoWebOutputForStylistLifecycle(projectPath, preferredWebOutput = "static") {
|
|
1130
|
+
const appJsonPath = path.join(projectPath, "app.json");
|
|
1067
1131
|
const raw = await readOptionalText(appJsonPath);
|
|
1068
1132
|
if (!raw) {
|
|
1069
1133
|
return [];
|
|
@@ -1081,13 +1145,15 @@ export async function repairExpoWebOutputForStylistLifecycle(projectPath, prefer
|
|
|
1081
1145
|
return [];
|
|
1082
1146
|
}
|
|
1083
1147
|
const hasWebPlatform = !Array.isArray(expo.platforms) ||
|
|
1084
|
-
expo.platforms.some((platform) => readString(platform) ===
|
|
1148
|
+
expo.platforms.some((platform) => readString(platform) === "web");
|
|
1085
1149
|
if (!hasWebPlatform) {
|
|
1086
1150
|
return [];
|
|
1087
1151
|
}
|
|
1088
1152
|
const hasStylistSyncRoute = await hasStylistSyncApiRoute(projectPath);
|
|
1089
1153
|
const preferred = normalizeExpoWebOutput(preferredWebOutput);
|
|
1090
|
-
const desiredOutput = hasStylistSyncRoute
|
|
1154
|
+
const desiredOutput = hasStylistSyncRoute
|
|
1155
|
+
? "server"
|
|
1156
|
+
: preferred;
|
|
1091
1157
|
const webConfig = isRecord(expo.web) ? expo.web : {};
|
|
1092
1158
|
const currentOutput = readString(webConfig.output);
|
|
1093
1159
|
if (currentOutput === desiredOutput) {
|
|
@@ -1097,7 +1163,7 @@ export async function repairExpoWebOutputForStylistLifecycle(projectPath, prefer
|
|
|
1097
1163
|
...webConfig,
|
|
1098
1164
|
output: desiredOutput,
|
|
1099
1165
|
};
|
|
1100
|
-
await writeFile(appJsonPath, `${JSON.stringify(parsed, null, 2)}\n`,
|
|
1166
|
+
await writeFile(appJsonPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
|
|
1101
1167
|
return [appJsonPath];
|
|
1102
1168
|
}
|
|
1103
1169
|
async function hasStylistSyncApiRoute(projectPath) {
|
|
@@ -1110,15 +1176,15 @@ async function hasStylistSyncApiRoute(projectPath) {
|
|
|
1110
1176
|
}
|
|
1111
1177
|
function normalizeExpoWebOutput(value) {
|
|
1112
1178
|
switch (value) {
|
|
1113
|
-
case
|
|
1114
|
-
return
|
|
1115
|
-
case
|
|
1116
|
-
return
|
|
1117
|
-
case
|
|
1118
|
-
return
|
|
1119
|
-
case
|
|
1179
|
+
case "server":
|
|
1180
|
+
return "server";
|
|
1181
|
+
case "spa":
|
|
1182
|
+
return "single";
|
|
1183
|
+
case "none":
|
|
1184
|
+
return "static";
|
|
1185
|
+
case "static":
|
|
1120
1186
|
default:
|
|
1121
|
-
return
|
|
1187
|
+
return "static";
|
|
1122
1188
|
}
|
|
1123
1189
|
}
|
|
1124
1190
|
async function findProjectFromCesConfig(cwd, projectName) {
|
|
@@ -1129,7 +1195,7 @@ async function findProjectFromCesConfig(cwd, projectName) {
|
|
|
1129
1195
|
continue;
|
|
1130
1196
|
}
|
|
1131
1197
|
const projectPath = path.join(cwd, entry.name);
|
|
1132
|
-
const raw = await readOptionalText(path.join(projectPath,
|
|
1198
|
+
const raw = await readOptionalText(path.join(projectPath, "cesconfig.jsonc"));
|
|
1133
1199
|
if (!raw) {
|
|
1134
1200
|
continue;
|
|
1135
1201
|
}
|
|
@@ -1145,348 +1211,282 @@ async function findProjectFromCesConfig(cwd, projectName) {
|
|
|
1145
1211
|
return null;
|
|
1146
1212
|
}
|
|
1147
1213
|
async function detectPackageManager(projectPath, args) {
|
|
1148
|
-
if (args.includes(
|
|
1149
|
-
return
|
|
1150
|
-
if (args.includes(
|
|
1151
|
-
return
|
|
1152
|
-
if (args.includes(
|
|
1153
|
-
return
|
|
1154
|
-
if (args.includes(
|
|
1155
|
-
return
|
|
1156
|
-
const packageJson = await readJson(path.join(projectPath,
|
|
1214
|
+
if (args.includes("--pnpm"))
|
|
1215
|
+
return "pnpm";
|
|
1216
|
+
if (args.includes("--yarn"))
|
|
1217
|
+
return "yarn";
|
|
1218
|
+
if (args.includes("--bun"))
|
|
1219
|
+
return "bun";
|
|
1220
|
+
if (args.includes("--npm"))
|
|
1221
|
+
return "npm";
|
|
1222
|
+
const packageJson = await readJson(path.join(projectPath, "package.json"));
|
|
1157
1223
|
const declared = readString(packageJson.packageManager);
|
|
1158
|
-
if (declared?.startsWith(
|
|
1159
|
-
return
|
|
1160
|
-
if (declared?.startsWith(
|
|
1161
|
-
return
|
|
1162
|
-
if (declared?.startsWith(
|
|
1163
|
-
return
|
|
1164
|
-
if (declared?.startsWith(
|
|
1165
|
-
return
|
|
1166
|
-
if (await pathExists(path.join(projectPath,
|
|
1167
|
-
return
|
|
1168
|
-
if (await pathExists(path.join(projectPath,
|
|
1169
|
-
return
|
|
1170
|
-
if ((await pathExists(path.join(projectPath,
|
|
1171
|
-
(await pathExists(path.join(projectPath,
|
|
1172
|
-
return
|
|
1173
|
-
}
|
|
1174
|
-
return
|
|
1224
|
+
if (declared?.startsWith("pnpm@"))
|
|
1225
|
+
return "pnpm";
|
|
1226
|
+
if (declared?.startsWith("yarn@"))
|
|
1227
|
+
return "yarn";
|
|
1228
|
+
if (declared?.startsWith("bun@"))
|
|
1229
|
+
return "bun";
|
|
1230
|
+
if (declared?.startsWith("npm@"))
|
|
1231
|
+
return "npm";
|
|
1232
|
+
if (await pathExists(path.join(projectPath, "pnpm-lock.yaml")))
|
|
1233
|
+
return "pnpm";
|
|
1234
|
+
if (await pathExists(path.join(projectPath, "yarn.lock")))
|
|
1235
|
+
return "yarn";
|
|
1236
|
+
if ((await pathExists(path.join(projectPath, "bun.lock"))) ||
|
|
1237
|
+
(await pathExists(path.join(projectPath, "bun.lockb")))) {
|
|
1238
|
+
return "bun";
|
|
1239
|
+
}
|
|
1240
|
+
return "npm";
|
|
1175
1241
|
}
|
|
1176
1242
|
function shouldRunExpoProjectChecks(parsed, noInstallRequested) {
|
|
1177
|
-
return !parsed.mds.skipCreate && !parsed.mds.skipExpoFix && !noInstallRequested;
|
|
1243
|
+
return (!parsed.mds.skipCreate && !parsed.mds.skipExpoFix && !noInstallRequested);
|
|
1178
1244
|
}
|
|
1179
1245
|
function hasNoInstallFlag(args) {
|
|
1180
1246
|
return args.some((arg) => {
|
|
1181
1247
|
const normalized = arg.trim().toLowerCase();
|
|
1182
|
-
return (normalized ===
|
|
1183
|
-
normalized ===
|
|
1184
|
-
normalized ===
|
|
1185
|
-
normalized ===
|
|
1248
|
+
return (normalized === "--no-install" ||
|
|
1249
|
+
normalized === "--noinstall" ||
|
|
1250
|
+
normalized === "--no-install=true" ||
|
|
1251
|
+
normalized === "--install=false");
|
|
1186
1252
|
});
|
|
1187
1253
|
}
|
|
1188
1254
|
export function buildInstallCommand(packageManager) {
|
|
1189
1255
|
switch (packageManager) {
|
|
1190
|
-
case
|
|
1256
|
+
case "pnpm":
|
|
1191
1257
|
return {
|
|
1192
|
-
command:
|
|
1193
|
-
args: [
|
|
1194
|
-
|
|
1195
|
-
|
|
1258
|
+
command: "pnpm",
|
|
1259
|
+
args: [
|
|
1260
|
+
"install",
|
|
1261
|
+
"--config.strict-dep-builds=false",
|
|
1262
|
+
"--ignore-workspace",
|
|
1263
|
+
],
|
|
1264
|
+
display: "pnpm install --config.strict-dep-builds=false --ignore-workspace",
|
|
1265
|
+
env: { PNPM_CONFIG_STRICT_DEP_BUILDS: "false" },
|
|
1196
1266
|
};
|
|
1197
|
-
case
|
|
1267
|
+
case "yarn":
|
|
1198
1268
|
return {
|
|
1199
|
-
command:
|
|
1200
|
-
args: [
|
|
1201
|
-
display:
|
|
1269
|
+
command: "yarn",
|
|
1270
|
+
args: ["install"],
|
|
1271
|
+
display: "yarn install",
|
|
1202
1272
|
};
|
|
1203
|
-
case
|
|
1273
|
+
case "bun":
|
|
1204
1274
|
return {
|
|
1205
|
-
command:
|
|
1206
|
-
args: [
|
|
1207
|
-
display:
|
|
1275
|
+
command: "bun",
|
|
1276
|
+
args: ["install"],
|
|
1277
|
+
display: "bun install",
|
|
1208
1278
|
};
|
|
1209
|
-
case
|
|
1279
|
+
case "npm":
|
|
1210
1280
|
return {
|
|
1211
|
-
command:
|
|
1212
|
-
args: [
|
|
1213
|
-
display:
|
|
1281
|
+
command: "npm",
|
|
1282
|
+
args: ["install"],
|
|
1283
|
+
display: "npm install",
|
|
1214
1284
|
};
|
|
1215
1285
|
}
|
|
1216
1286
|
}
|
|
1217
1287
|
export function buildExpoInstallFixCommand(packageManager) {
|
|
1218
1288
|
switch (packageManager) {
|
|
1219
|
-
case
|
|
1289
|
+
case "pnpm":
|
|
1220
1290
|
return {
|
|
1221
|
-
command:
|
|
1222
|
-
args: [
|
|
1223
|
-
display:
|
|
1224
|
-
env: { PNPM_CONFIG_STRICT_DEP_BUILDS:
|
|
1291
|
+
command: "pnpm",
|
|
1292
|
+
args: ["--ignore-workspace", "exec", "expo", "install", "--fix"],
|
|
1293
|
+
display: "pnpm --ignore-workspace exec expo install --fix",
|
|
1294
|
+
env: { PNPM_CONFIG_STRICT_DEP_BUILDS: "false" },
|
|
1225
1295
|
};
|
|
1226
|
-
case
|
|
1296
|
+
case "yarn":
|
|
1227
1297
|
return {
|
|
1228
|
-
command:
|
|
1229
|
-
args: [
|
|
1230
|
-
display:
|
|
1298
|
+
command: "yarn",
|
|
1299
|
+
args: ["expo", "install", "--fix"],
|
|
1300
|
+
display: "yarn expo install --fix",
|
|
1231
1301
|
};
|
|
1232
|
-
case
|
|
1302
|
+
case "bun":
|
|
1233
1303
|
return {
|
|
1234
|
-
command:
|
|
1235
|
-
args: [
|
|
1236
|
-
display:
|
|
1304
|
+
command: "bunx",
|
|
1305
|
+
args: ["expo", "install", "--fix"],
|
|
1306
|
+
display: "bunx expo install --fix",
|
|
1237
1307
|
};
|
|
1238
|
-
case
|
|
1308
|
+
case "npm":
|
|
1239
1309
|
return {
|
|
1240
|
-
command:
|
|
1241
|
-
args: [
|
|
1242
|
-
display:
|
|
1310
|
+
command: "npx",
|
|
1311
|
+
args: ["expo", "install", "--fix"],
|
|
1312
|
+
display: "npx expo install --fix",
|
|
1243
1313
|
};
|
|
1244
1314
|
}
|
|
1245
1315
|
}
|
|
1246
1316
|
export function buildExpoLatestSdkCommand(packageManager) {
|
|
1247
1317
|
switch (packageManager) {
|
|
1248
|
-
case
|
|
1318
|
+
case "pnpm":
|
|
1249
1319
|
return {
|
|
1250
|
-
command:
|
|
1251
|
-
args: [
|
|
1252
|
-
display:
|
|
1253
|
-
env: { PNPM_CONFIG_STRICT_DEP_BUILDS:
|
|
1320
|
+
command: "pnpm",
|
|
1321
|
+
args: ["--ignore-workspace", "exec", "expo", "install", "expo@latest"],
|
|
1322
|
+
display: "pnpm --ignore-workspace exec expo install expo@latest",
|
|
1323
|
+
env: { PNPM_CONFIG_STRICT_DEP_BUILDS: "false" },
|
|
1254
1324
|
};
|
|
1255
|
-
case
|
|
1325
|
+
case "yarn":
|
|
1256
1326
|
return {
|
|
1257
|
-
command:
|
|
1258
|
-
args: [
|
|
1259
|
-
display:
|
|
1327
|
+
command: "yarn",
|
|
1328
|
+
args: ["expo", "install", "expo@latest"],
|
|
1329
|
+
display: "yarn expo install expo@latest",
|
|
1260
1330
|
};
|
|
1261
|
-
case
|
|
1331
|
+
case "bun":
|
|
1262
1332
|
return {
|
|
1263
|
-
command:
|
|
1264
|
-
args: [
|
|
1265
|
-
display:
|
|
1333
|
+
command: "bunx",
|
|
1334
|
+
args: ["expo", "install", "expo@latest"],
|
|
1335
|
+
display: "bunx expo install expo@latest",
|
|
1266
1336
|
};
|
|
1267
|
-
case
|
|
1337
|
+
case "npm":
|
|
1268
1338
|
return {
|
|
1269
|
-
command:
|
|
1270
|
-
args: [
|
|
1271
|
-
display:
|
|
1339
|
+
command: "npx",
|
|
1340
|
+
args: ["expo", "install", "expo@latest"],
|
|
1341
|
+
display: "npx expo install expo@latest",
|
|
1272
1342
|
};
|
|
1273
1343
|
}
|
|
1274
1344
|
}
|
|
1275
|
-
export function buildExpoPinnedSdkCommand(packageManager) {
|
|
1276
|
-
const target = `expo@${CURRENT_EXPO_SDK_VERSION}`;
|
|
1277
|
-
switch (packageManager) {
|
|
1278
|
-
case 'pnpm':
|
|
1279
|
-
return {
|
|
1280
|
-
command: 'pnpm',
|
|
1281
|
-
args: ['--ignore-workspace', 'exec', 'expo', 'install', target],
|
|
1282
|
-
display: `pnpm --ignore-workspace exec expo install ${target}`,
|
|
1283
|
-
env: { PNPM_CONFIG_STRICT_DEP_BUILDS: 'false' },
|
|
1284
|
-
};
|
|
1285
|
-
case 'yarn':
|
|
1286
|
-
return {
|
|
1287
|
-
command: 'yarn',
|
|
1288
|
-
args: ['expo', 'install', target],
|
|
1289
|
-
display: `yarn expo install ${target}`,
|
|
1290
|
-
};
|
|
1291
|
-
case 'bun':
|
|
1292
|
-
return {
|
|
1293
|
-
command: 'bunx',
|
|
1294
|
-
args: ['expo', 'install', target],
|
|
1295
|
-
display: `bunx expo install ${target}`,
|
|
1296
|
-
};
|
|
1297
|
-
case 'npm':
|
|
1298
|
-
return {
|
|
1299
|
-
command: 'npx',
|
|
1300
|
-
args: ['expo', 'install', target],
|
|
1301
|
-
display: `npx expo install ${target}`,
|
|
1302
|
-
};
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
export async function shouldRunExpoPinnedSdkCommand(projectPath) {
|
|
1306
|
-
const packageJson = await readJson(path.join(projectPath, 'package.json'));
|
|
1307
|
-
return shouldRunExpoPinnedSdkCommandFromPackageJson(packageJson);
|
|
1308
|
-
}
|
|
1309
|
-
export function shouldRunExpoPinnedSdkCommandFromPackageJson(packageJson) {
|
|
1310
|
-
const dependencies = isRecord(packageJson.dependencies) ? packageJson.dependencies : {};
|
|
1311
|
-
const devDependencies = isRecord(packageJson.devDependencies) ? packageJson.devDependencies : {};
|
|
1312
|
-
const version = readString(dependencies.expo) ?? readString(devDependencies.expo);
|
|
1313
|
-
const current = version ? readSemverTriplet(version) : undefined;
|
|
1314
|
-
const target = readSemverTriplet(CURRENT_EXPO_SDK_VERSION);
|
|
1315
|
-
if (!current || !target) {
|
|
1316
|
-
return false;
|
|
1317
|
-
}
|
|
1318
|
-
if (current.major !== target.major || current.minor !== target.minor) {
|
|
1319
|
-
return false;
|
|
1320
|
-
}
|
|
1321
|
-
return current.patch < target.patch;
|
|
1322
|
-
}
|
|
1323
1345
|
export async function shouldRunExpoLatestSdkCommand(projectPath) {
|
|
1324
|
-
const packageJson = await readJson(path.join(projectPath,
|
|
1346
|
+
const packageJson = await readJson(path.join(projectPath, "package.json"));
|
|
1325
1347
|
return shouldRunExpoLatestSdkCommandFromPackageJson(packageJson);
|
|
1326
1348
|
}
|
|
1327
1349
|
export function shouldRunExpoLatestSdkCommandFromPackageJson(packageJson) {
|
|
1328
|
-
const dependencies = isRecord(packageJson.dependencies)
|
|
1329
|
-
|
|
1350
|
+
const dependencies = isRecord(packageJson.dependencies)
|
|
1351
|
+
? packageJson.dependencies
|
|
1352
|
+
: {};
|
|
1353
|
+
const devDependencies = isRecord(packageJson.devDependencies)
|
|
1354
|
+
? packageJson.devDependencies
|
|
1355
|
+
: {};
|
|
1330
1356
|
const version = readString(dependencies.expo) ?? readString(devDependencies.expo);
|
|
1331
|
-
|
|
1332
|
-
return !version;
|
|
1333
|
-
}
|
|
1334
|
-
const major = readSemverMajor(version);
|
|
1335
|
-
return major === undefined || major < CURRENT_EXPO_SDK_MAJOR;
|
|
1336
|
-
}
|
|
1337
|
-
function readSemverMajor(version) {
|
|
1338
|
-
const match = version.match(/\d+/u);
|
|
1339
|
-
if (!match) {
|
|
1340
|
-
return undefined;
|
|
1341
|
-
}
|
|
1342
|
-
return Number.parseInt(match[0], 10);
|
|
1343
|
-
}
|
|
1344
|
-
function readSemverTriplet(version) {
|
|
1345
|
-
const match = version.match(/(\d+)\.(\d+)\.(\d+)/u);
|
|
1346
|
-
if (!match) {
|
|
1347
|
-
return undefined;
|
|
1348
|
-
}
|
|
1349
|
-
const major = match[1];
|
|
1350
|
-
const minor = match[2];
|
|
1351
|
-
const patch = match[3];
|
|
1352
|
-
if (!major || !minor || !patch) {
|
|
1353
|
-
return undefined;
|
|
1354
|
-
}
|
|
1355
|
-
return {
|
|
1356
|
-
major: Number.parseInt(major, 10),
|
|
1357
|
-
minor: Number.parseInt(minor, 10),
|
|
1358
|
-
patch: Number.parseInt(patch, 10),
|
|
1359
|
-
};
|
|
1357
|
+
return version !== "latest";
|
|
1360
1358
|
}
|
|
1361
1359
|
export function buildExpoFontInstallCommand(packageManager) {
|
|
1362
1360
|
switch (packageManager) {
|
|
1363
|
-
case
|
|
1361
|
+
case "pnpm":
|
|
1364
1362
|
return {
|
|
1365
|
-
command:
|
|
1366
|
-
args: [
|
|
1367
|
-
display:
|
|
1368
|
-
env: { PNPM_CONFIG_STRICT_DEP_BUILDS:
|
|
1363
|
+
command: "pnpm",
|
|
1364
|
+
args: ["--ignore-workspace", "exec", "expo", "install", "expo-font"],
|
|
1365
|
+
display: "pnpm --ignore-workspace exec expo install expo-font",
|
|
1366
|
+
env: { PNPM_CONFIG_STRICT_DEP_BUILDS: "false" },
|
|
1369
1367
|
};
|
|
1370
|
-
case
|
|
1368
|
+
case "yarn":
|
|
1371
1369
|
return {
|
|
1372
|
-
command:
|
|
1373
|
-
args: [
|
|
1374
|
-
display:
|
|
1370
|
+
command: "yarn",
|
|
1371
|
+
args: ["expo", "install", "expo-font"],
|
|
1372
|
+
display: "yarn expo install expo-font",
|
|
1375
1373
|
};
|
|
1376
|
-
case
|
|
1374
|
+
case "bun":
|
|
1377
1375
|
return {
|
|
1378
|
-
command:
|
|
1379
|
-
args: [
|
|
1380
|
-
display:
|
|
1376
|
+
command: "bunx",
|
|
1377
|
+
args: ["expo", "install", "expo-font"],
|
|
1378
|
+
display: "bunx expo install expo-font",
|
|
1381
1379
|
};
|
|
1382
|
-
case
|
|
1380
|
+
case "npm":
|
|
1383
1381
|
return {
|
|
1384
|
-
command:
|
|
1385
|
-
args: [
|
|
1386
|
-
display:
|
|
1382
|
+
command: "npx",
|
|
1383
|
+
args: ["expo", "install", "expo-font"],
|
|
1384
|
+
display: "npx expo install expo-font",
|
|
1387
1385
|
};
|
|
1388
1386
|
}
|
|
1389
1387
|
}
|
|
1390
1388
|
export function buildExpoDoctorCommand(packageManager) {
|
|
1391
1389
|
switch (packageManager) {
|
|
1392
|
-
case
|
|
1390
|
+
case "pnpm":
|
|
1393
1391
|
return {
|
|
1394
|
-
command:
|
|
1395
|
-
args: [
|
|
1396
|
-
display:
|
|
1392
|
+
command: "pnpm",
|
|
1393
|
+
args: ["--ignore-workspace", "dlx", "expo-doctor"],
|
|
1394
|
+
display: "pnpm --ignore-workspace dlx expo-doctor",
|
|
1397
1395
|
};
|
|
1398
|
-
case
|
|
1396
|
+
case "yarn":
|
|
1399
1397
|
return {
|
|
1400
|
-
command:
|
|
1401
|
-
args: [
|
|
1402
|
-
display:
|
|
1398
|
+
command: "yarn",
|
|
1399
|
+
args: ["dlx", "expo-doctor"],
|
|
1400
|
+
display: "yarn dlx expo-doctor",
|
|
1403
1401
|
};
|
|
1404
|
-
case
|
|
1402
|
+
case "bun":
|
|
1405
1403
|
return {
|
|
1406
|
-
command:
|
|
1407
|
-
args: [
|
|
1408
|
-
display:
|
|
1404
|
+
command: "bunx",
|
|
1405
|
+
args: ["expo-doctor"],
|
|
1406
|
+
display: "bunx expo-doctor",
|
|
1409
1407
|
};
|
|
1410
|
-
case
|
|
1408
|
+
case "npm":
|
|
1411
1409
|
return {
|
|
1412
|
-
command:
|
|
1413
|
-
args: [
|
|
1414
|
-
display:
|
|
1410
|
+
command: "npx",
|
|
1411
|
+
args: ["expo-doctor"],
|
|
1412
|
+
display: "npx expo-doctor",
|
|
1415
1413
|
};
|
|
1416
1414
|
}
|
|
1417
1415
|
}
|
|
1418
1416
|
export function buildPrettierWriteCommand(packageManager) {
|
|
1419
|
-
const glob =
|
|
1417
|
+
const glob = "**/*.{js,jsx,ts,tsx,json}";
|
|
1420
1418
|
switch (packageManager) {
|
|
1421
|
-
case
|
|
1419
|
+
case "pnpm":
|
|
1422
1420
|
return {
|
|
1423
|
-
command:
|
|
1424
|
-
args: [
|
|
1421
|
+
command: "pnpm",
|
|
1422
|
+
args: ["exec", "prettier", "--write", glob],
|
|
1425
1423
|
display: `pnpm exec prettier --write "${glob}"`,
|
|
1426
1424
|
};
|
|
1427
|
-
case
|
|
1425
|
+
case "yarn":
|
|
1428
1426
|
return {
|
|
1429
|
-
command:
|
|
1430
|
-
args: [
|
|
1427
|
+
command: "yarn",
|
|
1428
|
+
args: ["prettier", "--write", glob],
|
|
1431
1429
|
display: `yarn prettier --write "${glob}"`,
|
|
1432
1430
|
};
|
|
1433
|
-
case
|
|
1431
|
+
case "bun":
|
|
1434
1432
|
return {
|
|
1435
|
-
command:
|
|
1436
|
-
args: [
|
|
1433
|
+
command: "bunx",
|
|
1434
|
+
args: ["prettier", "--write", glob],
|
|
1437
1435
|
display: `bunx prettier --write "${glob}"`,
|
|
1438
1436
|
};
|
|
1439
|
-
case
|
|
1437
|
+
case "npm":
|
|
1440
1438
|
default:
|
|
1441
1439
|
return {
|
|
1442
|
-
command:
|
|
1443
|
-
args: [
|
|
1440
|
+
command: "npx",
|
|
1441
|
+
args: ["prettier", "--write", glob],
|
|
1444
1442
|
display: `npx prettier --write "${glob}"`,
|
|
1445
1443
|
};
|
|
1446
1444
|
}
|
|
1447
1445
|
}
|
|
1448
1446
|
export function buildAddDevDependencyCommand(packageManager, dependency) {
|
|
1449
1447
|
switch (packageManager) {
|
|
1450
|
-
case
|
|
1448
|
+
case "pnpm":
|
|
1451
1449
|
return {
|
|
1452
|
-
command:
|
|
1453
|
-
args: [
|
|
1450
|
+
command: "pnpm",
|
|
1451
|
+
args: ["--ignore-workspace", "add", "-D", dependency],
|
|
1454
1452
|
display: `pnpm --ignore-workspace add -D ${dependency}`,
|
|
1455
|
-
env: { PNPM_CONFIG_STRICT_DEP_BUILDS:
|
|
1453
|
+
env: { PNPM_CONFIG_STRICT_DEP_BUILDS: "false" },
|
|
1456
1454
|
};
|
|
1457
|
-
case
|
|
1455
|
+
case "yarn":
|
|
1458
1456
|
return {
|
|
1459
|
-
command:
|
|
1460
|
-
args: [
|
|
1457
|
+
command: "yarn",
|
|
1458
|
+
args: ["add", "--dev", dependency],
|
|
1461
1459
|
display: `yarn add --dev ${dependency}`,
|
|
1462
1460
|
};
|
|
1463
|
-
case
|
|
1461
|
+
case "bun":
|
|
1464
1462
|
return {
|
|
1465
|
-
command:
|
|
1466
|
-
args: [
|
|
1463
|
+
command: "bun",
|
|
1464
|
+
args: ["add", "--dev", dependency],
|
|
1467
1465
|
display: `bun add --dev ${dependency}`,
|
|
1468
1466
|
};
|
|
1469
|
-
case
|
|
1467
|
+
case "npm":
|
|
1470
1468
|
return {
|
|
1471
|
-
command:
|
|
1472
|
-
args: [
|
|
1469
|
+
command: "npm",
|
|
1470
|
+
args: ["install", "--save-dev", dependency],
|
|
1473
1471
|
display: `npm install --save-dev ${dependency}`,
|
|
1474
1472
|
};
|
|
1475
1473
|
}
|
|
1476
1474
|
}
|
|
1477
1475
|
export function resolveWindowsTailwindOxidePackage({ platform = process.platform, arch = process.arch, nodeTargetType = process.config?.variables?.node_target_type, shlibSuffix = process.config?.variables?.shlib_suffix, } = {}) {
|
|
1478
|
-
if (platform !==
|
|
1476
|
+
if (platform !== "win32") {
|
|
1479
1477
|
return undefined;
|
|
1480
1478
|
}
|
|
1481
|
-
if (arch ===
|
|
1482
|
-
const usesGnu = shlibSuffix ===
|
|
1483
|
-
return usesGnu
|
|
1479
|
+
if (arch === "x64") {
|
|
1480
|
+
const usesGnu = shlibSuffix === "dll.a" || nodeTargetType === "shared_library";
|
|
1481
|
+
return usesGnu
|
|
1482
|
+
? "@tailwindcss/oxide-win32-x64-gnu"
|
|
1483
|
+
: "@tailwindcss/oxide-win32-x64-msvc";
|
|
1484
1484
|
}
|
|
1485
|
-
if (arch ===
|
|
1486
|
-
return
|
|
1485
|
+
if (arch === "ia32") {
|
|
1486
|
+
return "@tailwindcss/oxide-win32-ia32-msvc";
|
|
1487
1487
|
}
|
|
1488
|
-
if (arch ===
|
|
1489
|
-
return
|
|
1488
|
+
if (arch === "arm64") {
|
|
1489
|
+
return "@tailwindcss/oxide-win32-arm64-msvc";
|
|
1490
1490
|
}
|
|
1491
1491
|
return undefined;
|
|
1492
1492
|
}
|
|
@@ -1495,46 +1495,55 @@ export async function resolveMissingWindowsTailwindOxideBinding(projectPath) {
|
|
|
1495
1495
|
if (!packageName) {
|
|
1496
1496
|
return undefined;
|
|
1497
1497
|
}
|
|
1498
|
-
const packageJson = await readJson(path.join(projectPath,
|
|
1499
|
-
const dependencies = isRecord(packageJson.dependencies)
|
|
1500
|
-
|
|
1501
|
-
|
|
1498
|
+
const packageJson = await readJson(path.join(projectPath, "package.json"));
|
|
1499
|
+
const dependencies = isRecord(packageJson.dependencies)
|
|
1500
|
+
? packageJson.dependencies
|
|
1501
|
+
: {};
|
|
1502
|
+
const devDependencies = isRecord(packageJson.devDependencies)
|
|
1503
|
+
? packageJson.devDependencies
|
|
1504
|
+
: {};
|
|
1505
|
+
const hasUniwind = typeof dependencies.uniwind === "string" ||
|
|
1506
|
+
typeof devDependencies.uniwind === "string";
|
|
1502
1507
|
if (!hasUniwind) {
|
|
1503
1508
|
return undefined;
|
|
1504
1509
|
}
|
|
1505
|
-
if (await pathExists(path.join(projectPath,
|
|
1510
|
+
if (await pathExists(path.join(projectPath, "node_modules", packageName))) {
|
|
1506
1511
|
return undefined;
|
|
1507
1512
|
}
|
|
1508
|
-
const oxidePackageJsonPath = path.join(projectPath,
|
|
1513
|
+
const oxidePackageJsonPath = path.join(projectPath, "node_modules", "@tailwindcss", "oxide", "package.json");
|
|
1509
1514
|
const oxidePackage = await readJson(oxidePackageJsonPath);
|
|
1510
1515
|
const oxideVersion = readString(oxidePackage.version);
|
|
1511
1516
|
return oxideVersion ? `${packageName}@${oxideVersion}` : packageName;
|
|
1512
1517
|
}
|
|
1513
1518
|
export async function shouldInstallExpoFontPeer(projectPath) {
|
|
1514
|
-
const packageJson = await readJson(path.join(projectPath,
|
|
1519
|
+
const packageJson = await readJson(path.join(projectPath, "package.json"));
|
|
1515
1520
|
return shouldInstallExpoFontPeerFromPackageJson(packageJson);
|
|
1516
1521
|
}
|
|
1517
1522
|
export function shouldInstallExpoFontPeerFromPackageJson(packageJson) {
|
|
1518
|
-
const dependencies = isRecord(packageJson.dependencies)
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1523
|
+
const dependencies = isRecord(packageJson.dependencies)
|
|
1524
|
+
? packageJson.dependencies
|
|
1525
|
+
: {};
|
|
1526
|
+
const devDependencies = isRecord(packageJson.devDependencies)
|
|
1527
|
+
? packageJson.devDependencies
|
|
1528
|
+
: {};
|
|
1529
|
+
const hasVectorIcons = typeof dependencies["@expo/vector-icons"] === "string" ||
|
|
1530
|
+
typeof devDependencies["@expo/vector-icons"] === "string";
|
|
1531
|
+
const hasExpoFont = typeof dependencies["expo-font"] === "string" ||
|
|
1532
|
+
typeof devDependencies["expo-font"] === "string";
|
|
1524
1533
|
return hasVectorIcons && !hasExpoFont;
|
|
1525
1534
|
}
|
|
1526
1535
|
export async function detectEasSetup(projectPath, createExpoStackArgs) {
|
|
1527
|
-
if (hasFlag(createExpoStackArgs,
|
|
1536
|
+
if (hasFlag(createExpoStackArgs, "--eas")) {
|
|
1528
1537
|
return true;
|
|
1529
1538
|
}
|
|
1530
|
-
if (await pathExists(path.join(projectPath,
|
|
1539
|
+
if (await pathExists(path.join(projectPath, "eas.json"))) {
|
|
1531
1540
|
return true;
|
|
1532
1541
|
}
|
|
1533
|
-
const appJson = await readJson(path.join(projectPath,
|
|
1542
|
+
const appJson = await readJson(path.join(projectPath, "app.json"));
|
|
1534
1543
|
if (hasExpoEasProjectId(appJson)) {
|
|
1535
1544
|
return true;
|
|
1536
1545
|
}
|
|
1537
|
-
const appConfigJson = await readJson(path.join(projectPath,
|
|
1546
|
+
const appConfigJson = await readJson(path.join(projectPath, "app.config.json"));
|
|
1538
1547
|
if (hasExpoEasProjectId(appConfigJson)) {
|
|
1539
1548
|
return true;
|
|
1540
1549
|
}
|
|
@@ -1547,22 +1556,22 @@ function hasExpoEasProjectId(config) {
|
|
|
1547
1556
|
const expo = isRecord(config.expo) ? config.expo : config;
|
|
1548
1557
|
const extra = isRecord(expo.extra) ? expo.extra : undefined;
|
|
1549
1558
|
const eas = extra && isRecord(extra.eas) ? extra.eas : undefined;
|
|
1550
|
-
return typeof eas?.projectId ===
|
|
1559
|
+
return typeof eas?.projectId === "string" && eas.projectId.trim().length > 0;
|
|
1551
1560
|
}
|
|
1552
1561
|
function buildRunScriptCommand(packageManager, script) {
|
|
1553
1562
|
switch (packageManager) {
|
|
1554
|
-
case
|
|
1563
|
+
case "pnpm":
|
|
1555
1564
|
return `pnpm ${script}`;
|
|
1556
|
-
case
|
|
1565
|
+
case "yarn":
|
|
1557
1566
|
return `yarn ${script}`;
|
|
1558
|
-
case
|
|
1567
|
+
case "bun":
|
|
1559
1568
|
return `bun run ${script}`;
|
|
1560
|
-
case
|
|
1569
|
+
case "npm":
|
|
1561
1570
|
return `npm run ${script}`;
|
|
1562
1571
|
}
|
|
1563
1572
|
}
|
|
1564
1573
|
function formatDisplayArgs(args) {
|
|
1565
|
-
return args.map(quoteDisplayArg).join(
|
|
1574
|
+
return args.map(quoteDisplayArg).join(" ");
|
|
1566
1575
|
}
|
|
1567
1576
|
function quoteDisplayArg(value) {
|
|
1568
1577
|
if (!value || /[\s"]/u.test(value)) {
|
|
@@ -1570,6 +1579,27 @@ function quoteDisplayArg(value) {
|
|
|
1570
1579
|
}
|
|
1571
1580
|
return value;
|
|
1572
1581
|
}
|
|
1582
|
+
function printCopyableCommands(title, commands) {
|
|
1583
|
+
console.log(`${title} (copy this):`);
|
|
1584
|
+
console.log(renderCommandBox(commands));
|
|
1585
|
+
}
|
|
1586
|
+
function renderCommandBox(commands) {
|
|
1587
|
+
const visibleCommands = commands.filter((command) => command.trim().length > 0);
|
|
1588
|
+
if (visibleCommands.length === 0) {
|
|
1589
|
+
return "";
|
|
1590
|
+
}
|
|
1591
|
+
const formattedCommands = visibleCommands.map((command) => colorizeCommand(`> ${command}`));
|
|
1592
|
+
return ["┌", ...formattedCommands.map((command) => `│ ${command}`), "└"].join("\n");
|
|
1593
|
+
}
|
|
1594
|
+
function colorizeCommand(command) {
|
|
1595
|
+
if (!supportsAnsiColor()) {
|
|
1596
|
+
return command;
|
|
1597
|
+
}
|
|
1598
|
+
return `\x1b[36m${command}\x1b[0m`;
|
|
1599
|
+
}
|
|
1600
|
+
function supportsAnsiColor() {
|
|
1601
|
+
return process.stdout.isTTY === true && process.env.TERM !== "dumb";
|
|
1602
|
+
}
|
|
1573
1603
|
function buildOnboardArgv(projectPath, parsed, easSelected) {
|
|
1574
1604
|
return {
|
|
1575
1605
|
project: projectPath,
|
|
@@ -1592,12 +1622,11 @@ function buildOnboardArgv(projectPath, parsed, easSelected) {
|
|
|
1592
1622
|
platforms: parsed.mds.platforms,
|
|
1593
1623
|
firstPlatform: parsed.mds.firstPlatform,
|
|
1594
1624
|
platformStrategy: parsed.mds.platformStrategy,
|
|
1595
|
-
appDirectory: parsed.mds.appDirectory ??
|
|
1625
|
+
appDirectory: parsed.mds.appDirectory ?? "src",
|
|
1596
1626
|
platformLayouts: parsed.mds.platformLayouts,
|
|
1597
1627
|
webOutput: parsed.mds.webOutput,
|
|
1598
1628
|
deployedServer: parsed.mds.deployedServer,
|
|
1599
1629
|
createExpoComponents: parsed.mds.createExpoComponents,
|
|
1600
|
-
latestExpoSdk: parsed.mds.latestExpoSdk,
|
|
1601
1630
|
expoUi: parsed.mds.expoUi,
|
|
1602
1631
|
expoUiUniversal: parsed.mds.expoUiUniversal,
|
|
1603
1632
|
expoNativeTabs: parsed.mds.expoNativeTabs,
|
|
@@ -1606,7 +1635,7 @@ function buildOnboardArgv(projectPath, parsed, easSelected) {
|
|
|
1606
1635
|
}
|
|
1607
1636
|
function splitList(value) {
|
|
1608
1637
|
return value
|
|
1609
|
-
.split(
|
|
1638
|
+
.split(",")
|
|
1610
1639
|
.map((item) => item.trim())
|
|
1611
1640
|
.filter(Boolean);
|
|
1612
1641
|
}
|
|
@@ -1621,7 +1650,7 @@ async function pathExists(filePath) {
|
|
|
1621
1650
|
}
|
|
1622
1651
|
async function readOptionalText(filePath) {
|
|
1623
1652
|
try {
|
|
1624
|
-
return await readFile(filePath,
|
|
1653
|
+
return await readFile(filePath, "utf8");
|
|
1625
1654
|
}
|
|
1626
1655
|
catch {
|
|
1627
1656
|
return null;
|
|
@@ -1641,32 +1670,32 @@ async function readJson(filePath) {
|
|
|
1641
1670
|
}
|
|
1642
1671
|
}
|
|
1643
1672
|
function parseJsonc(value) {
|
|
1644
|
-
const cleaned = value.replace(/^\s*\/\/.*$/gm,
|
|
1673
|
+
const cleaned = value.replace(/^\s*\/\/.*$/gm, "");
|
|
1645
1674
|
const parsed = JSON.parse(cleaned);
|
|
1646
1675
|
return isRecord(parsed) ? parsed : {};
|
|
1647
1676
|
}
|
|
1648
1677
|
function readString(value) {
|
|
1649
|
-
return typeof value ===
|
|
1678
|
+
return typeof value === "string" ? value : undefined;
|
|
1650
1679
|
}
|
|
1651
1680
|
export function toExpoSlug(value) {
|
|
1652
1681
|
const slug = value
|
|
1653
1682
|
.trim()
|
|
1654
1683
|
.toLowerCase()
|
|
1655
|
-
.replace(/[^a-z0-9_-]+/g,
|
|
1656
|
-
.replace(/^-+|-+$/g,
|
|
1657
|
-
return slug ||
|
|
1684
|
+
.replace(/[^a-z0-9_-]+/g, "-")
|
|
1685
|
+
.replace(/^-+|-+$/g, "");
|
|
1686
|
+
return slug || "expo-app";
|
|
1658
1687
|
}
|
|
1659
1688
|
export function toExpoScheme(value) {
|
|
1660
1689
|
const scheme = value
|
|
1661
1690
|
.trim()
|
|
1662
1691
|
.toLowerCase()
|
|
1663
|
-
.replace(/[^a-z0-9+.-]+/g,
|
|
1664
|
-
.replace(/^[^a-z]+/,
|
|
1665
|
-
.replace(/-+$/g,
|
|
1666
|
-
return scheme ||
|
|
1692
|
+
.replace(/[^a-z0-9+.-]+/g, "-")
|
|
1693
|
+
.replace(/^[^a-z]+/, "")
|
|
1694
|
+
.replace(/-+$/g, "");
|
|
1695
|
+
return scheme || "expo-app";
|
|
1667
1696
|
}
|
|
1668
1697
|
function isRecord(value) {
|
|
1669
|
-
return typeof value ===
|
|
1698
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1670
1699
|
}
|
|
1671
1700
|
export function isCliEntryPoint(argv = process.argv) {
|
|
1672
1701
|
const entry = argv[1];
|