1 | "use strict";
|
2 |
|
3 | var _path = _interopRequireDefault(require("path"));
|
4 |
|
5 | var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
6 |
|
7 | var _chalk = _interopRequireDefault(require("chalk"));
|
8 |
|
9 | var _dedent = _interopRequireDefault(require("dedent"));
|
10 |
|
11 | var _yargs = _interopRequireDefault(require("yargs"));
|
12 |
|
13 | var _cosmiconfig = require("cosmiconfig");
|
14 |
|
15 | var _isGitDirty = _interopRequireDefault(require("is-git-dirty"));
|
16 |
|
17 | var _create = _interopRequireWildcard(require("./create"));
|
18 |
|
19 | var _prompts = _interopRequireDefault(require("./utils/prompts"));
|
20 |
|
21 | var logger = _interopRequireWildcard(require("./utils/logger"));
|
22 |
|
23 | var _aar = _interopRequireDefault(require("./targets/aar"));
|
24 |
|
25 | var _commonjs = _interopRequireDefault(require("./targets/commonjs"));
|
26 |
|
27 | var _module = _interopRequireDefault(require("./targets/module"));
|
28 |
|
29 | var _typescript = _interopRequireDefault(require("./targets/typescript"));
|
30 |
|
31 | function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
32 |
|
33 | function _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 |
|
35 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
36 |
|
37 |
|
38 | const {
|
39 | name,
|
40 | version
|
41 | } = require('../package.json');
|
42 |
|
43 | const root = process.cwd();
|
44 | const explorer = (0, _cosmiconfig.cosmiconfigSync)(name, {
|
45 | searchPlaces: ['package.json', `bob.config.js`]
|
46 | });
|
47 | const FLOW_PRGAMA_REGEX = /\*?\s*@(flow)\b/m;
|
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 |
|
\ | No newline at end of file |