UNPKG

react-native-builder-bob

Version:

CLI to build JavaScript files for React Native libraries

215 lines (214 loc) 10.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = build; var _del = _interopRequireDefault(require("del")); var _fsExtra = _interopRequireDefault(require("fs-extra")); var _json = _interopRequireDefault(require("json5")); var _kleur = _interopRequireDefault(require("kleur")); var _os = require("os"); var _path = _interopRequireDefault(require("path")); var _which = _interopRequireDefault(require("which")); var _spawn = require("../utils/spawn"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } async function build({ source, root, output, report, options, variants, esm }) { report.info(`Cleaning up previous build at ${_kleur.default.blue(_path.default.relative(root, output))}`); await (0, _del.default)([output]); report.info(`Generating type definitions with ${_kleur.default.blue('tsc')}`); const project = options?.project ? options.project : 'tsconfig.json'; const tsconfig = _path.default.join(root, project); try { if (await _fsExtra.default.pathExists(tsconfig)) { try { const config = _json.default.parse(await _fsExtra.default.readFile(tsconfig, 'utf-8')); if (config.compilerOptions) { const conflicts = []; if (config.compilerOptions.declarationDir) { conflicts.push('compilerOptions.declarationDir'); } if (config.compilerOptions.outDir && _path.default.join(root, config.compilerOptions.outDir) !== output) { conflicts.push('compilerOptions.outDir'); } if (conflicts.length) { report.warn(`Found following options in the config file which can conflict with the CLI options. Please remove them from ${_kleur.default.blue(project)}:${conflicts.reduce((acc, curr) => acc + `\n${_kleur.default.gray('-')} ${_kleur.default.yellow(curr)}`, '')}`); } } } catch (e) { report.warn(`Couldn't parse ${_kleur.default.blue(project)}. There might be validation errors.`); } } else { throw new Error(`Couldn't find a ${_kleur.default.blue(project)} in the project root.`); } let tsc; if (options?.tsc) { tsc = _path.default.resolve(root, options.tsc); if (!(await _fsExtra.default.pathExists(tsc))) { throw new Error(`The ${_kleur.default.blue('tsc')} binary doesn't seem to be installed at ${_kleur.default.blue(tsc)}. Please specify the correct path in options or remove it to use the workspace's version.`); } } else { const execpath = process.env.npm_execpath; const cli = execpath?.split(_path.default.sep).pop()?.includes('yarn') ? 'yarn' : 'npm'; if (cli === 'yarn') { const result = await (0, _spawn.spawn)('yarn', ['bin', 'tsc'], { cwd: root }); tsc = result.trim(); } else { tsc = _path.default.resolve(root, 'node_modules', '.bin', 'tsc'); } if ((0, _os.platform)() === 'win32' && !tsc.endsWith('.cmd')) { tsc += '.cmd'; } } if (!(await _fsExtra.default.pathExists(tsc))) { try { tsc = await (0, _which.default)('tsc'); if (await _fsExtra.default.pathExists(tsc)) { report.warn(`Failed to locate ${_kleur.default.blue('tsc')} in the workspace. Falling back to the binary found in ${_kleur.default.blue('PATH')} at ${_kleur.default.blue(tsc)}. Consider adding ${_kleur.default.blue('typescript')} to your ${_kleur.default.blue('devDependencies')} or specifying the ${_kleur.default.blue('tsc')} option for the typescript target.`); } } catch (e) { // Ignore } } if (tsc == null || !(await _fsExtra.default.pathExists(tsc))) { throw new Error(`The ${_kleur.default.blue('tsc')} binary doesn't seem to be installed under ${_kleur.default.blue('node_modules')} or present in $PATH. Make sure you have added ${_kleur.default.blue('typescript')} to your ${_kleur.default.blue('devDependencies')} or specify the ${_kleur.default.blue('tsc')} option for typescript.`); } const outputs = {}; if (esm && variants.commonjs && variants.module) { outputs.commonjs = _path.default.join(output, 'commonjs'); outputs.module = _path.default.join(output, 'module'); } else if (variants.commonjs) { outputs.commonjs = output; } else { outputs.module = output; } const outDir = outputs.commonjs ?? outputs.module; if (outDir == null) { throw new Error('Neither commonjs nor module output is enabled.'); } const tsbuildinfo = _path.default.join(outDir, project.replace(/\.json$/, '.tsbuildinfo')); try { await (0, _del.default)([tsbuildinfo]); } catch (e) { // Ignore } await (0, _spawn.spawn)(tsc, ['--pretty', '--declaration', '--declarationMap', '--noEmit', 'false', '--emitDeclarationOnly', '--project', project, '--outDir', outDir], { cwd: root }); try { await (0, _del.default)([tsbuildinfo]); } catch (e) { // Ignore } if (esm) { if (outputs?.commonjs && outputs?.module) { // When ESM compatible output is enabled and commonjs build is present, we need to generate 2 builds for commonjs and esm // In this case we copy the already generated types, and add `package.json` with `type` field await _fsExtra.default.copy(outputs.commonjs, outputs.module); await _fsExtra.default.writeJSON(_path.default.join(outputs.commonjs, 'package.json'), { type: 'commonjs' }); await _fsExtra.default.writeJSON(_path.default.join(outputs.module, 'package.json'), { type: 'module' }); } else if (outputs?.commonjs) { await _fsExtra.default.writeJSON(_path.default.join(outputs.commonjs, 'package.json'), { type: 'commonjs' }); } else if (outputs?.module) { await _fsExtra.default.writeJSON(_path.default.join(outputs.module, 'package.json'), { type: 'module' }); } } report.success(`Wrote definition files to ${_kleur.default.blue(_path.default.relative(root, output))}`); const pkg = JSON.parse(await _fsExtra.default.readFile(_path.default.join(root, 'package.json'), 'utf-8')); const fields = [{ name: 'types', value: pkg.types, output: outputs.commonjs, error: false, message: undefined }, ...(pkg.exports?.['.']?.types ? [{ name: "exports['.'].types", value: pkg.exports?.['.']?.types, output: outDir, error: Boolean(pkg.exports?.['.']?.import && pkg.exports?.['.']?.require), message: `using ${_kleur.default.blue("exports['.'].import")} and ${_kleur.default.blue("exports['.'].require")}. Specify ${_kleur.default.blue("exports['.'].import.types")} and ${_kleur.default.blue("exports['.'].require.types")} instead.` }] : []), { name: "exports['.'].import.types", value: pkg.exports?.['.']?.import?.types, output: outputs.module, error: !esm, message: `the ${_kleur.default.blue('esm')} option is not enabled for the ${_kleur.default.blue('module')} target` }, { name: "exports['.'].require.types", value: pkg.exports?.['.']?.require?.types, output: outputs.commonjs, error: false, message: undefined }]; const getGeneratedTypesPath = async field => { if (!field.output || field.error) { return null; } if (pkg.source) { const indexDTsName = _path.default.basename(pkg.source).replace(/\.(jsx?|tsx?)$/, '') + '.d.ts'; const potentialPaths = [_path.default.join(field.output, _path.default.dirname(pkg.source), indexDTsName), _path.default.join(field.output, _path.default.relative(source, _path.default.join(root, _path.default.dirname(pkg.source))), indexDTsName)]; for (const potentialPath of potentialPaths) { if (await _fsExtra.default.pathExists(potentialPath)) { return _path.default.relative(root, potentialPath); } } } return null; }; const invalidFieldNames = (await Promise.all(fields.map(async field => { if (field.error) { if (field.value) { report.warn(`The ${_kleur.default.blue(field.name)} field in ${_kleur.default.blue(`package.json`)} should not be set when ${String(field.message)}.`); } return null; } if (field.name.startsWith('exports') && field.value && !/^\.\//.test(field.value)) { report.error(`The ${_kleur.default.blue(field.name)} field in ${_kleur.default.blue(`package.json`)} should be a relative path starting with ${_kleur.default.blue('./')}. Found: ${_kleur.default.blue(field.value)}`); return field.name; } if (field.value && !(await _fsExtra.default.pathExists(_path.default.join(root, field.value)))) { const generatedTypesPath = await getGeneratedTypesPath(field); report.error(`The ${_kleur.default.blue(field.name)} field in ${_kleur.default.blue('package.json')} points to a non-existent file: ${_kleur.default.blue(field.value)}.\nVerify the path points to the correct file under ${_kleur.default.blue(_path.default.relative(root, output))}${generatedTypesPath ? ` (found ${_kleur.default.blue(generatedTypesPath)}).` : '.'}`); return field.name; } return null; }))).filter(name => name != null); if (invalidFieldNames.length) { throw new Error(`Found errors for fields: ${invalidFieldNames.join(', ')}.`); } const validFields = fields.filter(field => !field.error); if (validFields.every(field => field.value == null)) { const suggestedTypesPaths = (await Promise.all(validFields.map(async field => getGeneratedTypesPath(field)))).filter(path => path != null).filter((path, i, self) => self.indexOf(path) === i); report.warn(`No ${validFields.map(field => _kleur.default.blue(field.name)).join(' or ')} field found in ${_kleur.default.blue('package.json')}. Consider ${suggestedTypesPaths.length ? `pointing to ${suggestedTypesPaths.map(path => _kleur.default.blue(path)).join(' or ')}` : `adding ${validFields.length > 1 ? 'them' : 'it'}`} so that consumers of your package can use the typescript definitions.`); } } catch (e) { if (e != null && typeof e === 'object') { if ('stdout' in e && e.stdout != null) { report.error(`Errors found when building definition files:\n${e.stdout.toString()}`); } else if ('message' in e && typeof e.message === 'string') { report.error(e.message); } } throw new Error('Failed to build definition files.', { cause: e }); } } //# sourceMappingURL=typescript.js.map