1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.default = create;
|
7 | exports.args = void 0;
|
8 |
|
9 | var _path = _interopRequireDefault(require("path"));
|
10 |
|
11 | var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
12 |
|
13 | var _ejs = _interopRequireDefault(require("ejs"));
|
14 |
|
15 | var _dedent = _interopRequireDefault(require("dedent"));
|
16 |
|
17 | var _chalk = _interopRequireDefault(require("chalk"));
|
18 |
|
19 | var _crossSpawn = _interopRequireDefault(require("cross-spawn"));
|
20 |
|
21 | var _validateNpmPackageName = _interopRequireDefault(require("validate-npm-package-name"));
|
22 |
|
23 | var _githubUsername = _interopRequireDefault(require("github-username"));
|
24 |
|
25 | var _prompts = _interopRequireDefault(require("./utils/prompts"));
|
26 |
|
27 | var _package = _interopRequireDefault(require("../package.json"));
|
28 |
|
29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
30 |
|
31 | const BINARIES = /(gradlew|\.(jar|keystore|png|jpg|gif))$/;
|
32 |
|
33 | const COMMON_FILES = _path.default.resolve(__dirname, '../templates/common');
|
34 |
|
35 | const JS_FILES = _path.default.resolve(__dirname, '../templates/js-library');
|
36 |
|
37 | const EXPO_FILES = _path.default.resolve(__dirname, '../templates/expo-library');
|
38 |
|
39 | const CPP_FILES = _path.default.resolve(__dirname, '../templates/cpp-library');
|
40 |
|
41 | const EXAMPLE_FILES = _path.default.resolve(__dirname, '../templates/example');
|
42 |
|
43 |
|
44 | const NATIVE_FILES = moduleType => {
|
45 | switch (moduleType) {
|
46 | case 'module':
|
47 | return _path.default.resolve(__dirname, '../templates/native-library');
|
48 |
|
49 | case 'view':
|
50 | return _path.default.resolve(__dirname, '../templates/native-view-library');
|
51 | }
|
52 | };
|
53 |
|
54 |
|
55 | const OBJC_FILES = moduleType => {
|
56 | switch (moduleType) {
|
57 | case 'module':
|
58 | return _path.default.resolve(__dirname, '../templates/objc-library');
|
59 |
|
60 | case 'view':
|
61 | return _path.default.resolve(__dirname, '../templates/objc-view-library');
|
62 | }
|
63 | };
|
64 |
|
65 |
|
66 | const SWIFT_FILES = moduleType => {
|
67 | switch (moduleType) {
|
68 | case 'module':
|
69 | return _path.default.resolve(__dirname, '../templates/swift-library');
|
70 |
|
71 | case 'view':
|
72 | return _path.default.resolve(__dirname, '../templates/swift-view-library');
|
73 | }
|
74 | };
|
75 |
|
76 | const args = {
|
77 | 'slug': {
|
78 | description: 'Name of the npm package',
|
79 | type: 'string'
|
80 | },
|
81 | 'description': {
|
82 | description: 'Description of the npm package',
|
83 | type: 'string'
|
84 | },
|
85 | 'author-name': {
|
86 | description: 'Name of the package author',
|
87 | type: 'string'
|
88 | },
|
89 | 'author-email': {
|
90 | description: 'Email address of the package author',
|
91 | type: 'string'
|
92 | },
|
93 | 'author-url': {
|
94 | description: 'URL for the package author',
|
95 | type: 'string'
|
96 | },
|
97 | 'repo-url': {
|
98 | description: 'URL for the repository',
|
99 | type: 'string'
|
100 | },
|
101 | 'type': {
|
102 | description: 'Type package do you want to develop',
|
103 | choices: ['native', 'native-swift', 'js', 'cpp', 'expo']
|
104 | }
|
105 | };
|
106 | exports.args = args;
|
107 |
|
108 | async function create(argv) {
|
109 | const folder = _path.default.join(process.cwd(), argv.name);
|
110 |
|
111 | if (await _fsExtra.default.pathExists(folder)) {
|
112 | console.log(`A folder already exists at ${_chalk.default.blue(folder)}! Please specify another folder name or delete the existing one.`);
|
113 | process.exit(1);
|
114 | }
|
115 |
|
116 | let name, email;
|
117 |
|
118 | try {
|
119 | name = _crossSpawn.default.sync('git', ['config', '--get', 'user.name']).stdout.toString().trim();
|
120 | email = _crossSpawn.default.sync('git', ['config', '--get', 'user.email']).stdout.toString().trim();
|
121 | } catch (e) {
|
122 | }
|
123 |
|
124 | const basename = _path.default.basename(argv.name);
|
125 |
|
126 | const questions = {
|
127 | 'slug': {
|
128 | type: 'text',
|
129 | name: 'slug',
|
130 | message: 'What is the name of the npm package?',
|
131 | initial: (0, _validateNpmPackageName.default)(basename).validForNewPackages ? /^(@|react-native)/.test(basename) ? basename : `react-native-${basename}` : undefined,
|
132 | validate: input => (0, _validateNpmPackageName.default)(input).validForNewPackages || 'Must be a valid npm package name'
|
133 | },
|
134 | 'description': {
|
135 | type: 'text',
|
136 | name: 'description',
|
137 | message: 'What is the description for the package?',
|
138 | validate: input => Boolean(input) || 'Cannot be empty'
|
139 | },
|
140 | 'author-name': {
|
141 | type: 'text',
|
142 | name: 'authorName',
|
143 | message: 'What is the name of package author?',
|
144 | initial: name,
|
145 | validate: input => Boolean(input) || 'Cannot be empty'
|
146 | },
|
147 | 'author-email': {
|
148 | type: 'text',
|
149 | name: 'authorEmail',
|
150 | message: 'What is the email address for the package author?',
|
151 | initial: email,
|
152 | validate: input => /^\S+@\S+$/.test(input) || 'Must be a valid email address'
|
153 | },
|
154 | 'author-url': {
|
155 | type: 'text',
|
156 | name: 'authorUrl',
|
157 | message: 'What is the URL for the package author?',
|
158 |
|
159 | initial: async previous => {
|
160 | try {
|
161 | const username = await (0, _githubUsername.default)(previous);
|
162 | return `https://github.com/${username}`;
|
163 | } catch (e) {
|
164 | }
|
165 |
|
166 | return undefined;
|
167 | },
|
168 | validate: input => /^https?:\/\//.test(input) || 'Must be a valid URL'
|
169 | },
|
170 | 'repo-url': {
|
171 | type: 'text',
|
172 | name: 'repoUrl',
|
173 | message: 'What is the URL for the repository?',
|
174 |
|
175 | initial: (_, answers) => {
|
176 | if (/^https?:\/\/github.com\/[^/]+/.test(answers.authorUrl)) {
|
177 | return `${answers.authorUrl}/${answers.slug.replace(/^@/, '').replace(/\//g, '-')}`;
|
178 | }
|
179 |
|
180 | return '';
|
181 | },
|
182 | validate: input => /^https?:\/\//.test(input) || 'Must be a valid URL'
|
183 | },
|
184 | 'type': {
|
185 | type: 'select',
|
186 | name: 'type',
|
187 | message: 'What type of package do you want to develop?',
|
188 | choices: [{
|
189 | title: 'Native module in Kotlin and Objective-C',
|
190 | value: 'native'
|
191 | }, {
|
192 | title: 'Native module in Kotlin and Swift',
|
193 | value: 'native-swift'
|
194 | }, {
|
195 | title: 'Native module with C++ code',
|
196 | value: 'cpp'
|
197 | }, {
|
198 | title: 'Native view in Kotlin and Objective-C',
|
199 | value: 'native-view'
|
200 | }, {
|
201 | title: 'Native view in Kotlin and Swift',
|
202 | value: 'native-view-swift'
|
203 | }, {
|
204 | title: 'JavaScript library with native example',
|
205 | value: 'js'
|
206 | }, {
|
207 | title: 'JavaScript library with Expo example and Web support',
|
208 | value: 'expo'
|
209 | }]
|
210 | }
|
211 | };
|
212 | const {
|
213 | slug,
|
214 | description,
|
215 | authorName,
|
216 | authorEmail,
|
217 | authorUrl,
|
218 | repoUrl,
|
219 | type
|
220 | } = { ...argv,
|
221 | ...(await (0, _prompts.default)(Object.entries(questions).filter(([k, v]) => !(argv[k] && v.validate ? v.validate(argv[k]) === true : Boolean(argv[k]))).map(([, v]) => v)))
|
222 | };
|
223 | const project = slug.replace(/^(react-native-|@[^/]+\/)/, '');
|
224 | const moduleType = type === 'native-view' || type === 'native-view-swift' ? 'view' : 'module';
|
225 | const options = {
|
226 | bob: {
|
227 | version: _package.default.version
|
228 | },
|
229 | project: {
|
230 | slug,
|
231 | description,
|
232 | name: `${project.charAt(0).toUpperCase()}${project.replace(/[^a-z0-9](\w)/g, (_, $1) => $1.toUpperCase()).slice(1)}`,
|
233 | package: slug.replace(/[^a-z0-9]/g, '').toLowerCase(),
|
234 | podspec: slug.replace(/[^a-z0-9]+/g, '-').replace(/^-/, ''),
|
235 | native: type === 'native' || type === 'cpp' || 'native-swift' || 'native-view' || 'native-view-swift',
|
236 | cpp: type === 'cpp',
|
237 | swift: type === 'native-swift' || 'native-view-swift',
|
238 | module: type !== 'js',
|
239 | moduleType
|
240 | },
|
241 | author: {
|
242 | name: authorName,
|
243 | email: authorEmail,
|
244 | url: authorUrl
|
245 | },
|
246 | repo: repoUrl
|
247 | };
|
248 |
|
249 | const copyDir = async (source, dest) => {
|
250 | await _fsExtra.default.mkdirp(dest);
|
251 | const files = await _fsExtra.default.readdir(source);
|
252 |
|
253 | for (const f of files) {
|
254 | const target = _path.default.join(dest, _ejs.default.render(f.replace(/^\$/, ''), options, {
|
255 | openDelimiter: '{',
|
256 | closeDelimiter: '}'
|
257 | }));
|
258 |
|
259 | const file = _path.default.join(source, f);
|
260 |
|
261 | const stats = await _fsExtra.default.stat(file);
|
262 |
|
263 | if (stats.isDirectory()) {
|
264 | await copyDir(file, target);
|
265 | } else if (!file.match(BINARIES)) {
|
266 | const content = await _fsExtra.default.readFile(file, 'utf8');
|
267 | await _fsExtra.default.writeFile(target, _ejs.default.render(content, options));
|
268 | } else {
|
269 | await _fsExtra.default.copyFile(file, target);
|
270 | }
|
271 | }
|
272 | };
|
273 |
|
274 | await copyDir(COMMON_FILES, folder);
|
275 |
|
276 | if (type === 'expo') {
|
277 | await copyDir(JS_FILES, folder);
|
278 | await copyDir(EXPO_FILES, folder);
|
279 | } else if (type === 'js') {
|
280 | await copyDir(JS_FILES, folder);
|
281 | await copyDir(_path.default.join(EXAMPLE_FILES, 'example'), _path.default.join(folder, 'example'));
|
282 | } else {
|
283 | await copyDir(_path.default.join(EXAMPLE_FILES, 'example'), _path.default.join(folder, 'example'));
|
284 | await copyDir(NATIVE_FILES(moduleType), folder);
|
285 |
|
286 | if (type === 'cpp') {
|
287 | await copyDir(CPP_FILES, folder);
|
288 | } else if (type === 'native-swift') {
|
289 | await copyDir(SWIFT_FILES(moduleType), folder);
|
290 | } else {
|
291 | await copyDir(OBJC_FILES(moduleType), folder);
|
292 | }
|
293 | }
|
294 |
|
295 | try {
|
296 | _crossSpawn.default.sync('git', ['init'], {
|
297 | cwd: folder
|
298 | });
|
299 |
|
300 | _crossSpawn.default.sync('git', ['add', '.'], {
|
301 | cwd: folder
|
302 | });
|
303 |
|
304 | _crossSpawn.default.sync('git', ['commit', '-m', 'chore: initial commit'], {
|
305 | cwd: folder
|
306 | });
|
307 | } catch (e) {
|
308 | }
|
309 |
|
310 | const platforms = {
|
311 | ios: {
|
312 | name: 'iOS',
|
313 | color: 'cyan'
|
314 | },
|
315 | android: {
|
316 | name: 'Android',
|
317 | color: 'green'
|
318 | },
|
319 | ...(type === 'expo' ? {
|
320 | web: {
|
321 | name: 'Web',
|
322 | color: 'blue'
|
323 | }
|
324 | } : null)
|
325 | };
|
326 | console.log((0, _dedent.default)((0, _chalk.default)`
|
327 | Project created successfully at {yellow ${argv.name}}!
|
328 |
|
329 | {magenta {bold Get started} with the project}{gray :}
|
330 |
|
331 | {gray $} yarn
|
332 | ${Object.entries(platforms).map(([script, {
|
333 | name,
|
334 | color
|
335 | }]) => (0, _chalk.default)`
|
336 | {${color} Run the example app on {bold ${name}}}{gray :}
|
337 |
|
338 | {gray $} yarn example ${script}`).join('\n')}
|
339 |
|
340 | {yellow Good luck!}
|
341 | `));
|
342 | }
|
343 |
|
\ | No newline at end of file |