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