UNPKG

12.9 kBJavaScriptView Raw
1"use strict";
2
3var _path = _interopRequireDefault(require("path"));
4
5var _fsExtra = _interopRequireDefault(require("fs-extra"));
6
7var _chalk = _interopRequireDefault(require("chalk"));
8
9var _dedent = _interopRequireDefault(require("dedent"));
10
11var _yargs = _interopRequireDefault(require("yargs"));
12
13var _cosmiconfig = require("cosmiconfig");
14
15var _isGitDirty = _interopRequireDefault(require("is-git-dirty"));
16
17var _create = _interopRequireWildcard(require("./create"));
18
19var _prompts = _interopRequireDefault(require("./utils/prompts"));
20
21var logger = _interopRequireWildcard(require("./utils/logger"));
22
23var _aar = _interopRequireDefault(require("./targets/aar"));
24
25var _commonjs = _interopRequireDefault(require("./targets/commonjs"));
26
27var _module = _interopRequireDefault(require("./targets/module"));
28
29var _typescript = _interopRequireDefault(require("./targets/typescript"));
30
31function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
32
33function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
34
35function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
36
37// eslint-disable-next-line import/no-commonjs
38const {
39 name,
40 version
41} = require('../package.json');
42
43const root = process.cwd();
44const explorer = (0, _cosmiconfig.cosmiconfigSync)(name, {
45 searchPlaces: ['package.json', `bob.config.js`]
46});
47const FLOW_PRGAMA_REGEX = /\*?\s*@(flow)\b/m; // eslint-disable-next-line babel/no-unused-expressions
48
49_yargs.default.command('create <name>', 'create a react native library', _create.args, _create.default).command('init', 'configure the package to use bob', {}, async () => {
50 var _pkg$scripts;
51
52 const pak = _path.default.join(root, 'package.json');
53
54 if ((0, _isGitDirty.default)()) {
55 const {
56 shouldContinue
57 } = await (0, _prompts.default)({
58 type: 'confirm',
59 name: 'shouldContinue',
60 message: `The working directory is not clean. You should commit or stash your changes before configuring bob. Continue anyway?`,
61 initial: false
62 });
63
64 if (!shouldContinue) {
65 process.exit(1);
66 }
67 }
68
69 if (!(await _fsExtra.default.pathExists(pak))) {
70 logger.exit(`Couldn't find a 'package.json' file in '${root}'. Are you in a project folder?`);
71 }
72
73 const {
74 source
75 } = await (0, _prompts.default)({
76 type: 'text',
77 name: 'source',
78 message: 'Where are your source files?',
79 initial: 'src',
80 validate: input => Boolean(input)
81 });
82 let entryFile;
83
84 if (await _fsExtra.default.pathExists(_path.default.join(root, source, 'index.js'))) {
85 entryFile = 'index.js';
86 } else if (await _fsExtra.default.pathExists(_path.default.join(root, source, 'index.ts'))) {
87 entryFile = 'index.ts';
88 } else if (await _fsExtra.default.pathExists(_path.default.join(root, source, 'index.tsx'))) {
89 entryFile = 'index.tsx';
90 }
91
92 if (!entryFile) {
93 logger.exit(`Couldn't find a 'index.js'. 'index.ts' or 'index.tsx' file under '${source}'. Please re-run the CLI after creating it.`);
94 return;
95 }
96
97 const pkg = JSON.parse(await _fsExtra.default.readFile(pak, 'utf-8'));
98 pkg.devDependencies = Object.fromEntries([...Object.entries(pkg.devDependencies || {}), [name, `^${version}`]].sort(([a], [b]) => a.localeCompare(b)));
99 const questions = [{
100 type: 'text',
101 name: 'output',
102 message: 'Where do you want to generate the output files?',
103 initial: 'lib',
104 validate: input => Boolean(input)
105 }, {
106 type: 'multiselect',
107 name: 'targets',
108 message: 'Which targets do you want to build?',
109 choices: [{
110 title: 'commonjs - for running in Node (tests, SSR etc.)',
111 value: 'commonjs',
112 selected: true
113 }, {
114 title: 'module - for bundlers (metro, webpack etc.)',
115 value: 'module',
116 selected: true
117 }, {
118 title: 'typescript - declaration files for typechecking',
119 value: 'typescript',
120 selected: /\.tsx?$/.test(entryFile)
121 }, {
122 title: 'aar - bundle android code to a binary',
123 value: 'aar',
124 selected: false
125 }],
126 validate: input => Boolean(input.length)
127 }];
128
129 if (entryFile.endsWith('.js') && FLOW_PRGAMA_REGEX.test(await _fsExtra.default.readFile(_path.default.join(root, source, entryFile), 'utf-8'))) {
130 questions.push({
131 type: 'confirm',
132 name: 'flow',
133 message: 'Do you want to publish definitions for flow?',
134 initial: Object.keys(pkg.devDependencies || {}).includes('flow-bin')
135 });
136 }
137
138 const {
139 output,
140 targets,
141 flow
142 } = await (0, _prompts.default)(questions);
143 const target = targets[0] === 'commonjs' || targets[0] === 'module' ? targets[0] : undefined;
144 const entries = {
145 'main': target ? _path.default.join(output, target, 'index.js') : _path.default.join(source, entryFile),
146 'react-native': _path.default.join(source, entryFile)
147 };
148
149 if (targets.includes('module')) {
150 entries.module = _path.default.join(output, 'module', 'index.js');
151 }
152
153 if (targets.includes('typescript')) {
154 entries.types = _path.default.join(output, 'typescript', source, 'index.d.ts');
155
156 if (!(await _fsExtra.default.pathExists(_path.default.join(root, 'tsconfig.json')))) {
157 const {
158 tsconfig
159 } = await (0, _prompts.default)({
160 type: 'confirm',
161 name: 'tsconfig',
162 message: `You have enabled 'typescript' compilation, but we couldn't find a 'tsconfig.json' in project root. Generate one?`,
163 initial: true
164 });
165
166 if (tsconfig) {
167 await _fsExtra.default.writeFile(_path.default.join(root, 'tsconfig.json'), JSON.stringify({
168 compilerOptions: {
169 allowUnreachableCode: false,
170 allowUnusedLabels: false,
171 esModuleInterop: true,
172 forceConsistentCasingInFileNames: true,
173 jsx: 'react',
174 lib: ['esnext'],
175 module: 'esnext',
176 moduleResolution: 'node',
177 noFallthroughCasesInSwitch: true,
178 noImplicitReturns: true,
179 noImplicitUseStrict: false,
180 noStrictGenericChecks: false,
181 noUnusedLocals: true,
182 noUnusedParameters: true,
183 resolveJsonModule: true,
184 skipLibCheck: true,
185 strict: true,
186 target: 'esnext'
187 }
188 }, null, 2));
189 }
190 }
191 }
192
193 const prepare = 'bob build';
194 const files = [source, output, '!**/__tests__', '!**/__fixtures__', '!**/__mocks__'];
195
196 for (const key in entries) {
197 const entry = entries[key];
198
199 if (pkg[key] && pkg[key] !== entry) {
200 const {
201 replace
202 } = await (0, _prompts.default)({
203 type: 'confirm',
204 name: 'replace',
205 message: `Your package.json has the '${key}' field set to '${pkg[key]}'. Do you want to replace it with '${entry}'?`,
206 initial: true
207 });
208
209 if (replace) {
210 pkg[key] = entry;
211 }
212 } else {
213 pkg[key] = entry;
214 }
215 }
216
217 if ((_pkg$scripts = pkg.scripts) !== null && _pkg$scripts !== void 0 && _pkg$scripts.prepare && pkg.scripts.prepare !== prepare) {
218 const {
219 replace
220 } = await (0, _prompts.default)({
221 type: 'confirm',
222 name: 'replace',
223 message: `Your package.json has the 'scripts.prepare' field set to '${pkg.scripts.prepare}'. Do you want to replace it with '${prepare}'?`,
224 initial: true
225 });
226
227 if (replace) {
228 pkg.scripts.prepare = prepare;
229 }
230 } else {
231 pkg.scripts = pkg.scripts || {};
232 pkg.scripts.prepare = prepare;
233 }
234
235 if (pkg.files && JSON.stringify(pkg.files.slice().sort()) !== JSON.stringify(files.slice().sort())) {
236 const {
237 update
238 } = await (0, _prompts.default)({
239 type: 'confirm',
240 name: 'update',
241 message: `Your package.json already has a 'files' field. Do you want to update it?`,
242 initial: true
243 });
244
245 if (update) {
246 pkg.files = [...files, ...pkg.files.filter(file => !files.includes(file.replace(/\/$/g, '')))];
247 }
248 } else {
249 pkg.files = files;
250 }
251
252 pkg[name] = {
253 source,
254 output,
255 targets: targets.map(t => {
256 if (t === target && flow) {
257 return [t, {
258 flow
259 }];
260 }
261
262 return t;
263 })
264 };
265
266 if (pkg.jest) {
267 const entry = `<rootDir>/${output}/`;
268
269 if (pkg.jest.modulePathIgnorePatterns) {
270 const {
271 modulePathIgnorePatterns
272 } = pkg.jest;
273
274 if (!modulePathIgnorePatterns.includes(entry)) {
275 modulePathIgnorePatterns.push(entry);
276 }
277 } else {
278 pkg.jest.modulePathIgnorePatterns = [entry];
279 }
280 }
281
282 pkg.eslintIgnore = pkg.eslintIgnore || ['node_modules/'];
283
284 if (!pkg.eslintIgnore.includes(`${output}/`)) {
285 pkg.eslintIgnore.push(`${output}/`);
286 }
287
288 await _fsExtra.default.writeFile(pak, JSON.stringify(pkg, null, 2));
289 const ignorefiles = [_path.default.join(root, '.gitignore'), _path.default.join(root, '.eslintignore')];
290
291 for (const ignorefile of ignorefiles) {
292 if (await _fsExtra.default.pathExists(ignorefile)) {
293 const content = await _fsExtra.default.readFile(ignorefile, 'utf-8');
294
295 if (!content.split('\n').includes(`${output}/`)) {
296 await _fsExtra.default.writeFile(ignorefile, `${content}\n# generated by bob\n${output}/\n`);
297 }
298 }
299 }
300
301 console.log((0, _dedent.default)((0, _chalk.default)`
302 Project {yellow ${pkg.name}} configured successfully!
303
304 {magenta {bold Perform last steps} by running}{gray :}
305
306 {gray $} yarn
307
308 {yellow Good luck!}
309 `));
310}).command('build', 'build files for publishing', {}, async argv => {
311 var _options$targets;
312
313 const result = explorer.search();
314
315 if (!(result !== null && result !== void 0 && result.config)) {
316 logger.exit(`No configuration found. Run '${argv.$0} init' to create one automatically.`);
317 }
318
319 const options = result.config;
320
321 if (!((_options$targets = options.targets) !== null && _options$targets !== void 0 && _options$targets.length)) {
322 logger.exit(`No targets found in the configuration in '${_path.default.relative(root, result.filepath)}'.`);
323 }
324
325 const source = options.source;
326
327 if (!source) {
328 logger.exit(`No source option found in the configuration in '${_path.default.relative(root, result.filepath)}'.`);
329 }
330
331 const output = options.output;
332
333 if (!output) {
334 logger.exit(`No source option found in the configuration in '${_path.default.relative(root, result.filepath)}'.`);
335 }
336
337 const report = {
338 info: logger.info,
339 warn: logger.warn,
340 error: logger.error,
341 success: logger.success
342 };
343
344 for (const target of options.targets) {
345 const targetName = Array.isArray(target) ? target[0] : target;
346 const targetOptions = Array.isArray(target) ? target[1] : undefined;
347 report.info(`Building target ${_chalk.default.blue(targetName)}`);
348
349 switch (targetName) {
350 case 'aar':
351 await (0, _aar.default)({
352 root,
353 source: _path.default.resolve(root, source),
354 output: _path.default.resolve(root, output, 'aar'),
355 options: targetOptions,
356 report
357 });
358 break;
359
360 case 'commonjs':
361 await (0, _commonjs.default)({
362 root,
363 source: _path.default.resolve(root, source),
364 output: _path.default.resolve(root, output, 'commonjs'),
365 options: targetOptions,
366 report
367 });
368 break;
369
370 case 'module':
371 await (0, _module.default)({
372 root,
373 source: _path.default.resolve(root, source),
374 output: _path.default.resolve(root, output, 'module'),
375 options: targetOptions,
376 report
377 });
378 break;
379
380 case 'typescript':
381 await (0, _typescript.default)({
382 root,
383 source: _path.default.resolve(root, source),
384 output: _path.default.resolve(root, output, 'typescript'),
385 options: targetOptions,
386 report
387 });
388 break;
389
390 default:
391 logger.exit(`Invalid target ${_chalk.default.blue(targetName)}.`);
392 }
393 }
394}).demandCommand().recommendCommands().strict().argv;
395//# sourceMappingURL=cli.js.map
\No newline at end of file