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