create-expo-module 0.5.12 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/create-expo-module.js +95 -47
- package/build/create-expo-module.js.map +1 -1
- package/build/prompts.d.ts +2 -0
- package/build/prompts.js +47 -3
- package/build/prompts.js.map +1 -1
- package/build/types.d.ts +12 -0
- package/build/types.js.map +1 -1
- package/package.json +4 -2
- package/src/create-expo-module.ts +129 -53
- package/src/prompts.ts +52 -5
- package/src/types.ts +13 -0
|
@@ -8,6 +8,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
9
|
const download_tarball_1 = __importDefault(require("download-tarball"));
|
|
10
10
|
const ejs_1 = __importDefault(require("ejs"));
|
|
11
|
+
const find_up_1 = __importDefault(require("find-up"));
|
|
11
12
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
13
|
const getenv_1 = require("getenv");
|
|
13
14
|
const path_1 = __importDefault(require("path"));
|
|
@@ -36,6 +37,15 @@ const IGNORES_PATHS = [
|
|
|
36
37
|
];
|
|
37
38
|
// Url to the documentation on Expo Modules
|
|
38
39
|
const DOCS_URL = 'https://docs.expo.dev/modules';
|
|
40
|
+
async function getCorrectLocalDirectory(targetOrSlug) {
|
|
41
|
+
const packageJsonPath = await (0, find_up_1.default)('package.json', { cwd: CWD });
|
|
42
|
+
if (!packageJsonPath) {
|
|
43
|
+
console.log(chalk_1.default.red.bold('⚠️ This command should be run inside your Expo project when run with the --local flag.'));
|
|
44
|
+
console.log(chalk_1.default.red('For native modules to autolink correctly, you need to place them in the `modules` directory in the root of the project.'));
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return path_1.default.join(packageJsonPath, '..', 'modules', targetOrSlug);
|
|
48
|
+
}
|
|
39
49
|
/**
|
|
40
50
|
* The main function of the command.
|
|
41
51
|
*
|
|
@@ -43,69 +53,83 @@ const DOCS_URL = 'https://docs.expo.dev/modules';
|
|
|
43
53
|
* @param command An object from `commander`.
|
|
44
54
|
*/
|
|
45
55
|
async function main(target, options) {
|
|
46
|
-
const slug = await askForPackageSlugAsync(target);
|
|
47
|
-
const targetDir =
|
|
56
|
+
const slug = await askForPackageSlugAsync(target, options.local);
|
|
57
|
+
const targetDir = options.local
|
|
58
|
+
? await getCorrectLocalDirectory(target || slug)
|
|
59
|
+
: path_1.default.join(CWD, target || slug);
|
|
60
|
+
if (!targetDir) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
48
63
|
await fs_extra_1.default.ensureDir(targetDir);
|
|
49
64
|
await confirmTargetDirAsync(targetDir);
|
|
50
65
|
options.target = targetDir;
|
|
51
|
-
const data = await askForSubstitutionDataAsync(slug);
|
|
66
|
+
const data = await askForSubstitutionDataAsync(slug, options.local);
|
|
52
67
|
// Make one line break between prompts and progress logs
|
|
53
68
|
console.log();
|
|
54
69
|
const packageManager = await (0, resolvePackageManager_1.resolvePackageManager)();
|
|
55
70
|
const packagePath = options.source
|
|
56
71
|
? path_1.default.join(CWD, options.source)
|
|
57
|
-
: await downloadPackageAsync(targetDir);
|
|
72
|
+
: await downloadPackageAsync(targetDir, options.local);
|
|
58
73
|
(0, telemetry_1.logEventAsync)((0, telemetry_1.eventCreateExpoModule)(packageManager, options));
|
|
59
74
|
await (0, utils_1.newStep)('Creating the module from template files', async (step) => {
|
|
60
75
|
await createModuleFromTemplate(packagePath, targetDir, data);
|
|
61
76
|
step.succeed('Created the module from template files');
|
|
62
77
|
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
step.succeed('Created an empty Git repository');
|
|
68
|
-
}
|
|
69
|
-
else if (result === null) {
|
|
70
|
-
step.succeed('Skipped creating an empty Git repository, already within a Git repository');
|
|
71
|
-
}
|
|
72
|
-
else if (result === false) {
|
|
73
|
-
step.warn('Could not create an empty Git repository, see debug logs with EXPO_DEBUG=true');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch (e) {
|
|
77
|
-
step.fail(e.toString());
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
await (0, utils_1.newStep)('Installing module dependencies', async (step) => {
|
|
81
|
-
await (0, packageManager_1.installDependencies)(packageManager, targetDir);
|
|
82
|
-
step.succeed('Installed module dependencies');
|
|
83
|
-
});
|
|
84
|
-
await (0, utils_1.newStep)('Compiling TypeScript files', async (step) => {
|
|
85
|
-
await (0, spawn_async_1.default)(packageManager, ['run', 'build'], {
|
|
86
|
-
cwd: targetDir,
|
|
87
|
-
stdio: 'ignore',
|
|
78
|
+
if (!options.local) {
|
|
79
|
+
await (0, utils_1.newStep)('Installing module dependencies', async (step) => {
|
|
80
|
+
await (0, packageManager_1.installDependencies)(packageManager, targetDir);
|
|
81
|
+
step.succeed('Installed module dependencies');
|
|
88
82
|
});
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
await (0, utils_1.newStep)('Compiling TypeScript files', async (step) => {
|
|
84
|
+
await (0, spawn_async_1.default)(packageManager, ['run', 'build'], {
|
|
85
|
+
cwd: targetDir,
|
|
86
|
+
stdio: 'ignore',
|
|
87
|
+
});
|
|
88
|
+
step.succeed('Compiled TypeScript files');
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
91
|
if (!options.source) {
|
|
92
92
|
// Files in the downloaded tarball are wrapped in `package` dir.
|
|
93
93
|
// We should remove it after all.
|
|
94
94
|
await fs_extra_1.default.remove(packagePath);
|
|
95
95
|
}
|
|
96
|
-
if (!options.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
if (!options.local && data.type !== 'local') {
|
|
97
|
+
if (!options.withReadme) {
|
|
98
|
+
await fs_extra_1.default.remove(path_1.default.join(targetDir, 'README.md'));
|
|
99
|
+
}
|
|
100
|
+
if (!options.withChangelog) {
|
|
101
|
+
await fs_extra_1.default.remove(path_1.default.join(targetDir, 'CHANGELOG.md'));
|
|
102
|
+
}
|
|
103
|
+
if (options.example) {
|
|
104
|
+
// Create "example" folder
|
|
105
|
+
await (0, createExampleApp_1.createExampleApp)(data, targetDir, packageManager);
|
|
106
|
+
}
|
|
107
|
+
await (0, utils_1.newStep)('Creating an empty Git repository', async (step) => {
|
|
108
|
+
try {
|
|
109
|
+
const result = await createGitRepositoryAsync(targetDir);
|
|
110
|
+
if (result) {
|
|
111
|
+
step.succeed('Created an empty Git repository');
|
|
112
|
+
}
|
|
113
|
+
else if (result === null) {
|
|
114
|
+
step.succeed('Skipped creating an empty Git repository, already within a Git repository');
|
|
115
|
+
}
|
|
116
|
+
else if (result === false) {
|
|
117
|
+
step.warn('Could not create an empty Git repository, see debug logs with EXPO_DEBUG=true');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
step.fail(e.toString());
|
|
122
|
+
}
|
|
123
|
+
});
|
|
105
124
|
}
|
|
106
125
|
console.log();
|
|
107
126
|
console.log('✅ Successfully created Expo module');
|
|
108
|
-
|
|
127
|
+
if (options.local) {
|
|
128
|
+
printFurtherLocalInstructions(slug, data.project.moduleName);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
printFurtherInstructions(targetDir, packageManager, options.example);
|
|
132
|
+
}
|
|
109
133
|
}
|
|
110
134
|
/**
|
|
111
135
|
* Recursively scans for the files within the directory. Returned paths are relative to the `root` path.
|
|
@@ -140,9 +164,9 @@ async function getNpmTarballUrl(packageName, version = 'latest') {
|
|
|
140
164
|
/**
|
|
141
165
|
* Downloads the template from NPM registry.
|
|
142
166
|
*/
|
|
143
|
-
async function downloadPackageAsync(targetDir) {
|
|
167
|
+
async function downloadPackageAsync(targetDir, isLocal = false) {
|
|
144
168
|
return await (0, utils_1.newStep)('Downloading module template from npm', async (step) => {
|
|
145
|
-
const tarballUrl = await getNpmTarballUrl('expo-module-template', EXPO_BETA ? 'next' : 'latest');
|
|
169
|
+
const tarballUrl = await getNpmTarballUrl(isLocal ? 'expo-module-template-local' : 'expo-module-template', EXPO_BETA ? 'next' : 'latest');
|
|
146
170
|
await (0, download_tarball_1.default)({
|
|
147
171
|
url: tarballUrl,
|
|
148
172
|
dir: targetDir,
|
|
@@ -206,8 +230,8 @@ async function createGitRepositoryAsync(targetDir) {
|
|
|
206
230
|
/**
|
|
207
231
|
* Asks the user for the package slug (npm package name).
|
|
208
232
|
*/
|
|
209
|
-
async function askForPackageSlugAsync(customTargetPath) {
|
|
210
|
-
const { slug } = await (0, prompts_1.default)((
|
|
233
|
+
async function askForPackageSlugAsync(customTargetPath, isLocal = false) {
|
|
234
|
+
const { slug } = await (0, prompts_1.default)((isLocal ? prompts_2.getLocalFolderNamePrompt : prompts_2.getSlugPrompt)(customTargetPath), {
|
|
211
235
|
onCancel: () => process.exit(0),
|
|
212
236
|
});
|
|
213
237
|
return slug;
|
|
@@ -216,13 +240,27 @@ async function askForPackageSlugAsync(customTargetPath) {
|
|
|
216
240
|
* Asks the user for some data necessary to render the template.
|
|
217
241
|
* Some values may already be provided by command options, the prompt is skipped in that case.
|
|
218
242
|
*/
|
|
219
|
-
async function askForSubstitutionDataAsync(slug) {
|
|
220
|
-
const promptQueries = await (
|
|
243
|
+
async function askForSubstitutionDataAsync(slug, isLocal = false) {
|
|
244
|
+
const promptQueries = await (isLocal
|
|
245
|
+
? prompts_2.getLocalSubstitutionDataPrompts
|
|
246
|
+
: prompts_2.getSubstitutionDataPrompts)(slug);
|
|
221
247
|
// Stop the process when the user cancels/exits the prompt.
|
|
222
248
|
const onCancel = () => {
|
|
223
249
|
process.exit(0);
|
|
224
250
|
};
|
|
225
251
|
const { name, description, package: projectPackage, authorName, authorEmail, authorUrl, repo, } = await (0, prompts_1.default)(promptQueries, { onCancel });
|
|
252
|
+
if (isLocal) {
|
|
253
|
+
return {
|
|
254
|
+
project: {
|
|
255
|
+
slug,
|
|
256
|
+
name,
|
|
257
|
+
package: projectPackage,
|
|
258
|
+
moduleName: handleSuffix(name, 'Module'),
|
|
259
|
+
viewName: handleSuffix(name, 'View'),
|
|
260
|
+
},
|
|
261
|
+
type: 'local',
|
|
262
|
+
};
|
|
263
|
+
}
|
|
226
264
|
return {
|
|
227
265
|
project: {
|
|
228
266
|
slug,
|
|
@@ -236,6 +274,7 @@ async function askForSubstitutionDataAsync(slug) {
|
|
|
236
274
|
author: `${authorName} <${authorEmail}> (${authorUrl})`,
|
|
237
275
|
license: 'MIT',
|
|
238
276
|
repo,
|
|
277
|
+
type: 'remote',
|
|
239
278
|
};
|
|
240
279
|
}
|
|
241
280
|
/**
|
|
@@ -275,6 +314,14 @@ function printFurtherInstructions(targetDir, packageManager, includesExample) {
|
|
|
275
314
|
}
|
|
276
315
|
console.log(`Visit ${chalk_1.default.blue.bold(DOCS_URL)} for the documentation on Expo Modules APIs`);
|
|
277
316
|
}
|
|
317
|
+
function printFurtherLocalInstructions(slug, name) {
|
|
318
|
+
console.log(`You can now import this module inside your application:`);
|
|
319
|
+
console.log();
|
|
320
|
+
console.log(chalk_1.default.blue(`import { hello } from '${slug}';`));
|
|
321
|
+
console.log();
|
|
322
|
+
console.log(`Visit ${chalk_1.default.blue.bold(DOCS_URL)} for the documentation on Expo Modules APIs`);
|
|
323
|
+
console.log(chalk_1.default.yellow(`Remember you need to rebuild your development client or reinstall pods to see the changes.`));
|
|
324
|
+
}
|
|
278
325
|
const program = new commander_1.Command();
|
|
279
326
|
program
|
|
280
327
|
.name(packageJson.name)
|
|
@@ -285,6 +332,7 @@ program
|
|
|
285
332
|
.option('--with-readme', 'Whether to include README.md file.', false)
|
|
286
333
|
.option('--with-changelog', 'Whether to include CHANGELOG.md file.', false)
|
|
287
334
|
.option('--no-example', 'Whether to skip creating the example app.', false)
|
|
335
|
+
.option('--local', 'Whether to create a local module in the current project, skipping installing node_modules and creating the example directory.', false)
|
|
288
336
|
.action(main);
|
|
289
337
|
program
|
|
290
338
|
.hook('postAction', async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-expo-module.js","sourceRoot":"","sources":["../src/create-expo-module.ts"],"names":[],"mappings":";;;;;AAAA,oEAA2C;AAC3C,kDAA0B;AAC1B,yCAAoC;AACpC,wEAA+C;AAC/C,8CAAsB;AACtB,wDAA0B;AAC1B,mCAAiC;AACjC,gDAAwB;AACxB,sDAA8B;AAE9B,yDAAsD;AACtD,qDAAuD;AACvD,uCAAsE;AACtE,mEAIiC;AACjC,2CAAuF;AAEvF,mCAAkC;AAElC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,yBAAyB,CAAuB,CAAC;AAChF,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE/C,gCAAgC;AAChC,MAAM,SAAS,GAAG,IAAA,gBAAO,EAAC,WAAW,EAAE,KAAK,CAAC,CAAC;AAE9C,oFAAoF;AACpF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;AAElD,iEAAiE;AACjE,yDAAyD;AACzD,MAAM,aAAa,GAAG;IACpB,WAAW;IACX,OAAO;IACP,cAAc;IACd,cAAc;IACd,YAAY;IACZ,YAAY;CACb,CAAC;AAEF,2CAA2C;AAC3C,MAAM,QAAQ,GAAG,+BAA+B,CAAC;AAEjD;;;;;GAKG;AACH,KAAK,UAAU,IAAI,CAAC,MAA0B,EAAE,OAAuB;IACrE,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC;IAEjD,MAAM,kBAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,MAAM,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAEvC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAE3B,MAAM,IAAI,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,CAAC;IAErD,wDAAwD;IACxD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,cAAc,GAAG,MAAM,IAAA,6CAAqB,GAAE,CAAC;IACrD,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM;QAChC,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC;QAChC,CAAC,CAAC,MAAM,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAE1C,IAAA,yBAAa,EAAC,IAAA,iCAAqB,EAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IAE9D,MAAM,IAAA,eAAO,EAAC,yCAAyC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACtE,MAAM,wBAAwB,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,IAAA,eAAO,EAAC,kCAAkC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC/D,IAAI;YACF,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,SAAS,CAAC,CAAC;YACzD,IAAI,MAAM,EAAE;gBACV,IAAI,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;aACjD;iBAAM,IAAI,MAAM,KAAK,IAAI,EAAE;gBAC1B,IAAI,CAAC,OAAO,CAAC,2EAA2E,CAAC,CAAC;aAC3F;iBAAM,IAAI,MAAM,KAAK,KAAK,EAAE;gBAC3B,IAAI,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;aAC5F;SACF;QAAC,OAAO,CAAM,EAAE;YACf,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;SACzB;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,IAAA,eAAO,EAAC,gCAAgC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC7D,MAAM,IAAA,oCAAmB,EAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,MAAM,IAAA,eAAO,EAAC,4BAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACzD,MAAM,IAAA,qBAAU,EAAC,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;YACjD,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;QACnB,gEAAgE;QAChE,iCAAiC;QACjC,MAAM,kBAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;KAC9B;IACD,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;QACvB,MAAM,kBAAE,CAAC,MAAM,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;KACpD;IACD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;QAC1B,MAAM,kBAAE,CAAC,MAAM,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;KACvD;IACD,IAAI,OAAO,CAAC,OAAO,EAAE;QACnB,0BAA0B;QAC1B,MAAM,IAAA,mCAAgB,EAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;KACzD;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAElD,wBAAwB,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,MAAqB,IAAI;IAClE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAElD,KAAK,MAAM,IAAI,IAAI,MAAM,kBAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAC5C,MAAM,YAAY,GAAG,GAAG,CAAC,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEvD,IAAI,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YACxE,SAAS;SACV;QAED,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,kBAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEtC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;YACtB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;SAC1D;aAAM;YACL,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;SAC1B;KACF;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,WAAmB,EAAE,UAAkB,QAAQ;IAC7E,KAAK,CAAC,yBAAyB,eAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,eAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjF,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,WAAW,IAAI,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAClG,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,oBAAoB,CAAC,SAAiB;IACnD,OAAO,MAAM,IAAA,eAAO,EAAC,sCAAsC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC1E,MAAM,UAAU,GAAG,MAAM,gBAAgB,CACvC,sBAAsB,EACtB,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAC9B,CAAC;QAEF,MAAM,IAAA,0BAAe,EAAC;YACpB,GAAG,EAAE,UAAU;YACf,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC;QAEpD,OAAO,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,MAAc;IAChD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;QACzB,OAAO,IAAI,CAAC;KACb;IACD,OAAO,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,wBAAwB,CACrC,YAAoB,EACpB,UAAkB,EAClB,IAAsB;IAEtB,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;IAEhD,sCAAsC;IACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,MAAM,oBAAoB,GAAG,aAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE;YACrE,aAAa,EAAE,GAAG;YAClB,cAAc,EAAE,GAAG;YACnB,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,cAAI,CAAC,GAAG,CAAC;SAC1D,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACnE,MAAM,eAAe,GAAG,aAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAEnD,MAAM,kBAAE,CAAC,UAAU,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;KACpE;AACH,CAAC;AAED,KAAK,UAAU,wBAAwB,CAAC,SAAiB;IACvD,kDAAkD;IAClD,IAAI;QACF,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC,EAAE;YAC9D,KAAK,EAAE,QAAQ;YACf,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QACH,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC,CAAC;QACpF,OAAO,IAAI,CAAC;KACb;IAAC,OAAO,CAAM,EAAE;QACf,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE;YACxB,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;YACvE,OAAO,KAAK,CAAC;SACd;KACF;IAED,8BAA8B;IAC9B,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IACvE,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IAE5E,MAAM,SAAS,GAAG,kCAAkC,WAAW,CAAC,IAAI,IAAI,WAAW,CAAC,OAAO,GAAG,CAAC;IAC/F,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE;QACnD,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,SAAS;KACf,CAAC,CAAC;IAEH,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,sBAAsB,CAAC,gBAAyB;IAC7D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,iBAAO,EAAC,IAAA,uBAAa,EAAC,gBAAgB,CAAC,EAAE;QAC9D,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;KAChC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,2BAA2B,CAAC,IAAY;IACrD,MAAM,aAAa,GAAG,MAAM,IAAA,oCAA0B,EAAC,IAAI,CAAC,CAAC;IAE7D,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,EACJ,IAAI,EACJ,WAAW,EACX,OAAO,EAAE,cAAc,EACvB,UAAU,EACV,WAAW,EACX,SAAS,EACT,IAAI,GACL,GAAG,MAAM,IAAA,iBAAO,EAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE/C,OAAO;QACL,OAAO,EAAE;YACP,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,OAAO;YAChB,WAAW;YACX,OAAO,EAAE,cAAc;YACvB,UAAU,EAAE,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC;YACxC,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC;SACrC;QACD,MAAM,EAAE,GAAG,UAAU,KAAK,WAAW,MAAM,SAAS,GAAG;QACvD,OAAO,EAAE,KAAK;QACd,IAAI;KACL,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,qBAAqB,CAAC,SAAiB;IACpD,MAAM,KAAK,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAE1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QACtB,OAAO;KACR;IACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,IAAA,iBAAO,EACtC;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,wBAAwB,eAAK,CAAC,OAAO,CAC5C,SAAS,CACV,gDAAgD;QACjD,OAAO,EAAE,IAAI;KACd,EACD;QACE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;KACtB,CACF,CAAC;IACF,IAAI,CAAC,cAAc,EAAE;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;AACH,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAC/B,SAAiB,EACjB,cAAkC,EAClC,eAAwB;IAExB,IAAI,eAAe,EAAE;QACnB,MAAM,QAAQ,GAAG;YACf,MAAM,cAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE;YACrC,IAAA,wCAAgB,EAAC,cAAc,EAAE,UAAU,CAAC;YAC5C,IAAA,wCAAgB,EAAC,cAAc,EAAE,cAAc,CAAC;SACjD,CAAC;QAEF,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CACT,iHAAiH,CAClH,CAAC;QACF,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,eAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjF,OAAO,CAAC,GAAG,EAAE,CAAC;KACf;IACD,OAAO,CAAC,GAAG,CAAC,SAAS,eAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;KACtB,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;KACpC,SAAS,CAAC,QAAQ,CAAC;KACnB,MAAM,CACL,2BAA2B,EAC3B,sFAAsF,CACvF;KACA,MAAM,CAAC,eAAe,EAAE,oCAAoC,EAAE,KAAK,CAAC;KACpE,MAAM,CAAC,kBAAkB,EAAE,uCAAuC,EAAE,KAAK,CAAC;KAC1E,MAAM,CAAC,cAAc,EAAE,2CAA2C,EAAE,KAAK,CAAC;KAC1E,MAAM,CAAC,IAAI,CAAC,CAAC;AAEhB,OAAO;KACJ,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IAC7B,MAAM,IAAA,8BAAkB,GAAE,CAAC,KAAK,EAAE,EAAE,CAAC;AACvC,CAAC,CAAC;KACD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC","sourcesContent":["import spawnAsync from '@expo/spawn-async';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport downloadTarball from 'download-tarball';\nimport ejs from 'ejs';\nimport fs from 'fs-extra';\nimport { boolish } from 'getenv';\nimport path from 'path';\nimport prompts from 'prompts';\n\nimport { createExampleApp } from './createExampleApp';\nimport { installDependencies } from './packageManager';\nimport { getSlugPrompt, getSubstitutionDataPrompts } from './prompts';\nimport {\n formatRunCommand,\n PackageManagerName,\n resolvePackageManager,\n} from './resolvePackageManager';\nimport { eventCreateExpoModule, getTelemetryClient, logEventAsync } from './telemetry';\nimport { CommandOptions, SubstitutionData } from './types';\nimport { newStep } from './utils';\n\nconst debug = require('debug')('create-expo-module:main') as typeof console.log;\nconst packageJson = require('../package.json');\n\n// Opt in to using beta versions\nconst EXPO_BETA = boolish('EXPO_BETA', false);\n\n// `yarn run` may change the current working dir, then we should use `INIT_CWD` env.\nconst CWD = process.env.INIT_CWD || process.cwd();\n\n// Ignore some paths. Especially `package.json` as it is rendered\n// from `$package.json` file instead of the original one.\nconst IGNORES_PATHS = [\n '.DS_Store',\n 'build',\n 'node_modules',\n 'package.json',\n '.npmignore',\n '.gitignore',\n];\n\n// Url to the documentation on Expo Modules\nconst DOCS_URL = 'https://docs.expo.dev/modules';\n\n/**\n * The main function of the command.\n *\n * @param target Path to the directory where to create the module. Defaults to current working dir.\n * @param command An object from `commander`.\n */\nasync function main(target: string | undefined, options: CommandOptions) {\n const slug = await askForPackageSlugAsync(target);\n const targetDir = path.join(CWD, target || slug);\n\n await fs.ensureDir(targetDir);\n await confirmTargetDirAsync(targetDir);\n\n options.target = targetDir;\n\n const data = await askForSubstitutionDataAsync(slug);\n\n // Make one line break between prompts and progress logs\n console.log();\n\n const packageManager = await resolvePackageManager();\n const packagePath = options.source\n ? path.join(CWD, options.source)\n : await downloadPackageAsync(targetDir);\n\n logEventAsync(eventCreateExpoModule(packageManager, options));\n\n await newStep('Creating the module from template files', async (step) => {\n await createModuleFromTemplate(packagePath, targetDir, data);\n step.succeed('Created the module from template files');\n });\n\n await newStep('Creating an empty Git repository', async (step) => {\n try {\n const result = await createGitRepositoryAsync(targetDir);\n if (result) {\n step.succeed('Created an empty Git repository');\n } else if (result === null) {\n step.succeed('Skipped creating an empty Git repository, already within a Git repository');\n } else if (result === false) {\n step.warn('Could not create an empty Git repository, see debug logs with EXPO_DEBUG=true');\n }\n } catch (e: any) {\n step.fail(e.toString());\n }\n });\n\n await newStep('Installing module dependencies', async (step) => {\n await installDependencies(packageManager, targetDir);\n step.succeed('Installed module dependencies');\n });\n\n await newStep('Compiling TypeScript files', async (step) => {\n await spawnAsync(packageManager, ['run', 'build'], {\n cwd: targetDir,\n stdio: 'ignore',\n });\n step.succeed('Compiled TypeScript files');\n });\n\n if (!options.source) {\n // Files in the downloaded tarball are wrapped in `package` dir.\n // We should remove it after all.\n await fs.remove(packagePath);\n }\n if (!options.withReadme) {\n await fs.remove(path.join(targetDir, 'README.md'));\n }\n if (!options.withChangelog) {\n await fs.remove(path.join(targetDir, 'CHANGELOG.md'));\n }\n if (options.example) {\n // Create \"example\" folder\n await createExampleApp(data, targetDir, packageManager);\n }\n\n console.log();\n console.log('✅ Successfully created Expo module');\n\n printFurtherInstructions(targetDir, packageManager, options.example);\n}\n\n/**\n * Recursively scans for the files within the directory. Returned paths are relative to the `root` path.\n */\nasync function getFilesAsync(root: string, dir: string | null = null): Promise<string[]> {\n const files: string[] = [];\n const baseDir = dir ? path.join(root, dir) : root;\n\n for (const file of await fs.readdir(baseDir)) {\n const relativePath = dir ? path.join(dir, file) : file;\n\n if (IGNORES_PATHS.includes(relativePath) || IGNORES_PATHS.includes(file)) {\n continue;\n }\n\n const fullPath = path.join(baseDir, file);\n const stat = await fs.lstat(fullPath);\n\n if (stat.isDirectory()) {\n files.push(...(await getFilesAsync(root, relativePath)));\n } else {\n files.push(relativePath);\n }\n }\n return files;\n}\n\n/**\n * Asks NPM registry for the url to the tarball.\n */\nasync function getNpmTarballUrl(packageName: string, version: string = 'latest'): Promise<string> {\n debug(`Using module template ${chalk.bold(packageName)}@${chalk.bold(version)}`);\n const { stdout } = await spawnAsync('npm', ['view', `${packageName}@${version}`, 'dist.tarball']);\n return stdout.trim();\n}\n\n/**\n * Downloads the template from NPM registry.\n */\nasync function downloadPackageAsync(targetDir: string): Promise<string> {\n return await newStep('Downloading module template from npm', async (step) => {\n const tarballUrl = await getNpmTarballUrl(\n 'expo-module-template',\n EXPO_BETA ? 'next' : 'latest'\n );\n\n await downloadTarball({\n url: tarballUrl,\n dir: targetDir,\n });\n\n step.succeed('Downloaded module template from npm');\n\n return path.join(targetDir, 'package');\n });\n}\n\nfunction handleSuffix(name: string, suffix: string): string {\n if (name.endsWith(suffix)) {\n return name;\n }\n return `${name}${suffix}`;\n}\n\n/**\n * Creates the module based on the `ejs` template (e.g. `expo-module-template` package).\n */\nasync function createModuleFromTemplate(\n templatePath: string,\n targetPath: string,\n data: SubstitutionData\n) {\n const files = await getFilesAsync(templatePath);\n\n // Iterate through all template files.\n for (const file of files) {\n const renderedRelativePath = ejs.render(file.replace(/^\\$/, ''), data, {\n openDelimiter: '{',\n closeDelimiter: '}',\n escape: (value: string) => value.replace(/\\./g, path.sep),\n });\n const fromPath = path.join(templatePath, file);\n const toPath = path.join(targetPath, renderedRelativePath);\n const template = await fs.readFile(fromPath, { encoding: 'utf8' });\n const renderedContent = ejs.render(template, data);\n\n await fs.outputFile(toPath, renderedContent, { encoding: 'utf8' });\n }\n}\n\nasync function createGitRepositoryAsync(targetDir: string) {\n // Check if we are inside a git repository already\n try {\n await spawnAsync('git', ['rev-parse', '--is-inside-work-tree'], {\n stdio: 'ignore',\n cwd: targetDir,\n });\n debug(chalk.dim('New project is already inside of a Git repo, skipping git init.'));\n return null;\n } catch (e: any) {\n if (e.errno === 'ENOENT') {\n debug(chalk.dim('Unable to initialize Git repo. `git` not in $PATH.'));\n return false;\n }\n }\n\n // Create a new git repository\n await spawnAsync('git', ['init'], { stdio: 'ignore', cwd: targetDir });\n await spawnAsync('git', ['add', '-A'], { stdio: 'ignore', cwd: targetDir });\n\n const commitMsg = `Initial commit\\n\\nGenerated by ${packageJson.name} ${packageJson.version}.`;\n await spawnAsync('git', ['commit', '-m', commitMsg], {\n stdio: 'ignore',\n cwd: targetDir,\n });\n\n debug(chalk.dim('Initialized a Git repository.'));\n return true;\n}\n\n/**\n * Asks the user for the package slug (npm package name).\n */\nasync function askForPackageSlugAsync(customTargetPath?: string): Promise<string> {\n const { slug } = await prompts(getSlugPrompt(customTargetPath), {\n onCancel: () => process.exit(0),\n });\n return slug;\n}\n\n/**\n * Asks the user for some data necessary to render the template.\n * Some values may already be provided by command options, the prompt is skipped in that case.\n */\nasync function askForSubstitutionDataAsync(slug: string): Promise<SubstitutionData> {\n const promptQueries = await getSubstitutionDataPrompts(slug);\n\n // Stop the process when the user cancels/exits the prompt.\n const onCancel = () => {\n process.exit(0);\n };\n\n const {\n name,\n description,\n package: projectPackage,\n authorName,\n authorEmail,\n authorUrl,\n repo,\n } = await prompts(promptQueries, { onCancel });\n\n return {\n project: {\n slug,\n name,\n version: '0.1.0',\n description,\n package: projectPackage,\n moduleName: handleSuffix(name, 'Module'),\n viewName: handleSuffix(name, 'View'),\n },\n author: `${authorName} <${authorEmail}> (${authorUrl})`,\n license: 'MIT',\n repo,\n };\n}\n\n/**\n * Checks whether the target directory is empty and if not, asks the user to confirm if he wants to continue.\n */\nasync function confirmTargetDirAsync(targetDir: string): Promise<void> {\n const files = await fs.readdir(targetDir);\n\n if (files.length === 0) {\n return;\n }\n const { shouldContinue } = await prompts(\n {\n type: 'confirm',\n name: 'shouldContinue',\n message: `The target directory ${chalk.magenta(\n targetDir\n )} is not empty, do you want to continue anyway?`,\n initial: true,\n },\n {\n onCancel: () => false,\n }\n );\n if (!shouldContinue) {\n process.exit(0);\n }\n}\n\n/**\n * Prints how the user can follow up once the script finishes creating the module.\n */\nfunction printFurtherInstructions(\n targetDir: string,\n packageManager: PackageManagerName,\n includesExample: boolean\n) {\n if (includesExample) {\n const commands = [\n `cd ${path.relative(CWD, targetDir)}`,\n formatRunCommand(packageManager, 'open:ios'),\n formatRunCommand(packageManager, 'open:android'),\n ];\n\n console.log();\n console.log(\n 'To start developing your module, navigate to the directory and open iOS and Android projects of the example app'\n );\n commands.forEach((command) => console.log(chalk.gray('>'), chalk.bold(command)));\n console.log();\n }\n console.log(`Visit ${chalk.blue.bold(DOCS_URL)} for the documentation on Expo Modules APIs`);\n}\n\nconst program = new Command();\n\nprogram\n .name(packageJson.name)\n .version(packageJson.version)\n .description(packageJson.description)\n .arguments('[path]')\n .option(\n '-s, --source <source_dir>',\n 'Local path to the template. By default it downloads `expo-module-template` from NPM.'\n )\n .option('--with-readme', 'Whether to include README.md file.', false)\n .option('--with-changelog', 'Whether to include CHANGELOG.md file.', false)\n .option('--no-example', 'Whether to skip creating the example app.', false)\n .action(main);\n\nprogram\n .hook('postAction', async () => {\n await getTelemetryClient().flush?.();\n })\n .parse(process.argv);\n"]}
|
|
1
|
+
{"version":3,"file":"create-expo-module.js","sourceRoot":"","sources":["../src/create-expo-module.ts"],"names":[],"mappings":";;;;;AAAA,oEAA2C;AAC3C,kDAA0B;AAC1B,yCAAoC;AACpC,wEAA+C;AAC/C,8CAAsB;AACtB,sDAA6B;AAC7B,wDAA0B;AAC1B,mCAAiC;AACjC,gDAAwB;AACxB,sDAA8B;AAE9B,yDAAsD;AACtD,qDAAuD;AACvD,uCAKmB;AACnB,mEAIiC;AACjC,2CAAuF;AAEvF,mCAAkC;AAElC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,yBAAyB,CAAuB,CAAC;AAChF,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE/C,gCAAgC;AAChC,MAAM,SAAS,GAAG,IAAA,gBAAO,EAAC,WAAW,EAAE,KAAK,CAAC,CAAC;AAE9C,oFAAoF;AACpF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;AAElD,iEAAiE;AACjE,yDAAyD;AACzD,MAAM,aAAa,GAAG;IACpB,WAAW;IACX,OAAO;IACP,cAAc;IACd,cAAc;IACd,YAAY;IACZ,YAAY;CACb,CAAC;AAEF,2CAA2C;AAC3C,MAAM,QAAQ,GAAG,+BAA+B,CAAC;AAEjD,KAAK,UAAU,wBAAwB,CAAC,YAAoB;IAC1D,MAAM,eAAe,GAAG,MAAM,IAAA,iBAAM,EAAC,cAAc,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC,eAAe,EAAE;QACpB,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,GAAG,CAAC,IAAI,CACZ,yFAAyF,CAC1F,CACF,CAAC;QACF,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,GAAG,CACP,yHAAyH,CAC1H,CACF,CAAC;QACF,OAAO,IAAI,CAAC;KACb;IACD,OAAO,cAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,IAAI,CAAC,MAA0B,EAAE,OAAuB;IACrE,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK;QAC7B,CAAC,CAAC,MAAM,wBAAwB,CAAC,MAAM,IAAI,IAAI,CAAC;QAChD,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC;IAEnC,IAAI,CAAC,SAAS,EAAE;QACd,OAAO;KACR;IACD,MAAM,kBAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,MAAM,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAEvC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAE3B,MAAM,IAAI,GAAG,MAAM,2BAA2B,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAEpE,wDAAwD;IACxD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,cAAc,GAAG,MAAM,IAAA,6CAAqB,GAAE,CAAC;IACrD,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM;QAChC,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC;QAChC,CAAC,CAAC,MAAM,oBAAoB,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAEzD,IAAA,yBAAa,EAAC,IAAA,iCAAqB,EAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IAE9D,MAAM,IAAA,eAAO,EAAC,yCAAyC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACtE,MAAM,wBAAwB,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;QAClB,MAAM,IAAA,eAAO,EAAC,gCAAgC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YAC7D,MAAM,IAAA,oCAAmB,EAAC,cAAc,EAAE,SAAS,CAAC,CAAC;YACrD,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QACH,MAAM,IAAA,eAAO,EAAC,4BAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACzD,MAAM,IAAA,qBAAU,EAAC,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;gBACjD,GAAG,EAAE,SAAS;gBACd,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;KACJ;IAED,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;QACnB,gEAAgE;QAChE,iCAAiC;QACjC,MAAM,kBAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;KAC9B;IACD,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE;QAC3C,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;YACvB,MAAM,kBAAE,CAAC,MAAM,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;SACpD;QACD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YAC1B,MAAM,kBAAE,CAAC,MAAM,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;SACvD;QACD,IAAI,OAAO,CAAC,OAAO,EAAE;YACnB,0BAA0B;YAC1B,MAAM,IAAA,mCAAgB,EAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;SACzD;QAED,MAAM,IAAA,eAAO,EAAC,kCAAkC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YAC/D,IAAI;gBACF,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,SAAS,CAAC,CAAC;gBACzD,IAAI,MAAM,EAAE;oBACV,IAAI,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;iBACjD;qBAAM,IAAI,MAAM,KAAK,IAAI,EAAE;oBAC1B,IAAI,CAAC,OAAO,CAAC,2EAA2E,CAAC,CAAC;iBAC3F;qBAAM,IAAI,MAAM,KAAK,KAAK,EAAE;oBAC3B,IAAI,CAAC,IAAI,CACP,+EAA+E,CAChF,CAAC;iBACH;aACF;YAAC,OAAO,CAAM,EAAE;gBACf,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;aACzB;QACH,CAAC,CAAC,CAAC;KACJ;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,KAAK,EAAE;QACjB,6BAA6B,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;KAC9D;SAAM;QACL,wBAAwB,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;KACtE;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,MAAqB,IAAI;IAClE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAElD,KAAK,MAAM,IAAI,IAAI,MAAM,kBAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAC5C,MAAM,YAAY,GAAG,GAAG,CAAC,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEvD,IAAI,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YACxE,SAAS;SACV;QAED,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,kBAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEtC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;YACtB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;SAC1D;aAAM;YACL,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;SAC1B;KACF;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,WAAmB,EAAE,UAAkB,QAAQ;IAC7E,KAAK,CAAC,yBAAyB,eAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,eAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjF,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,WAAW,IAAI,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAClG,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,oBAAoB,CAAC,SAAiB,EAAE,OAAO,GAAG,KAAK;IACpE,OAAO,MAAM,IAAA,eAAO,EAAC,sCAAsC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC1E,MAAM,UAAU,GAAG,MAAM,gBAAgB,CACvC,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,sBAAsB,EAC/D,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAC9B,CAAC;QAEF,MAAM,IAAA,0BAAe,EAAC;YACpB,GAAG,EAAE,UAAU;YACf,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC;QAEpD,OAAO,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,MAAc;IAChD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;QACzB,OAAO,IAAI,CAAC;KACb;IACD,OAAO,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,wBAAwB,CACrC,YAAoB,EACpB,UAAkB,EAClB,IAA8C;IAE9C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;IAEhD,sCAAsC;IACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,MAAM,oBAAoB,GAAG,aAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE;YACrE,aAAa,EAAE,GAAG;YAClB,cAAc,EAAE,GAAG;YACnB,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,cAAI,CAAC,GAAG,CAAC;SAC1D,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACnE,MAAM,eAAe,GAAG,aAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAEnD,MAAM,kBAAE,CAAC,UAAU,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;KACpE;AACH,CAAC;AAED,KAAK,UAAU,wBAAwB,CAAC,SAAiB;IACvD,kDAAkD;IAClD,IAAI;QACF,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC,EAAE;YAC9D,KAAK,EAAE,QAAQ;YACf,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QACH,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC,CAAC;QACpF,OAAO,IAAI,CAAC;KACb;IAAC,OAAO,CAAM,EAAE;QACf,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE;YACxB,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;YACvE,OAAO,KAAK,CAAC;SACd;KACF;IAED,8BAA8B;IAC9B,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IACvE,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IAE5E,MAAM,SAAS,GAAG,kCAAkC,WAAW,CAAC,IAAI,IAAI,WAAW,CAAC,OAAO,GAAG,CAAC;IAC/F,MAAM,IAAA,qBAAU,EAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE;QACnD,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,SAAS;KACf,CAAC,CAAC;IAEH,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,sBAAsB,CAAC,gBAAyB,EAAE,OAAO,GAAG,KAAK;IAC9E,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,iBAAO,EAC5B,CAAC,OAAO,CAAC,CAAC,CAAC,kCAAwB,CAAC,CAAC,CAAC,uBAAa,CAAC,CAAC,gBAAgB,CAAC,EACtE;QACE,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;KAChC,CACF,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,2BAA2B,CACxC,IAAY,EACZ,OAAO,GAAG,KAAK;IAEf,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO;QAClC,CAAC,CAAC,yCAA+B;QACjC,CAAC,CAAC,oCAA0B,CAAC,CAAC,IAAI,CAAC,CAAC;IAEtC,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,EACJ,IAAI,EACJ,WAAW,EACX,OAAO,EAAE,cAAc,EACvB,UAAU,EACV,WAAW,EACX,SAAS,EACT,IAAI,GACL,GAAG,MAAM,IAAA,iBAAO,EAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE/C,IAAI,OAAO,EAAE;QACX,OAAO;YACL,OAAO,EAAE;gBACP,IAAI;gBACJ,IAAI;gBACJ,OAAO,EAAE,cAAc;gBACvB,UAAU,EAAE,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC;gBACxC,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC;aACrC;YACD,IAAI,EAAE,OAAO;SACd,CAAC;KACH;IAED,OAAO;QACL,OAAO,EAAE;YACP,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,OAAO;YAChB,WAAW;YACX,OAAO,EAAE,cAAc;YACvB,UAAU,EAAE,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC;YACxC,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC;SACrC;QACD,MAAM,EAAE,GAAG,UAAU,KAAK,WAAW,MAAM,SAAS,GAAG;QACvD,OAAO,EAAE,KAAK;QACd,IAAI;QACJ,IAAI,EAAE,QAAQ;KACf,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,qBAAqB,CAAC,SAAiB;IACpD,MAAM,KAAK,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAE1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QACtB,OAAO;KACR;IACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,IAAA,iBAAO,EACtC;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,wBAAwB,eAAK,CAAC,OAAO,CAC5C,SAAS,CACV,gDAAgD;QACjD,OAAO,EAAE,IAAI;KACd,EACD;QACE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;KACtB,CACF,CAAC;IACF,IAAI,CAAC,cAAc,EAAE;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;AACH,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAC/B,SAAiB,EACjB,cAAkC,EAClC,eAAwB;IAExB,IAAI,eAAe,EAAE;QACnB,MAAM,QAAQ,GAAG;YACf,MAAM,cAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE;YACrC,IAAA,wCAAgB,EAAC,cAAc,EAAE,UAAU,CAAC;YAC5C,IAAA,wCAAgB,EAAC,cAAc,EAAE,cAAc,CAAC;SACjD,CAAC;QAEF,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CACT,iHAAiH,CAClH,CAAC;QACF,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,eAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjF,OAAO,CAAC,GAAG,EAAE,CAAC;KACf;IACD,OAAO,CAAC,GAAG,CAAC,SAAS,eAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,6BAA6B,CAAC,IAAY,EAAE,IAAY;IAC/D,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,0BAA0B,IAAI,IAAI,CAAC,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,SAAS,eAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC;IAC7F,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,MAAM,CACV,4FAA4F,CAC7F,CACF,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;KACtB,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;KACpC,SAAS,CAAC,QAAQ,CAAC;KACnB,MAAM,CACL,2BAA2B,EAC3B,sFAAsF,CACvF;KACA,MAAM,CAAC,eAAe,EAAE,oCAAoC,EAAE,KAAK,CAAC;KACpE,MAAM,CAAC,kBAAkB,EAAE,uCAAuC,EAAE,KAAK,CAAC;KAC1E,MAAM,CAAC,cAAc,EAAE,2CAA2C,EAAE,KAAK,CAAC;KAC1E,MAAM,CACL,SAAS,EACT,+HAA+H,EAC/H,KAAK,CACN;KACA,MAAM,CAAC,IAAI,CAAC,CAAC;AAEhB,OAAO;KACJ,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IAC7B,MAAM,IAAA,8BAAkB,GAAE,CAAC,KAAK,EAAE,EAAE,CAAC;AACvC,CAAC,CAAC;KACD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC","sourcesContent":["import spawnAsync from '@expo/spawn-async';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport downloadTarball from 'download-tarball';\nimport ejs from 'ejs';\nimport findUp from 'find-up';\nimport fs from 'fs-extra';\nimport { boolish } from 'getenv';\nimport path from 'path';\nimport prompts from 'prompts';\n\nimport { createExampleApp } from './createExampleApp';\nimport { installDependencies } from './packageManager';\nimport {\n getLocalFolderNamePrompt,\n getLocalSubstitutionDataPrompts,\n getSlugPrompt,\n getSubstitutionDataPrompts,\n} from './prompts';\nimport {\n formatRunCommand,\n PackageManagerName,\n resolvePackageManager,\n} from './resolvePackageManager';\nimport { eventCreateExpoModule, getTelemetryClient, logEventAsync } from './telemetry';\nimport { CommandOptions, LocalSubstitutionData, SubstitutionData } from './types';\nimport { newStep } from './utils';\n\nconst debug = require('debug')('create-expo-module:main') as typeof console.log;\nconst packageJson = require('../package.json');\n\n// Opt in to using beta versions\nconst EXPO_BETA = boolish('EXPO_BETA', false);\n\n// `yarn run` may change the current working dir, then we should use `INIT_CWD` env.\nconst CWD = process.env.INIT_CWD || process.cwd();\n\n// Ignore some paths. Especially `package.json` as it is rendered\n// from `$package.json` file instead of the original one.\nconst IGNORES_PATHS = [\n '.DS_Store',\n 'build',\n 'node_modules',\n 'package.json',\n '.npmignore',\n '.gitignore',\n];\n\n// Url to the documentation on Expo Modules\nconst DOCS_URL = 'https://docs.expo.dev/modules';\n\nasync function getCorrectLocalDirectory(targetOrSlug: string) {\n const packageJsonPath = await findUp('package.json', { cwd: CWD });\n if (!packageJsonPath) {\n console.log(\n chalk.red.bold(\n '⚠️ This command should be run inside your Expo project when run with the --local flag.'\n )\n );\n console.log(\n chalk.red(\n 'For native modules to autolink correctly, you need to place them in the `modules` directory in the root of the project.'\n )\n );\n return null;\n }\n return path.join(packageJsonPath, '..', 'modules', targetOrSlug);\n}\n\n/**\n * The main function of the command.\n *\n * @param target Path to the directory where to create the module. Defaults to current working dir.\n * @param command An object from `commander`.\n */\nasync function main(target: string | undefined, options: CommandOptions) {\n const slug = await askForPackageSlugAsync(target, options.local);\n const targetDir = options.local\n ? await getCorrectLocalDirectory(target || slug)\n : path.join(CWD, target || slug);\n\n if (!targetDir) {\n return;\n }\n await fs.ensureDir(targetDir);\n await confirmTargetDirAsync(targetDir);\n\n options.target = targetDir;\n\n const data = await askForSubstitutionDataAsync(slug, options.local);\n\n // Make one line break between prompts and progress logs\n console.log();\n\n const packageManager = await resolvePackageManager();\n const packagePath = options.source\n ? path.join(CWD, options.source)\n : await downloadPackageAsync(targetDir, options.local);\n\n logEventAsync(eventCreateExpoModule(packageManager, options));\n\n await newStep('Creating the module from template files', async (step) => {\n await createModuleFromTemplate(packagePath, targetDir, data);\n step.succeed('Created the module from template files');\n });\n if (!options.local) {\n await newStep('Installing module dependencies', async (step) => {\n await installDependencies(packageManager, targetDir);\n step.succeed('Installed module dependencies');\n });\n await newStep('Compiling TypeScript files', async (step) => {\n await spawnAsync(packageManager, ['run', 'build'], {\n cwd: targetDir,\n stdio: 'ignore',\n });\n step.succeed('Compiled TypeScript files');\n });\n }\n\n if (!options.source) {\n // Files in the downloaded tarball are wrapped in `package` dir.\n // We should remove it after all.\n await fs.remove(packagePath);\n }\n if (!options.local && data.type !== 'local') {\n if (!options.withReadme) {\n await fs.remove(path.join(targetDir, 'README.md'));\n }\n if (!options.withChangelog) {\n await fs.remove(path.join(targetDir, 'CHANGELOG.md'));\n }\n if (options.example) {\n // Create \"example\" folder\n await createExampleApp(data, targetDir, packageManager);\n }\n\n await newStep('Creating an empty Git repository', async (step) => {\n try {\n const result = await createGitRepositoryAsync(targetDir);\n if (result) {\n step.succeed('Created an empty Git repository');\n } else if (result === null) {\n step.succeed('Skipped creating an empty Git repository, already within a Git repository');\n } else if (result === false) {\n step.warn(\n 'Could not create an empty Git repository, see debug logs with EXPO_DEBUG=true'\n );\n }\n } catch (e: any) {\n step.fail(e.toString());\n }\n });\n }\n\n console.log();\n console.log('✅ Successfully created Expo module');\n if (options.local) {\n printFurtherLocalInstructions(slug, data.project.moduleName);\n } else {\n printFurtherInstructions(targetDir, packageManager, options.example);\n }\n}\n\n/**\n * Recursively scans for the files within the directory. Returned paths are relative to the `root` path.\n */\nasync function getFilesAsync(root: string, dir: string | null = null): Promise<string[]> {\n const files: string[] = [];\n const baseDir = dir ? path.join(root, dir) : root;\n\n for (const file of await fs.readdir(baseDir)) {\n const relativePath = dir ? path.join(dir, file) : file;\n\n if (IGNORES_PATHS.includes(relativePath) || IGNORES_PATHS.includes(file)) {\n continue;\n }\n\n const fullPath = path.join(baseDir, file);\n const stat = await fs.lstat(fullPath);\n\n if (stat.isDirectory()) {\n files.push(...(await getFilesAsync(root, relativePath)));\n } else {\n files.push(relativePath);\n }\n }\n return files;\n}\n\n/**\n * Asks NPM registry for the url to the tarball.\n */\nasync function getNpmTarballUrl(packageName: string, version: string = 'latest'): Promise<string> {\n debug(`Using module template ${chalk.bold(packageName)}@${chalk.bold(version)}`);\n const { stdout } = await spawnAsync('npm', ['view', `${packageName}@${version}`, 'dist.tarball']);\n return stdout.trim();\n}\n\n/**\n * Downloads the template from NPM registry.\n */\nasync function downloadPackageAsync(targetDir: string, isLocal = false): Promise<string> {\n return await newStep('Downloading module template from npm', async (step) => {\n const tarballUrl = await getNpmTarballUrl(\n isLocal ? 'expo-module-template-local' : 'expo-module-template',\n EXPO_BETA ? 'next' : 'latest'\n );\n\n await downloadTarball({\n url: tarballUrl,\n dir: targetDir,\n });\n\n step.succeed('Downloaded module template from npm');\n\n return path.join(targetDir, 'package');\n });\n}\n\nfunction handleSuffix(name: string, suffix: string): string {\n if (name.endsWith(suffix)) {\n return name;\n }\n return `${name}${suffix}`;\n}\n\n/**\n * Creates the module based on the `ejs` template (e.g. `expo-module-template` package).\n */\nasync function createModuleFromTemplate(\n templatePath: string,\n targetPath: string,\n data: SubstitutionData | LocalSubstitutionData\n) {\n const files = await getFilesAsync(templatePath);\n\n // Iterate through all template files.\n for (const file of files) {\n const renderedRelativePath = ejs.render(file.replace(/^\\$/, ''), data, {\n openDelimiter: '{',\n closeDelimiter: '}',\n escape: (value: string) => value.replace(/\\./g, path.sep),\n });\n const fromPath = path.join(templatePath, file);\n const toPath = path.join(targetPath, renderedRelativePath);\n const template = await fs.readFile(fromPath, { encoding: 'utf8' });\n const renderedContent = ejs.render(template, data);\n\n await fs.outputFile(toPath, renderedContent, { encoding: 'utf8' });\n }\n}\n\nasync function createGitRepositoryAsync(targetDir: string) {\n // Check if we are inside a git repository already\n try {\n await spawnAsync('git', ['rev-parse', '--is-inside-work-tree'], {\n stdio: 'ignore',\n cwd: targetDir,\n });\n debug(chalk.dim('New project is already inside of a Git repo, skipping git init.'));\n return null;\n } catch (e: any) {\n if (e.errno === 'ENOENT') {\n debug(chalk.dim('Unable to initialize Git repo. `git` not in $PATH.'));\n return false;\n }\n }\n\n // Create a new git repository\n await spawnAsync('git', ['init'], { stdio: 'ignore', cwd: targetDir });\n await spawnAsync('git', ['add', '-A'], { stdio: 'ignore', cwd: targetDir });\n\n const commitMsg = `Initial commit\\n\\nGenerated by ${packageJson.name} ${packageJson.version}.`;\n await spawnAsync('git', ['commit', '-m', commitMsg], {\n stdio: 'ignore',\n cwd: targetDir,\n });\n\n debug(chalk.dim('Initialized a Git repository.'));\n return true;\n}\n\n/**\n * Asks the user for the package slug (npm package name).\n */\nasync function askForPackageSlugAsync(customTargetPath?: string, isLocal = false): Promise<string> {\n const { slug } = await prompts(\n (isLocal ? getLocalFolderNamePrompt : getSlugPrompt)(customTargetPath),\n {\n onCancel: () => process.exit(0),\n }\n );\n return slug;\n}\n\n/**\n * Asks the user for some data necessary to render the template.\n * Some values may already be provided by command options, the prompt is skipped in that case.\n */\nasync function askForSubstitutionDataAsync(\n slug: string,\n isLocal = false\n): Promise<SubstitutionData | LocalSubstitutionData> {\n const promptQueries = await (isLocal\n ? getLocalSubstitutionDataPrompts\n : getSubstitutionDataPrompts)(slug);\n\n // Stop the process when the user cancels/exits the prompt.\n const onCancel = () => {\n process.exit(0);\n };\n\n const {\n name,\n description,\n package: projectPackage,\n authorName,\n authorEmail,\n authorUrl,\n repo,\n } = await prompts(promptQueries, { onCancel });\n\n if (isLocal) {\n return {\n project: {\n slug,\n name,\n package: projectPackage,\n moduleName: handleSuffix(name, 'Module'),\n viewName: handleSuffix(name, 'View'),\n },\n type: 'local',\n };\n }\n\n return {\n project: {\n slug,\n name,\n version: '0.1.0',\n description,\n package: projectPackage,\n moduleName: handleSuffix(name, 'Module'),\n viewName: handleSuffix(name, 'View'),\n },\n author: `${authorName} <${authorEmail}> (${authorUrl})`,\n license: 'MIT',\n repo,\n type: 'remote',\n };\n}\n\n/**\n * Checks whether the target directory is empty and if not, asks the user to confirm if he wants to continue.\n */\nasync function confirmTargetDirAsync(targetDir: string): Promise<void> {\n const files = await fs.readdir(targetDir);\n\n if (files.length === 0) {\n return;\n }\n const { shouldContinue } = await prompts(\n {\n type: 'confirm',\n name: 'shouldContinue',\n message: `The target directory ${chalk.magenta(\n targetDir\n )} is not empty, do you want to continue anyway?`,\n initial: true,\n },\n {\n onCancel: () => false,\n }\n );\n if (!shouldContinue) {\n process.exit(0);\n }\n}\n\n/**\n * Prints how the user can follow up once the script finishes creating the module.\n */\nfunction printFurtherInstructions(\n targetDir: string,\n packageManager: PackageManagerName,\n includesExample: boolean\n) {\n if (includesExample) {\n const commands = [\n `cd ${path.relative(CWD, targetDir)}`,\n formatRunCommand(packageManager, 'open:ios'),\n formatRunCommand(packageManager, 'open:android'),\n ];\n\n console.log();\n console.log(\n 'To start developing your module, navigate to the directory and open iOS and Android projects of the example app'\n );\n commands.forEach((command) => console.log(chalk.gray('>'), chalk.bold(command)));\n console.log();\n }\n console.log(`Visit ${chalk.blue.bold(DOCS_URL)} for the documentation on Expo Modules APIs`);\n}\n\nfunction printFurtherLocalInstructions(slug: string, name: string) {\n console.log(`You can now import this module inside your application:`);\n console.log();\n console.log(chalk.blue(`import { hello } from '${slug}';`));\n console.log();\n console.log(`Visit ${chalk.blue.bold(DOCS_URL)} for the documentation on Expo Modules APIs`);\n console.log(\n chalk.yellow(\n `Remember you need to rebuild your development client or reinstall pods to see the changes.`\n )\n );\n}\n\nconst program = new Command();\n\nprogram\n .name(packageJson.name)\n .version(packageJson.version)\n .description(packageJson.description)\n .arguments('[path]')\n .option(\n '-s, --source <source_dir>',\n 'Local path to the template. By default it downloads `expo-module-template` from NPM.'\n )\n .option('--with-readme', 'Whether to include README.md file.', false)\n .option('--with-changelog', 'Whether to include CHANGELOG.md file.', false)\n .option('--no-example', 'Whether to skip creating the example app.', false)\n .option(\n '--local',\n 'Whether to create a local module in the current project, skipping installing node_modules and creating the example directory.',\n false\n )\n .action(main);\n\nprogram\n .hook('postAction', async () => {\n await getTelemetryClient().flush?.();\n })\n .parse(process.argv);\n"]}
|
package/build/prompts.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { PromptObject } from 'prompts';
|
|
2
2
|
export declare function getSlugPrompt(customTargetPath?: string | null): PromptObject<string>;
|
|
3
|
+
export declare function getLocalFolderNamePrompt(customTargetPath?: string | null): PromptObject<string>;
|
|
3
4
|
export declare function getSubstitutionDataPrompts(slug: string): Promise<PromptObject<string>[]>;
|
|
5
|
+
export declare function getLocalSubstitutionDataPrompts(slug: string): Promise<PromptObject<string>[]>;
|
package/build/prompts.js
CHANGED
|
@@ -3,15 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getSubstitutionDataPrompts = exports.getSlugPrompt = void 0;
|
|
6
|
+
exports.getLocalSubstitutionDataPrompts = exports.getSubstitutionDataPrompts = exports.getLocalFolderNamePrompt = exports.getSlugPrompt = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
|
|
9
9
|
const utils_1 = require("./utils");
|
|
10
|
-
function
|
|
10
|
+
function getInitialName(customTargetPath) {
|
|
11
11
|
const targetBasename = customTargetPath && path_1.default.basename(customTargetPath);
|
|
12
|
-
|
|
12
|
+
return targetBasename && (0, validate_npm_package_name_1.default)(targetBasename).validForNewPackages
|
|
13
13
|
? targetBasename
|
|
14
14
|
: 'my-module';
|
|
15
|
+
}
|
|
16
|
+
function getSlugPrompt(customTargetPath) {
|
|
17
|
+
const initial = getInitialName(customTargetPath);
|
|
15
18
|
return {
|
|
16
19
|
type: 'text',
|
|
17
20
|
name: 'slug',
|
|
@@ -21,6 +24,17 @@ function getSlugPrompt(customTargetPath) {
|
|
|
21
24
|
};
|
|
22
25
|
}
|
|
23
26
|
exports.getSlugPrompt = getSlugPrompt;
|
|
27
|
+
function getLocalFolderNamePrompt(customTargetPath) {
|
|
28
|
+
const initial = getInitialName(customTargetPath);
|
|
29
|
+
return {
|
|
30
|
+
type: 'text',
|
|
31
|
+
name: 'slug',
|
|
32
|
+
message: 'What is the name of the local module?',
|
|
33
|
+
initial,
|
|
34
|
+
validate: (input) => (0, validate_npm_package_name_1.default)(input).validForNewPackages || 'Must be a valid npm package name',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
exports.getLocalFolderNamePrompt = getLocalFolderNamePrompt;
|
|
24
38
|
async function getSubstitutionDataPrompts(slug) {
|
|
25
39
|
return [
|
|
26
40
|
{
|
|
@@ -84,4 +98,34 @@ async function getSubstitutionDataPrompts(slug) {
|
|
|
84
98
|
];
|
|
85
99
|
}
|
|
86
100
|
exports.getSubstitutionDataPrompts = getSubstitutionDataPrompts;
|
|
101
|
+
async function getLocalSubstitutionDataPrompts(slug) {
|
|
102
|
+
return [
|
|
103
|
+
{
|
|
104
|
+
type: 'text',
|
|
105
|
+
name: 'name',
|
|
106
|
+
message: 'What is the native module name?',
|
|
107
|
+
initial: () => {
|
|
108
|
+
return slug
|
|
109
|
+
.replace(/^@/, '')
|
|
110
|
+
.replace(/^./, (match) => match.toUpperCase())
|
|
111
|
+
.replace(/\W+(\w)/g, (_, p1) => p1.toUpperCase());
|
|
112
|
+
},
|
|
113
|
+
validate: (input) => !!input || 'The native module name cannot be empty',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
type: 'text',
|
|
117
|
+
name: 'package',
|
|
118
|
+
message: 'What is the Android package name?',
|
|
119
|
+
initial: () => {
|
|
120
|
+
const namespace = slug
|
|
121
|
+
.replace(/\W/g, '')
|
|
122
|
+
.replace(/^(expo|reactnative)/, '')
|
|
123
|
+
.toLowerCase();
|
|
124
|
+
return `expo.modules.${namespace}`;
|
|
125
|
+
},
|
|
126
|
+
validate: (input) => !!input || 'The Android package name cannot be empty',
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
exports.getLocalSubstitutionDataPrompts = getLocalSubstitutionDataPrompts;
|
|
87
131
|
//# sourceMappingURL=prompts.js.map
|
package/build/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AAExB,0FAA2D;AAE3D,mCAA0F;AAE1F,
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport { Answers, PromptObject } from 'prompts';\nimport validateNpmPackage from 'validate-npm-package-name';\n\nimport { findGitHubEmail, findGitHubProfileUrl, findMyName, guessRepoUrl } from './utils';\n\nfunction getInitialName(customTargetPath?: string | null): string {\n const targetBasename = customTargetPath && path.basename(customTargetPath);\n return targetBasename && validateNpmPackage(targetBasename).validForNewPackages\n ? targetBasename\n : 'my-module';\n}\n\nexport function getSlugPrompt(customTargetPath?: string | null): PromptObject<string> {\n const initial = getInitialName(customTargetPath);\n return {\n type: 'text',\n name: 'slug',\n message: 'What is the name of the npm package?',\n initial,\n validate: (input) =>\n validateNpmPackage(input).validForNewPackages || 'Must be a valid npm package name',\n };\n}\n\nexport function getLocalFolderNamePrompt(customTargetPath?: string | null): PromptObject<string> {\n const initial = getInitialName(customTargetPath);\n\n return {\n type: 'text',\n name: 'slug',\n message: 'What is the name of the local module?',\n initial,\n validate: (input) =>\n validateNpmPackage(input).validForNewPackages || 'Must be a valid npm package name',\n };\n}\n\nexport async function getSubstitutionDataPrompts(slug: string): Promise<PromptObject<string>[]> {\n return [\n {\n type: 'text',\n name: 'name',\n message: 'What is the native module name?',\n initial: () => {\n return slug\n .replace(/^@/, '')\n .replace(/^./, (match) => match.toUpperCase())\n .replace(/\\W+(\\w)/g, (_, p1) => p1.toUpperCase());\n },\n validate: (input) => !!input || 'The native module name cannot be empty',\n },\n {\n type: 'text',\n name: 'description',\n message: 'How would you describe the module?',\n initial: 'My new module',\n validate: (input) => !!input || 'The description cannot be empty',\n },\n {\n type: 'text',\n name: 'package',\n message: 'What is the Android package name?',\n initial: () => {\n const namespace = slug\n .replace(/\\W/g, '')\n .replace(/^(expo|reactnative)/, '')\n .toLowerCase();\n return `expo.modules.${namespace}`;\n },\n validate: (input) => !!input || 'The Android package name cannot be empty',\n },\n {\n type: 'text',\n name: 'authorName',\n message: 'What is the name of the package author?',\n initial: await findMyName(),\n validate: (input) => !!input || 'Cannot be empty',\n },\n {\n type: 'text',\n name: 'authorEmail',\n message: 'What is the email address of the author?',\n initial: await findGitHubEmail(),\n },\n {\n type: 'text',\n name: 'authorUrl',\n message: \"What is the URL to the author's GitHub profile?\",\n initial: async (_, answers: Answers<string>) =>\n await findGitHubProfileUrl(answers.authorEmail),\n },\n {\n type: 'text',\n name: 'repo',\n message: 'What is the URL for the repository?',\n initial: async (_, answers: Answers<string>) => await guessRepoUrl(answers.authorUrl, slug),\n validate: (input) => /^https?:\\/\\//.test(input) || 'Must be a valid URL',\n },\n ];\n}\n\nexport async function getLocalSubstitutionDataPrompts(\n slug: string\n): Promise<PromptObject<string>[]> {\n return [\n {\n type: 'text',\n name: 'name',\n message: 'What is the native module name?',\n initial: () => {\n return slug\n .replace(/^@/, '')\n .replace(/^./, (match) => match.toUpperCase())\n .replace(/\\W+(\\w)/g, (_, p1) => p1.toUpperCase());\n },\n validate: (input) => !!input || 'The native module name cannot be empty',\n },\n {\n type: 'text',\n name: 'package',\n message: 'What is the Android package name?',\n initial: () => {\n const namespace = slug\n .replace(/\\W/g, '')\n .replace(/^(expo|reactnative)/, '')\n .toLowerCase();\n return `expo.modules.${namespace}`;\n },\n validate: (input) => !!input || 'The Android package name cannot be empty',\n },\n ];\n}\n"]}
|
package/build/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type CommandOptions = {
|
|
|
8
8
|
withReadme: boolean;
|
|
9
9
|
withChangelog: boolean;
|
|
10
10
|
example: boolean;
|
|
11
|
+
local: boolean;
|
|
11
12
|
};
|
|
12
13
|
/**
|
|
13
14
|
* Represents an object that is passed to `ejs` when rendering the template.
|
|
@@ -25,6 +26,17 @@ export type SubstitutionData = {
|
|
|
25
26
|
author: string;
|
|
26
27
|
license: string;
|
|
27
28
|
repo: string;
|
|
29
|
+
type: 'remote';
|
|
30
|
+
};
|
|
31
|
+
export type LocalSubstitutionData = {
|
|
32
|
+
project: {
|
|
33
|
+
slug: string;
|
|
34
|
+
name: string;
|
|
35
|
+
package: string;
|
|
36
|
+
moduleName: string;
|
|
37
|
+
viewName: string;
|
|
38
|
+
};
|
|
39
|
+
type: 'local';
|
|
28
40
|
};
|
|
29
41
|
export type CustomPromptObject = PromptObject & {
|
|
30
42
|
name: string;
|
package/build/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { PromptObject } from 'prompts';\n\n/**\n * Possible command options.\n */\nexport type CommandOptions = {\n target: string;\n source?: string;\n withReadme: boolean;\n withChangelog: boolean;\n example: boolean;\n};\n\n/**\n * Represents an object that is passed to `ejs` when rendering the template.\n */\nexport type SubstitutionData = {\n project: {\n slug: string;\n name: string;\n version: string;\n description: string;\n package: string;\n moduleName: string;\n viewName: string;\n };\n author: string;\n license: string;\n repo: string;\n};\n\nexport type CustomPromptObject = PromptObject & {\n name: string;\n resolvedValue?: string | null;\n};\n\nexport type Answers = Record<string, string>;\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { PromptObject } from 'prompts';\n\n/**\n * Possible command options.\n */\nexport type CommandOptions = {\n target: string;\n source?: string;\n withReadme: boolean;\n withChangelog: boolean;\n example: boolean;\n local: boolean;\n};\n\n/**\n * Represents an object that is passed to `ejs` when rendering the template.\n */\nexport type SubstitutionData = {\n project: {\n slug: string;\n name: string;\n version: string;\n description: string;\n package: string;\n moduleName: string;\n viewName: string;\n };\n author: string;\n license: string;\n repo: string;\n type: 'remote';\n};\n\nexport type LocalSubstitutionData = {\n project: {\n slug: string;\n name: string;\n package: string;\n moduleName: string;\n viewName: string;\n };\n type: 'local';\n};\n\nexport type CustomPromptObject = PromptObject & {\n name: string;\n resolvedValue?: string | null;\n};\n\nexport type Answers = Record<string, string>;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-expo-module",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "The script to create the Expo module",
|
|
5
5
|
"main": "build/create-expo-module.js",
|
|
6
6
|
"types": "build/create-expo-module.d.ts",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"debug": "^4.3.4",
|
|
44
44
|
"download-tarball": "^2.0.0",
|
|
45
45
|
"ejs": "^3.1.7",
|
|
46
|
+
"find-up": "^5.0.0",
|
|
46
47
|
"fs-extra": "^10.0.0",
|
|
47
48
|
"getenv": "^1.0.0",
|
|
48
49
|
"github-username": "^6.0.0",
|
|
@@ -53,8 +54,9 @@
|
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@tsconfig/node14": "^1.0.3",
|
|
55
56
|
"@types/ejs": "^3.1.0",
|
|
57
|
+
"@types/find-up": "^4.0.0",
|
|
56
58
|
"@types/prompts": "^2.0.14",
|
|
57
59
|
"expo-module-scripts": "^3.0.0"
|
|
58
60
|
},
|
|
59
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "5222dff5bbfeb88d610dac5215809285700fb819"
|
|
60
62
|
}
|
|
@@ -3,6 +3,7 @@ import chalk from 'chalk';
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import downloadTarball from 'download-tarball';
|
|
5
5
|
import ejs from 'ejs';
|
|
6
|
+
import findUp from 'find-up';
|
|
6
7
|
import fs from 'fs-extra';
|
|
7
8
|
import { boolish } from 'getenv';
|
|
8
9
|
import path from 'path';
|
|
@@ -10,14 +11,19 @@ import prompts from 'prompts';
|
|
|
10
11
|
|
|
11
12
|
import { createExampleApp } from './createExampleApp';
|
|
12
13
|
import { installDependencies } from './packageManager';
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
getLocalFolderNamePrompt,
|
|
16
|
+
getLocalSubstitutionDataPrompts,
|
|
17
|
+
getSlugPrompt,
|
|
18
|
+
getSubstitutionDataPrompts,
|
|
19
|
+
} from './prompts';
|
|
14
20
|
import {
|
|
15
21
|
formatRunCommand,
|
|
16
22
|
PackageManagerName,
|
|
17
23
|
resolvePackageManager,
|
|
18
24
|
} from './resolvePackageManager';
|
|
19
25
|
import { eventCreateExpoModule, getTelemetryClient, logEventAsync } from './telemetry';
|
|
20
|
-
import { CommandOptions, SubstitutionData } from './types';
|
|
26
|
+
import { CommandOptions, LocalSubstitutionData, SubstitutionData } from './types';
|
|
21
27
|
import { newStep } from './utils';
|
|
22
28
|
|
|
23
29
|
const debug = require('debug')('create-expo-module:main') as typeof console.log;
|
|
@@ -43,6 +49,24 @@ const IGNORES_PATHS = [
|
|
|
43
49
|
// Url to the documentation on Expo Modules
|
|
44
50
|
const DOCS_URL = 'https://docs.expo.dev/modules';
|
|
45
51
|
|
|
52
|
+
async function getCorrectLocalDirectory(targetOrSlug: string) {
|
|
53
|
+
const packageJsonPath = await findUp('package.json', { cwd: CWD });
|
|
54
|
+
if (!packageJsonPath) {
|
|
55
|
+
console.log(
|
|
56
|
+
chalk.red.bold(
|
|
57
|
+
'⚠️ This command should be run inside your Expo project when run with the --local flag.'
|
|
58
|
+
)
|
|
59
|
+
);
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.red(
|
|
62
|
+
'For native modules to autolink correctly, you need to place them in the `modules` directory in the root of the project.'
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return path.join(packageJsonPath, '..', 'modules', targetOrSlug);
|
|
68
|
+
}
|
|
69
|
+
|
|
46
70
|
/**
|
|
47
71
|
* The main function of the command.
|
|
48
72
|
*
|
|
@@ -50,15 +74,20 @@ const DOCS_URL = 'https://docs.expo.dev/modules';
|
|
|
50
74
|
* @param command An object from `commander`.
|
|
51
75
|
*/
|
|
52
76
|
async function main(target: string | undefined, options: CommandOptions) {
|
|
53
|
-
const slug = await askForPackageSlugAsync(target);
|
|
54
|
-
const targetDir =
|
|
77
|
+
const slug = await askForPackageSlugAsync(target, options.local);
|
|
78
|
+
const targetDir = options.local
|
|
79
|
+
? await getCorrectLocalDirectory(target || slug)
|
|
80
|
+
: path.join(CWD, target || slug);
|
|
55
81
|
|
|
82
|
+
if (!targetDir) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
56
85
|
await fs.ensureDir(targetDir);
|
|
57
86
|
await confirmTargetDirAsync(targetDir);
|
|
58
87
|
|
|
59
88
|
options.target = targetDir;
|
|
60
89
|
|
|
61
|
-
const data = await askForSubstitutionDataAsync(slug);
|
|
90
|
+
const data = await askForSubstitutionDataAsync(slug, options.local);
|
|
62
91
|
|
|
63
92
|
// Make one line break between prompts and progress logs
|
|
64
93
|
console.log();
|
|
@@ -66,7 +95,7 @@ async function main(target: string | undefined, options: CommandOptions) {
|
|
|
66
95
|
const packageManager = await resolvePackageManager();
|
|
67
96
|
const packagePath = options.source
|
|
68
97
|
? path.join(CWD, options.source)
|
|
69
|
-
: await downloadPackageAsync(targetDir);
|
|
98
|
+
: await downloadPackageAsync(targetDir, options.local);
|
|
70
99
|
|
|
71
100
|
logEventAsync(eventCreateExpoModule(packageManager, options));
|
|
72
101
|
|
|
@@ -74,55 +103,62 @@ async function main(target: string | undefined, options: CommandOptions) {
|
|
|
74
103
|
await createModuleFromTemplate(packagePath, targetDir, data);
|
|
75
104
|
step.succeed('Created the module from template files');
|
|
76
105
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (result) {
|
|
82
|
-
step.succeed('Created an empty Git repository');
|
|
83
|
-
} else if (result === null) {
|
|
84
|
-
step.succeed('Skipped creating an empty Git repository, already within a Git repository');
|
|
85
|
-
} else if (result === false) {
|
|
86
|
-
step.warn('Could not create an empty Git repository, see debug logs with EXPO_DEBUG=true');
|
|
87
|
-
}
|
|
88
|
-
} catch (e: any) {
|
|
89
|
-
step.fail(e.toString());
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
await newStep('Installing module dependencies', async (step) => {
|
|
94
|
-
await installDependencies(packageManager, targetDir);
|
|
95
|
-
step.succeed('Installed module dependencies');
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
await newStep('Compiling TypeScript files', async (step) => {
|
|
99
|
-
await spawnAsync(packageManager, ['run', 'build'], {
|
|
100
|
-
cwd: targetDir,
|
|
101
|
-
stdio: 'ignore',
|
|
106
|
+
if (!options.local) {
|
|
107
|
+
await newStep('Installing module dependencies', async (step) => {
|
|
108
|
+
await installDependencies(packageManager, targetDir);
|
|
109
|
+
step.succeed('Installed module dependencies');
|
|
102
110
|
});
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
await newStep('Compiling TypeScript files', async (step) => {
|
|
112
|
+
await spawnAsync(packageManager, ['run', 'build'], {
|
|
113
|
+
cwd: targetDir,
|
|
114
|
+
stdio: 'ignore',
|
|
115
|
+
});
|
|
116
|
+
step.succeed('Compiled TypeScript files');
|
|
117
|
+
});
|
|
118
|
+
}
|
|
105
119
|
|
|
106
120
|
if (!options.source) {
|
|
107
121
|
// Files in the downloaded tarball are wrapped in `package` dir.
|
|
108
122
|
// We should remove it after all.
|
|
109
123
|
await fs.remove(packagePath);
|
|
110
124
|
}
|
|
111
|
-
if (!options.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
if (!options.local && data.type !== 'local') {
|
|
126
|
+
if (!options.withReadme) {
|
|
127
|
+
await fs.remove(path.join(targetDir, 'README.md'));
|
|
128
|
+
}
|
|
129
|
+
if (!options.withChangelog) {
|
|
130
|
+
await fs.remove(path.join(targetDir, 'CHANGELOG.md'));
|
|
131
|
+
}
|
|
132
|
+
if (options.example) {
|
|
133
|
+
// Create "example" folder
|
|
134
|
+
await createExampleApp(data, targetDir, packageManager);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
await newStep('Creating an empty Git repository', async (step) => {
|
|
138
|
+
try {
|
|
139
|
+
const result = await createGitRepositoryAsync(targetDir);
|
|
140
|
+
if (result) {
|
|
141
|
+
step.succeed('Created an empty Git repository');
|
|
142
|
+
} else if (result === null) {
|
|
143
|
+
step.succeed('Skipped creating an empty Git repository, already within a Git repository');
|
|
144
|
+
} else if (result === false) {
|
|
145
|
+
step.warn(
|
|
146
|
+
'Could not create an empty Git repository, see debug logs with EXPO_DEBUG=true'
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
} catch (e: any) {
|
|
150
|
+
step.fail(e.toString());
|
|
151
|
+
}
|
|
152
|
+
});
|
|
120
153
|
}
|
|
121
154
|
|
|
122
155
|
console.log();
|
|
123
156
|
console.log('✅ Successfully created Expo module');
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
if (options.local) {
|
|
158
|
+
printFurtherLocalInstructions(slug, data.project.moduleName);
|
|
159
|
+
} else {
|
|
160
|
+
printFurtherInstructions(targetDir, packageManager, options.example);
|
|
161
|
+
}
|
|
126
162
|
}
|
|
127
163
|
|
|
128
164
|
/**
|
|
@@ -163,10 +199,10 @@ async function getNpmTarballUrl(packageName: string, version: string = 'latest')
|
|
|
163
199
|
/**
|
|
164
200
|
* Downloads the template from NPM registry.
|
|
165
201
|
*/
|
|
166
|
-
async function downloadPackageAsync(targetDir: string): Promise<string> {
|
|
202
|
+
async function downloadPackageAsync(targetDir: string, isLocal = false): Promise<string> {
|
|
167
203
|
return await newStep('Downloading module template from npm', async (step) => {
|
|
168
204
|
const tarballUrl = await getNpmTarballUrl(
|
|
169
|
-
'expo-module-template',
|
|
205
|
+
isLocal ? 'expo-module-template-local' : 'expo-module-template',
|
|
170
206
|
EXPO_BETA ? 'next' : 'latest'
|
|
171
207
|
);
|
|
172
208
|
|
|
@@ -194,7 +230,7 @@ function handleSuffix(name: string, suffix: string): string {
|
|
|
194
230
|
async function createModuleFromTemplate(
|
|
195
231
|
templatePath: string,
|
|
196
232
|
targetPath: string,
|
|
197
|
-
data: SubstitutionData
|
|
233
|
+
data: SubstitutionData | LocalSubstitutionData
|
|
198
234
|
) {
|
|
199
235
|
const files = await getFilesAsync(templatePath);
|
|
200
236
|
|
|
@@ -247,10 +283,13 @@ async function createGitRepositoryAsync(targetDir: string) {
|
|
|
247
283
|
/**
|
|
248
284
|
* Asks the user for the package slug (npm package name).
|
|
249
285
|
*/
|
|
250
|
-
async function askForPackageSlugAsync(customTargetPath?: string): Promise<string> {
|
|
251
|
-
const { slug } = await prompts(
|
|
252
|
-
|
|
253
|
-
|
|
286
|
+
async function askForPackageSlugAsync(customTargetPath?: string, isLocal = false): Promise<string> {
|
|
287
|
+
const { slug } = await prompts(
|
|
288
|
+
(isLocal ? getLocalFolderNamePrompt : getSlugPrompt)(customTargetPath),
|
|
289
|
+
{
|
|
290
|
+
onCancel: () => process.exit(0),
|
|
291
|
+
}
|
|
292
|
+
);
|
|
254
293
|
return slug;
|
|
255
294
|
}
|
|
256
295
|
|
|
@@ -258,8 +297,13 @@ async function askForPackageSlugAsync(customTargetPath?: string): Promise<string
|
|
|
258
297
|
* Asks the user for some data necessary to render the template.
|
|
259
298
|
* Some values may already be provided by command options, the prompt is skipped in that case.
|
|
260
299
|
*/
|
|
261
|
-
async function askForSubstitutionDataAsync(
|
|
262
|
-
|
|
300
|
+
async function askForSubstitutionDataAsync(
|
|
301
|
+
slug: string,
|
|
302
|
+
isLocal = false
|
|
303
|
+
): Promise<SubstitutionData | LocalSubstitutionData> {
|
|
304
|
+
const promptQueries = await (isLocal
|
|
305
|
+
? getLocalSubstitutionDataPrompts
|
|
306
|
+
: getSubstitutionDataPrompts)(slug);
|
|
263
307
|
|
|
264
308
|
// Stop the process when the user cancels/exits the prompt.
|
|
265
309
|
const onCancel = () => {
|
|
@@ -276,6 +320,19 @@ async function askForSubstitutionDataAsync(slug: string): Promise<SubstitutionDa
|
|
|
276
320
|
repo,
|
|
277
321
|
} = await prompts(promptQueries, { onCancel });
|
|
278
322
|
|
|
323
|
+
if (isLocal) {
|
|
324
|
+
return {
|
|
325
|
+
project: {
|
|
326
|
+
slug,
|
|
327
|
+
name,
|
|
328
|
+
package: projectPackage,
|
|
329
|
+
moduleName: handleSuffix(name, 'Module'),
|
|
330
|
+
viewName: handleSuffix(name, 'View'),
|
|
331
|
+
},
|
|
332
|
+
type: 'local',
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
279
336
|
return {
|
|
280
337
|
project: {
|
|
281
338
|
slug,
|
|
@@ -289,6 +346,7 @@ async function askForSubstitutionDataAsync(slug: string): Promise<SubstitutionDa
|
|
|
289
346
|
author: `${authorName} <${authorEmail}> (${authorUrl})`,
|
|
290
347
|
license: 'MIT',
|
|
291
348
|
repo,
|
|
349
|
+
type: 'remote',
|
|
292
350
|
};
|
|
293
351
|
}
|
|
294
352
|
|
|
@@ -344,6 +402,19 @@ function printFurtherInstructions(
|
|
|
344
402
|
console.log(`Visit ${chalk.blue.bold(DOCS_URL)} for the documentation on Expo Modules APIs`);
|
|
345
403
|
}
|
|
346
404
|
|
|
405
|
+
function printFurtherLocalInstructions(slug: string, name: string) {
|
|
406
|
+
console.log(`You can now import this module inside your application:`);
|
|
407
|
+
console.log();
|
|
408
|
+
console.log(chalk.blue(`import { hello } from '${slug}';`));
|
|
409
|
+
console.log();
|
|
410
|
+
console.log(`Visit ${chalk.blue.bold(DOCS_URL)} for the documentation on Expo Modules APIs`);
|
|
411
|
+
console.log(
|
|
412
|
+
chalk.yellow(
|
|
413
|
+
`Remember you need to rebuild your development client or reinstall pods to see the changes.`
|
|
414
|
+
)
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
347
418
|
const program = new Command();
|
|
348
419
|
|
|
349
420
|
program
|
|
@@ -358,6 +429,11 @@ program
|
|
|
358
429
|
.option('--with-readme', 'Whether to include README.md file.', false)
|
|
359
430
|
.option('--with-changelog', 'Whether to include CHANGELOG.md file.', false)
|
|
360
431
|
.option('--no-example', 'Whether to skip creating the example app.', false)
|
|
432
|
+
.option(
|
|
433
|
+
'--local',
|
|
434
|
+
'Whether to create a local module in the current project, skipping installing node_modules and creating the example directory.',
|
|
435
|
+
false
|
|
436
|
+
)
|
|
361
437
|
.action(main);
|
|
362
438
|
|
|
363
439
|
program
|
package/src/prompts.ts
CHANGED
|
@@ -4,13 +4,15 @@ import validateNpmPackage from 'validate-npm-package-name';
|
|
|
4
4
|
|
|
5
5
|
import { findGitHubEmail, findGitHubProfileUrl, findMyName, guessRepoUrl } from './utils';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
function getInitialName(customTargetPath?: string | null): string {
|
|
8
8
|
const targetBasename = customTargetPath && path.basename(customTargetPath);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
return targetBasename && validateNpmPackage(targetBasename).validForNewPackages
|
|
10
|
+
? targetBasename
|
|
11
|
+
: 'my-module';
|
|
12
|
+
}
|
|
13
13
|
|
|
14
|
+
export function getSlugPrompt(customTargetPath?: string | null): PromptObject<string> {
|
|
15
|
+
const initial = getInitialName(customTargetPath);
|
|
14
16
|
return {
|
|
15
17
|
type: 'text',
|
|
16
18
|
name: 'slug',
|
|
@@ -21,6 +23,19 @@ export function getSlugPrompt(customTargetPath?: string | null): PromptObject<st
|
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
export function getLocalFolderNamePrompt(customTargetPath?: string | null): PromptObject<string> {
|
|
27
|
+
const initial = getInitialName(customTargetPath);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
type: 'text',
|
|
31
|
+
name: 'slug',
|
|
32
|
+
message: 'What is the name of the local module?',
|
|
33
|
+
initial,
|
|
34
|
+
validate: (input) =>
|
|
35
|
+
validateNpmPackage(input).validForNewPackages || 'Must be a valid npm package name',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
24
39
|
export async function getSubstitutionDataPrompts(slug: string): Promise<PromptObject<string>[]> {
|
|
25
40
|
return [
|
|
26
41
|
{
|
|
@@ -84,3 +99,35 @@ export async function getSubstitutionDataPrompts(slug: string): Promise<PromptOb
|
|
|
84
99
|
},
|
|
85
100
|
];
|
|
86
101
|
}
|
|
102
|
+
|
|
103
|
+
export async function getLocalSubstitutionDataPrompts(
|
|
104
|
+
slug: string
|
|
105
|
+
): Promise<PromptObject<string>[]> {
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
type: 'text',
|
|
109
|
+
name: 'name',
|
|
110
|
+
message: 'What is the native module name?',
|
|
111
|
+
initial: () => {
|
|
112
|
+
return slug
|
|
113
|
+
.replace(/^@/, '')
|
|
114
|
+
.replace(/^./, (match) => match.toUpperCase())
|
|
115
|
+
.replace(/\W+(\w)/g, (_, p1) => p1.toUpperCase());
|
|
116
|
+
},
|
|
117
|
+
validate: (input) => !!input || 'The native module name cannot be empty',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: 'text',
|
|
121
|
+
name: 'package',
|
|
122
|
+
message: 'What is the Android package name?',
|
|
123
|
+
initial: () => {
|
|
124
|
+
const namespace = slug
|
|
125
|
+
.replace(/\W/g, '')
|
|
126
|
+
.replace(/^(expo|reactnative)/, '')
|
|
127
|
+
.toLowerCase();
|
|
128
|
+
return `expo.modules.${namespace}`;
|
|
129
|
+
},
|
|
130
|
+
validate: (input) => !!input || 'The Android package name cannot be empty',
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type CommandOptions = {
|
|
|
9
9
|
withReadme: boolean;
|
|
10
10
|
withChangelog: boolean;
|
|
11
11
|
example: boolean;
|
|
12
|
+
local: boolean;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -27,6 +28,18 @@ export type SubstitutionData = {
|
|
|
27
28
|
author: string;
|
|
28
29
|
license: string;
|
|
29
30
|
repo: string;
|
|
31
|
+
type: 'remote';
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type LocalSubstitutionData = {
|
|
35
|
+
project: {
|
|
36
|
+
slug: string;
|
|
37
|
+
name: string;
|
|
38
|
+
package: string;
|
|
39
|
+
moduleName: string;
|
|
40
|
+
viewName: string;
|
|
41
|
+
};
|
|
42
|
+
type: 'local';
|
|
30
43
|
};
|
|
31
44
|
|
|
32
45
|
export type CustomPromptObject = PromptObject & {
|