create-expo-module 0.2.0 → 0.3.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 +29 -17
- package/build/create-expo-module.js.map +1 -1
- package/build/resolvePackageManager.d.ts +3 -0
- package/build/resolvePackageManager.js +36 -0
- package/build/resolvePackageManager.js.map +1 -0
- package/package.json +4 -3
- package/src/create-expo-module.ts +40 -21
- package/src/resolvePackageManager.ts +34 -0
|
@@ -4,12 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const spawn_async_1 = __importDefault(require("@expo/spawn-async"));
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
7
8
|
const commander_1 = require("commander");
|
|
8
9
|
const download_tarball_1 = __importDefault(require("download-tarball"));
|
|
9
10
|
const ejs_1 = __importDefault(require("ejs"));
|
|
10
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
12
|
const path_1 = __importDefault(require("path"));
|
|
12
13
|
const prompts_1 = __importDefault(require("prompts"));
|
|
14
|
+
const resolvePackageManager_1 = require("./resolvePackageManager");
|
|
13
15
|
const packageJson = require('../package.json');
|
|
14
16
|
// `yarn run` may change the current working dir, then we should use `INIT_CWD` env.
|
|
15
17
|
const CWD = process.env.INIT_CWD || process.cwd();
|
|
@@ -24,10 +26,11 @@ const IGNORES_PATHS = ['.DS_Store', 'build', 'node_modules', 'package.json'];
|
|
|
24
26
|
*/
|
|
25
27
|
async function main(target, options) {
|
|
26
28
|
const targetDir = target ? path_1.default.join(CWD, target) : CWD;
|
|
29
|
+
await confirmTargetDirAsync(targetDir);
|
|
27
30
|
options.target = targetDir;
|
|
28
31
|
await fs_extra_1.default.ensureDir(targetDir);
|
|
29
32
|
const data = await askForSubstitutionDataAsync(targetDir, options);
|
|
30
|
-
const packageManager = await
|
|
33
|
+
const packageManager = await (0, resolvePackageManager_1.resolvePackageManager)();
|
|
31
34
|
const packagePath = options.source
|
|
32
35
|
? path_1.default.join(CWD, options.source)
|
|
33
36
|
: await downloadPackageAsync(targetDir);
|
|
@@ -114,21 +117,6 @@ async function downloadPackageAsync(targetDir) {
|
|
|
114
117
|
});
|
|
115
118
|
return path_1.default.join(targetDir, 'package');
|
|
116
119
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Asks whether to use Yarn or npm as a dependency package manager.
|
|
119
|
-
*/
|
|
120
|
-
async function selectPackageManagerAsync() {
|
|
121
|
-
const { packageManager } = await (0, prompts_1.default)({
|
|
122
|
-
type: 'select',
|
|
123
|
-
name: 'packageManager',
|
|
124
|
-
message: 'Which package manager do you want to use to install dependencies?',
|
|
125
|
-
choices: [
|
|
126
|
-
{ title: 'yarn', value: 'yarn' },
|
|
127
|
-
{ title: 'npm', value: 'npm' },
|
|
128
|
-
],
|
|
129
|
-
});
|
|
130
|
-
return packageManager;
|
|
131
|
-
}
|
|
132
120
|
/**
|
|
133
121
|
* Installs dependencies and builds TypeScript files.
|
|
134
122
|
*/
|
|
@@ -197,10 +185,14 @@ async function askForSubstitutionDataAsync(targetDir, options) {
|
|
|
197
185
|
message: 'What is the repository URL?',
|
|
198
186
|
},
|
|
199
187
|
];
|
|
188
|
+
// Stop the process when the user cancels/exits the prompt.
|
|
189
|
+
const onCancel = () => {
|
|
190
|
+
process.exit(0);
|
|
191
|
+
};
|
|
200
192
|
const answers = {};
|
|
201
193
|
for (const query of promptQueries) {
|
|
202
194
|
const { name, resolvedValue } = query;
|
|
203
|
-
answers[name] = (_b = resolvedValue !== null && resolvedValue !== void 0 ? resolvedValue : options[name]) !== null && _b !== void 0 ? _b : (await (0, prompts_1.default)(query))[name];
|
|
195
|
+
answers[name] = (_b = resolvedValue !== null && resolvedValue !== void 0 ? resolvedValue : options[name]) !== null && _b !== void 0 ? _b : (await (0, prompts_1.default)(query, { onCancel }))[name];
|
|
204
196
|
}
|
|
205
197
|
const { slug, name, description, package: projectPackage, author, license, repo } = answers;
|
|
206
198
|
return {
|
|
@@ -216,6 +208,26 @@ async function askForSubstitutionDataAsync(targetDir, options) {
|
|
|
216
208
|
repo,
|
|
217
209
|
};
|
|
218
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Checks whether the target directory is empty and if not, asks the user to confirm if he wants to continue.
|
|
213
|
+
*/
|
|
214
|
+
async function confirmTargetDirAsync(targetDir) {
|
|
215
|
+
const files = await fs_extra_1.default.readdir(targetDir);
|
|
216
|
+
if (files.length === 0) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const { shouldContinue } = await (0, prompts_1.default)({
|
|
220
|
+
type: 'confirm',
|
|
221
|
+
name: 'shouldContinue',
|
|
222
|
+
message: `The target directory ${chalk_1.default.magenta(targetDir)} is not empty.\nDo you want to continue anyway?`,
|
|
223
|
+
initial: true,
|
|
224
|
+
}, {
|
|
225
|
+
onCancel: () => false,
|
|
226
|
+
});
|
|
227
|
+
if (!shouldContinue) {
|
|
228
|
+
process.exit(0);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
219
231
|
const program = new commander_1.Command();
|
|
220
232
|
program
|
|
221
233
|
.name(packageJson.name)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-expo-module.js","sourceRoot":"","sources":["../src/create-expo-module.ts"],"names":[],"mappings":"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","sourcesContent":["import spawnAsync from '@expo/spawn-async';\nimport { Command } from 'commander';\nimport downloadTarball from 'download-tarball';\nimport ejs from 'ejs';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport prompts, { PromptObject } from 'prompts';\n\nconst packageJson = require('../package.json');\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 = ['.DS_Store', 'build', 'node_modules', 'package.json'];\n\n/**\n * Possible command options.\n */\ntype CommandOptions = {\n target: string;\n source?: string;\n name?: string;\n description?: string;\n package?: string;\n author?: string;\n license?: string;\n repo?: string;\n withReadme: boolean;\n withChangelog: boolean;\n};\n\n/**\n * Represents an object that is passed to `ejs` when rendering the template.\n */\ntype SubstitutionData = {\n project: {\n slug: string;\n name: string;\n version: string;\n description: string;\n package: string;\n };\n author: string;\n license: string;\n repo: string;\n};\n\ntype CustomPromptObject = PromptObject & {\n name: string;\n resolvedValue?: string | null;\n};\n\ntype PackageManager = 'npm' | 'yarn';\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 targetDir = target ? path.join(CWD, target) : CWD;\n\n options.target = targetDir;\n await fs.ensureDir(targetDir);\n\n const data = await askForSubstitutionDataAsync(targetDir, options);\n const packageManager = await selectPackageManagerAsync();\n const packagePath = options.source\n ? path.join(CWD, options.source)\n : await downloadPackageAsync(targetDir);\n const files = await getFilesAsync(packagePath);\n\n console.log('🎨 Creating Expo module from the template files...');\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('.', path.sep),\n });\n const fromPath = path.join(packagePath, file);\n const toPath = path.join(targetDir, 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 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\n // Install dependencies and build\n await postActionsAsync(packageManager, targetDir);\n\n console.log('✅ Successfully created Expo module');\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 const { stdout } = await spawnAsync('npm', ['view', `${packageName}@${version}`, 'dist.tarball']);\n return stdout.trim();\n}\n\n/**\n * Gets the username of currently logged in user. Used as a default in the prompt asking for the module author.\n */\nasync function npmWhoamiAsync(targetDir: string): Promise<string | null> {\n try {\n const { stdout } = await spawnAsync('npm', ['whoami'], { cwd: targetDir });\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\n/**\n * Downloads the template from NPM registry.\n */\nasync function downloadPackageAsync(targetDir: string): Promise<string> {\n const tarballUrl = await getNpmTarballUrl('expo-module-template');\n\n console.log('⬇️ Downloading module template from npm...');\n\n await downloadTarball({\n url: tarballUrl,\n dir: targetDir,\n });\n return path.join(targetDir, 'package');\n}\n\n/**\n * Asks whether to use Yarn or npm as a dependency package manager.\n */\nasync function selectPackageManagerAsync(): Promise<PackageManager> {\n const { packageManager } = await prompts({\n type: 'select',\n name: 'packageManager',\n message: 'Which package manager do you want to use to install dependencies?',\n choices: [\n { title: 'yarn', value: 'yarn' },\n { title: 'npm', value: 'npm' },\n ],\n });\n return packageManager;\n}\n\n/**\n * Installs dependencies and builds TypeScript files.\n */\nasync function postActionsAsync(packageManager: PackageManager, targetDir: string) {\n async function run(...args: string[]) {\n await spawnAsync(packageManager, args, {\n cwd: targetDir,\n stdio: 'ignore',\n });\n }\n\n console.log('📦 Installing dependencies...');\n await run('install');\n\n console.log('🛠 Compiling TypeScript files...');\n await run('run', 'build');\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 targetDir: string,\n options: CommandOptions\n): Promise<SubstitutionData> {\n const defaultPackageSlug = path.basename(targetDir);\n const defaultProjectName = defaultPackageSlug\n .replace(/^./, (match) => match.toUpperCase())\n .replace(/\\W+(\\w)/g, (_, p1) => p1.toUpperCase());\n\n const promptQueries: CustomPromptObject[] = [\n {\n type: 'text',\n name: 'slug',\n message: 'What is the package slug?',\n initial: defaultPackageSlug,\n resolvedValue: options.target ? defaultPackageSlug : null,\n },\n {\n type: 'text',\n name: 'name',\n message: 'What is the project name?',\n initial: defaultProjectName,\n },\n {\n type: 'text',\n name: 'description',\n message: 'How would you describe the module?',\n },\n {\n type: 'text',\n name: 'package',\n message: 'What is the Android package name?',\n initial: `expo.modules.${defaultPackageSlug.replace(/\\W/g, '').toLowerCase()}`,\n },\n {\n type: 'text',\n name: 'author',\n message: 'Who is the author?',\n initial: (await npmWhoamiAsync(targetDir)) ?? '',\n },\n {\n type: 'text',\n name: 'license',\n message: 'What is the license?',\n initial: 'MIT',\n },\n {\n type: 'text',\n name: 'repo',\n message: 'What is the repository URL?',\n },\n ];\n\n const answers: Record<string, string> = {};\n for (const query of promptQueries) {\n const { name, resolvedValue } = query;\n answers[name] = resolvedValue ?? options[name] ?? (await prompts(query))[name];\n }\n\n const { slug, name, description, package: projectPackage, author, license, repo } = answers;\n\n return {\n project: {\n slug,\n name,\n version: '0.1.0',\n description,\n package: projectPackage,\n },\n author,\n license,\n repo,\n };\n}\n\nconst program = new Command();\n\nprogram\n .name(packageJson.name)\n .version(packageJson.version)\n .description(packageJson.description)\n .arguments('[target_dir]')\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('-n, --name <module_name>', 'Name of the native module.')\n .option('-d, --description <description>', 'Description of the module.')\n .option('-p, --package <package>', 'The Android package name.')\n .option('-a, --author <author>', 'The author name.')\n .option('-l, --license <license>', 'The license that the module is distributed with.')\n .option('-r, --repo <repo_url>', 'The URL to the repository.')\n .option('--with-readme', 'Whether to include README.md file.', false)\n .option('--with-changelog', 'Whether to include CHANGELOG.md file.', false)\n .action(main);\n\nprogram.parse(process.argv);\n"]}
|
|
1
|
+
{"version":3,"file":"create-expo-module.js","sourceRoot":"","sources":["../src/create-expo-module.ts"],"names":[],"mappings":"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","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 path from 'path';\nimport prompts, { PromptObject } from 'prompts';\n\nimport { PackageManagerName, resolvePackageManager } from './resolvePackageManager';\n\nconst packageJson = require('../package.json');\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 = ['.DS_Store', 'build', 'node_modules', 'package.json'];\n\n/**\n * Possible command options.\n */\ntype CommandOptions = {\n target: string;\n source?: string;\n name?: string;\n description?: string;\n package?: string;\n author?: string;\n license?: string;\n repo?: string;\n withReadme: boolean;\n withChangelog: boolean;\n};\n\n/**\n * Represents an object that is passed to `ejs` when rendering the template.\n */\ntype SubstitutionData = {\n project: {\n slug: string;\n name: string;\n version: string;\n description: string;\n package: string;\n };\n author: string;\n license: string;\n repo: string;\n};\n\ntype CustomPromptObject = PromptObject & {\n name: string;\n resolvedValue?: string | null;\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 targetDir = target ? path.join(CWD, target) : CWD;\n\n await confirmTargetDirAsync(targetDir);\n\n options.target = targetDir;\n await fs.ensureDir(targetDir);\n\n const data = await askForSubstitutionDataAsync(targetDir, options);\n const packageManager = await resolvePackageManager();\n const packagePath = options.source\n ? path.join(CWD, options.source)\n : await downloadPackageAsync(targetDir);\n const files = await getFilesAsync(packagePath);\n\n console.log('🎨 Creating Expo module from the template files...');\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('.', path.sep),\n });\n const fromPath = path.join(packagePath, file);\n const toPath = path.join(targetDir, 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 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\n // Install dependencies and build\n await postActionsAsync(packageManager, targetDir);\n\n console.log('✅ Successfully created Expo module');\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 const { stdout } = await spawnAsync('npm', ['view', `${packageName}@${version}`, 'dist.tarball']);\n return stdout.trim();\n}\n\n/**\n * Gets the username of currently logged in user. Used as a default in the prompt asking for the module author.\n */\nasync function npmWhoamiAsync(targetDir: string): Promise<string | null> {\n try {\n const { stdout } = await spawnAsync('npm', ['whoami'], { cwd: targetDir });\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\n/**\n * Downloads the template from NPM registry.\n */\nasync function downloadPackageAsync(targetDir: string): Promise<string> {\n const tarballUrl = await getNpmTarballUrl('expo-module-template');\n\n console.log('⬇️ Downloading module template from npm...');\n\n await downloadTarball({\n url: tarballUrl,\n dir: targetDir,\n });\n return path.join(targetDir, 'package');\n}\n\n/**\n * Installs dependencies and builds TypeScript files.\n */\nasync function postActionsAsync(packageManager: PackageManagerName, targetDir: string) {\n async function run(...args: string[]) {\n await spawnAsync(packageManager, args, {\n cwd: targetDir,\n stdio: 'ignore',\n });\n }\n\n console.log('📦 Installing dependencies...');\n await run('install');\n\n console.log('🛠 Compiling TypeScript files...');\n await run('run', 'build');\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 targetDir: string,\n options: CommandOptions\n): Promise<SubstitutionData> {\n const defaultPackageSlug = path.basename(targetDir);\n const defaultProjectName = defaultPackageSlug\n .replace(/^./, (match) => match.toUpperCase())\n .replace(/\\W+(\\w)/g, (_, p1) => p1.toUpperCase());\n\n const promptQueries: CustomPromptObject[] = [\n {\n type: 'text',\n name: 'slug',\n message: 'What is the package slug?',\n initial: defaultPackageSlug,\n resolvedValue: options.target ? defaultPackageSlug : null,\n },\n {\n type: 'text',\n name: 'name',\n message: 'What is the project name?',\n initial: defaultProjectName,\n },\n {\n type: 'text',\n name: 'description',\n message: 'How would you describe the module?',\n },\n {\n type: 'text',\n name: 'package',\n message: 'What is the Android package name?',\n initial: `expo.modules.${defaultPackageSlug.replace(/\\W/g, '').toLowerCase()}`,\n },\n {\n type: 'text',\n name: 'author',\n message: 'Who is the author?',\n initial: (await npmWhoamiAsync(targetDir)) ?? '',\n },\n {\n type: 'text',\n name: 'license',\n message: 'What is the license?',\n initial: 'MIT',\n },\n {\n type: 'text',\n name: 'repo',\n message: 'What is the repository URL?',\n },\n ];\n\n // Stop the process when the user cancels/exits the prompt.\n const onCancel = () => {\n process.exit(0);\n };\n\n const answers: Record<string, string> = {};\n for (const query of promptQueries) {\n const { name, resolvedValue } = query;\n answers[name] = resolvedValue ?? options[name] ?? (await prompts(query, { onCancel }))[name];\n }\n\n const { slug, name, description, package: projectPackage, author, license, repo } = answers;\n\n return {\n project: {\n slug,\n name,\n version: '0.1.0',\n description,\n package: projectPackage,\n },\n author,\n license,\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.\\nDo 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\nconst program = new Command();\n\nprogram\n .name(packageJson.name)\n .version(packageJson.version)\n .description(packageJson.description)\n .arguments('[target_dir]')\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('-n, --name <module_name>', 'Name of the native module.')\n .option('-d, --description <description>', 'Description of the module.')\n .option('-p, --package <package>', 'The Android package name.')\n .option('-a, --author <author>', 'The author name.')\n .option('-l, --license <license>', 'The license that the module is distributed with.')\n .option('-r, --repo <repo_url>', 'The URL to the repository.')\n .option('--with-readme', 'Whether to include README.md file.', false)\n .option('--with-changelog', 'Whether to include CHANGELOG.md file.', false)\n .action(main);\n\nprogram.parse(process.argv);\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvePackageManager = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
/** Determine which package manager to use for installing dependencies based on how the process was started. */
|
|
6
|
+
function resolvePackageManager() {
|
|
7
|
+
// Attempt to detect if the user started the command using `yarn` or `pnpm`
|
|
8
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
9
|
+
if (userAgent === null || userAgent === void 0 ? void 0 : userAgent.startsWith('yarn')) {
|
|
10
|
+
return 'yarn';
|
|
11
|
+
}
|
|
12
|
+
else if (userAgent === null || userAgent === void 0 ? void 0 : userAgent.startsWith('pnpm')) {
|
|
13
|
+
return 'pnpm';
|
|
14
|
+
}
|
|
15
|
+
else if (userAgent === null || userAgent === void 0 ? void 0 : userAgent.startsWith('npm')) {
|
|
16
|
+
return 'npm';
|
|
17
|
+
}
|
|
18
|
+
// Try availability
|
|
19
|
+
if (isPackageManagerAvailable('yarn')) {
|
|
20
|
+
return 'yarn';
|
|
21
|
+
}
|
|
22
|
+
else if (isPackageManagerAvailable('pnpm')) {
|
|
23
|
+
return 'pnpm';
|
|
24
|
+
}
|
|
25
|
+
return 'npm';
|
|
26
|
+
}
|
|
27
|
+
exports.resolvePackageManager = resolvePackageManager;
|
|
28
|
+
function isPackageManagerAvailable(manager) {
|
|
29
|
+
try {
|
|
30
|
+
(0, child_process_1.execSync)(`${manager} --version`, { stdio: 'ignore' });
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch { }
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=resolvePackageManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePackageManager.js","sourceRoot":"","sources":["../src/resolvePackageManager.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAIzC,+GAA+G;AAC/G,SAAgB,qBAAqB;IACnC,2EAA2E;IAC3E,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAEpD,IAAI,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,CAAC,MAAM,CAAC,EAAE;QACjC,OAAO,MAAM,CAAC;KACf;SAAM,IAAI,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,CAAC,MAAM,CAAC,EAAE;QACxC,OAAO,MAAM,CAAC;KACf;SAAM,IAAI,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,CAAC,KAAK,CAAC,EAAE;QACvC,OAAO,KAAK,CAAC;KACd;IAED,mBAAmB;IACnB,IAAI,yBAAyB,CAAC,MAAM,CAAC,EAAE;QACrC,OAAO,MAAM,CAAC;KACf;SAAM,IAAI,yBAAyB,CAAC,MAAM,CAAC,EAAE;QAC5C,OAAO,MAAM,CAAC;KACf;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AApBD,sDAoBC;AAED,SAAS,yBAAyB,CAAC,OAA2B;IAC5D,IAAI;QACF,IAAA,wBAAQ,EAAC,GAAG,OAAO,YAAY,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;KACb;IAAC,MAAM,GAAE;IACV,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { execSync } from 'child_process';\n\nexport type PackageManagerName = 'npm' | 'pnpm' | 'yarn';\n\n/** Determine which package manager to use for installing dependencies based on how the process was started. */\nexport function resolvePackageManager(): PackageManagerName {\n // Attempt to detect if the user started the command using `yarn` or `pnpm`\n const userAgent = process.env.npm_config_user_agent;\n\n if (userAgent?.startsWith('yarn')) {\n return 'yarn';\n } else if (userAgent?.startsWith('pnpm')) {\n return 'pnpm';\n } else if (userAgent?.startsWith('npm')) {\n return 'npm';\n }\n\n // Try availability\n if (isPackageManagerAvailable('yarn')) {\n return 'yarn';\n } else if (isPackageManagerAvailable('pnpm')) {\n return 'pnpm';\n }\n\n return 'npm';\n}\n\nfunction isPackageManagerAvailable(manager: PackageManagerName): boolean {\n try {\n execSync(`${manager} --version`, { stdio: 'ignore' });\n return true;\n } catch {}\n return false;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-expo-module",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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",
|
|
@@ -34,9 +34,10 @@
|
|
|
34
34
|
"homepage": "https://github.com/expo/expo/tree/main/packages/expo",
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@expo/spawn-async": "^1.5.0",
|
|
37
|
+
"chalk": "^4.1.2",
|
|
37
38
|
"commander": "^8.3.0",
|
|
38
39
|
"download-tarball": "^2.0.0",
|
|
39
|
-
"ejs": "^3.1.
|
|
40
|
+
"ejs": "^3.1.7",
|
|
40
41
|
"fs-extra": "^10.0.0",
|
|
41
42
|
"prompts": "^2.4.2"
|
|
42
43
|
},
|
|
@@ -45,5 +46,5 @@
|
|
|
45
46
|
"@types/prompts": "^2.0.14",
|
|
46
47
|
"expo-module-scripts": "^2.0.0"
|
|
47
48
|
},
|
|
48
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "5e7c69008fe51f86e96877116602ef1a50a4655f"
|
|
49
50
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import spawnAsync from '@expo/spawn-async';
|
|
2
|
+
import chalk from 'chalk';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
import downloadTarball from 'download-tarball';
|
|
4
5
|
import ejs from 'ejs';
|
|
@@ -6,6 +7,8 @@ import fs from 'fs-extra';
|
|
|
6
7
|
import path from 'path';
|
|
7
8
|
import prompts, { PromptObject } from 'prompts';
|
|
8
9
|
|
|
10
|
+
import { PackageManagerName, resolvePackageManager } from './resolvePackageManager';
|
|
11
|
+
|
|
9
12
|
const packageJson = require('../package.json');
|
|
10
13
|
|
|
11
14
|
// `yarn run` may change the current working dir, then we should use `INIT_CWD` env.
|
|
@@ -52,8 +55,6 @@ type CustomPromptObject = PromptObject & {
|
|
|
52
55
|
resolvedValue?: string | null;
|
|
53
56
|
};
|
|
54
57
|
|
|
55
|
-
type PackageManager = 'npm' | 'yarn';
|
|
56
|
-
|
|
57
58
|
/**
|
|
58
59
|
* The main function of the command.
|
|
59
60
|
*
|
|
@@ -63,11 +64,13 @@ type PackageManager = 'npm' | 'yarn';
|
|
|
63
64
|
async function main(target: string | undefined, options: CommandOptions) {
|
|
64
65
|
const targetDir = target ? path.join(CWD, target) : CWD;
|
|
65
66
|
|
|
67
|
+
await confirmTargetDirAsync(targetDir);
|
|
68
|
+
|
|
66
69
|
options.target = targetDir;
|
|
67
70
|
await fs.ensureDir(targetDir);
|
|
68
71
|
|
|
69
72
|
const data = await askForSubstitutionDataAsync(targetDir, options);
|
|
70
|
-
const packageManager = await
|
|
73
|
+
const packageManager = await resolvePackageManager();
|
|
71
74
|
const packagePath = options.source
|
|
72
75
|
? path.join(CWD, options.source)
|
|
73
76
|
: await downloadPackageAsync(targetDir);
|
|
@@ -169,26 +172,10 @@ async function downloadPackageAsync(targetDir: string): Promise<string> {
|
|
|
169
172
|
return path.join(targetDir, 'package');
|
|
170
173
|
}
|
|
171
174
|
|
|
172
|
-
/**
|
|
173
|
-
* Asks whether to use Yarn or npm as a dependency package manager.
|
|
174
|
-
*/
|
|
175
|
-
async function selectPackageManagerAsync(): Promise<PackageManager> {
|
|
176
|
-
const { packageManager } = await prompts({
|
|
177
|
-
type: 'select',
|
|
178
|
-
name: 'packageManager',
|
|
179
|
-
message: 'Which package manager do you want to use to install dependencies?',
|
|
180
|
-
choices: [
|
|
181
|
-
{ title: 'yarn', value: 'yarn' },
|
|
182
|
-
{ title: 'npm', value: 'npm' },
|
|
183
|
-
],
|
|
184
|
-
});
|
|
185
|
-
return packageManager;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
175
|
/**
|
|
189
176
|
* Installs dependencies and builds TypeScript files.
|
|
190
177
|
*/
|
|
191
|
-
async function postActionsAsync(packageManager:
|
|
178
|
+
async function postActionsAsync(packageManager: PackageManagerName, targetDir: string) {
|
|
192
179
|
async function run(...args: string[]) {
|
|
193
180
|
await spawnAsync(packageManager, args, {
|
|
194
181
|
cwd: targetDir,
|
|
@@ -260,10 +247,15 @@ async function askForSubstitutionDataAsync(
|
|
|
260
247
|
},
|
|
261
248
|
];
|
|
262
249
|
|
|
250
|
+
// Stop the process when the user cancels/exits the prompt.
|
|
251
|
+
const onCancel = () => {
|
|
252
|
+
process.exit(0);
|
|
253
|
+
};
|
|
254
|
+
|
|
263
255
|
const answers: Record<string, string> = {};
|
|
264
256
|
for (const query of promptQueries) {
|
|
265
257
|
const { name, resolvedValue } = query;
|
|
266
|
-
answers[name] = resolvedValue ?? options[name] ?? (await prompts(query))[name];
|
|
258
|
+
answers[name] = resolvedValue ?? options[name] ?? (await prompts(query, { onCancel }))[name];
|
|
267
259
|
}
|
|
268
260
|
|
|
269
261
|
const { slug, name, description, package: projectPackage, author, license, repo } = answers;
|
|
@@ -282,6 +274,33 @@ async function askForSubstitutionDataAsync(
|
|
|
282
274
|
};
|
|
283
275
|
}
|
|
284
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Checks whether the target directory is empty and if not, asks the user to confirm if he wants to continue.
|
|
279
|
+
*/
|
|
280
|
+
async function confirmTargetDirAsync(targetDir: string): Promise<void> {
|
|
281
|
+
const files = await fs.readdir(targetDir);
|
|
282
|
+
|
|
283
|
+
if (files.length === 0) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const { shouldContinue } = await prompts(
|
|
287
|
+
{
|
|
288
|
+
type: 'confirm',
|
|
289
|
+
name: 'shouldContinue',
|
|
290
|
+
message: `The target directory ${chalk.magenta(
|
|
291
|
+
targetDir
|
|
292
|
+
)} is not empty.\nDo you want to continue anyway?`,
|
|
293
|
+
initial: true,
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
onCancel: () => false,
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
if (!shouldContinue) {
|
|
300
|
+
process.exit(0);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
285
304
|
const program = new Command();
|
|
286
305
|
|
|
287
306
|
program
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
|
|
3
|
+
export type PackageManagerName = 'npm' | 'pnpm' | 'yarn';
|
|
4
|
+
|
|
5
|
+
/** Determine which package manager to use for installing dependencies based on how the process was started. */
|
|
6
|
+
export function resolvePackageManager(): PackageManagerName {
|
|
7
|
+
// Attempt to detect if the user started the command using `yarn` or `pnpm`
|
|
8
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
9
|
+
|
|
10
|
+
if (userAgent?.startsWith('yarn')) {
|
|
11
|
+
return 'yarn';
|
|
12
|
+
} else if (userAgent?.startsWith('pnpm')) {
|
|
13
|
+
return 'pnpm';
|
|
14
|
+
} else if (userAgent?.startsWith('npm')) {
|
|
15
|
+
return 'npm';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Try availability
|
|
19
|
+
if (isPackageManagerAvailable('yarn')) {
|
|
20
|
+
return 'yarn';
|
|
21
|
+
} else if (isPackageManagerAvailable('pnpm')) {
|
|
22
|
+
return 'pnpm';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return 'npm';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isPackageManagerAvailable(manager: PackageManagerName): boolean {
|
|
29
|
+
try {
|
|
30
|
+
execSync(`${manager} --version`, { stdio: 'ignore' });
|
|
31
|
+
return true;
|
|
32
|
+
} catch {}
|
|
33
|
+
return false;
|
|
34
|
+
}
|