UNPKG

npm-link-up

Version:

Use this package to link your projects together for local development.

198 lines (197 loc) 8.33 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); const path = require("path"); const fs = require("fs"); const chalk_1 = require("chalk"); const dashdash = require('dashdash'); const async = require("async"); const residence = require("residence"); const mkdirp = require("mkdirp"); const cmd_line_opts_1 = require("./cmd-line-opts"); const logging_1 = require("../../logging"); const cwd = process.cwd(); const root = residence.findProjectRoot(cwd); const find_matching_projects_1 = require("./find-matching-projects"); const add_ignore_1 = require("./add-ignore"); const always_ignore_1 = require("../../always-ignore"); const map_paths_1 = require("../../map-paths"); const run_link_1 = require("../../run-link"); const get_clean_final_map_1 = require("../../get-clean-final-map"); const nluUtils = require("../../utils"); process.once('exit', code => { logging_1.default.info('Exiting with code:', code, '\n'); }); if (!root) { logging_1.default.error('Cannot find a project root given your current working directory:', chalk_1.default.magenta(cwd)); logging_1.default.error(' => NLU could not find a package.json file within your cwd.'); process.exit(1); } const allowUnknown = process.argv.indexOf('--allow-unknown') > 0; let opts, parser = dashdash.createParser({ options: cmd_line_opts_1.default, allowUnknown }); try { opts = parser.parse(process.argv); } catch (e) { logging_1.default.error(chalk_1.default.magenta('CLI parsing error:'), chalk_1.default.magentaBright.bold(e.message)); process.exit(1); } if (opts.help) { let help = parser.help({ includeEnv: true }).trimRight(); console.log('usage: nlu add [OPTIONS]\n' + 'options:\n' + help); process.exit(0); } let pkgJSON; try { pkgJSON = require(path.resolve(root + '/package.json')); } catch (err) { logging_1.default.error(err); logging_1.default.error('Could not load your projects package.json file.'); logging_1.default.error('No package.json file could be found in path:', root); process.exit(1); } const projectsToAdd = nluUtils.flattenDeep([opts._args]).map(v => String(v || '').trim()).filter(Boolean); const absolutePaths = projectsToAdd.filter(v => path.isAbsolute(v)); if (absolutePaths.length > 0) { throw `NLU cannot currently handle file paths. Instead, use 'nlu add one two three', and nlu will find them on your fs.`; } if (projectsToAdd.length < 1) { logging_1.default.error('You did not pass any projects to add. Try: nlu add foo'); process.exit(1); } projectsToAdd.forEach(v => { logging_1.default.info('nlu will add a symlink to this project:', v); }); const mainProjectName = pkgJSON.name; if (!mainProjectName) { logging_1.default.error('Your current project does not have a name (no name property in package.json.'); logging_1.default.error('That is weird.'); } else { logging_1.default.info('Your project name is:', chalk_1.default.bold.blueBright(mainProjectName)); } let nluJSON, nluJSONPath = path.resolve(root + '/.nlu.json'); try { nluJSON = require(nluJSONPath); } catch (err) { logging_1.default.error('Cannot find an .nlu.json config file in your project.'); logging_1.default.error('Your project path is:', root); throw err.message; } if (!nluUtils.validateConfigFile(nluJSON)) { console.error(); if (!opts.override) { logging_1.default.error(chalk_1.default.redBright('Your .nlu.json config file appears to be invalid. To override this, use --override.')); process.exit(1); } } let searchRoots = nluUtils.flattenDeep([nluJSON.searchRoots, nluJSON.searchRoot]); if (opts.search_from_home && opts.search_root) { logging_1.default.error('You passed the --search-from-home option along with --search/--search-root.'); process.exit(1); } if (opts.search_from_home) { searchRoots = [process.env.HOME]; } if (opts.search_root) { searchRoots = nluUtils.flattenDeep([opts.search_root]).map(v => String(v || '').trim()).filter(Boolean); } if (!(searchRoots && searchRoots.length > 0)) { logging_1.default.warn(`Using $HOME to search for related projects. To limit your fs search, use the --search=<path> option.`); searchRoots = [process.env.HOME]; if (!opts.search_from_home) { logging_1.default.warn('Please use --search=<path> to confine your project search to something less wide as user home.'); logging_1.default.warn('For multiple search roots, you can use --search more than once.'); logging_1.default.warn(`If you wish to use $HOME as the search root, use ${chalk_1.default.bold('--search-from-home')},`, `but be aware that it can take a long time to search through user home.`); process.exit(1); } } else { if (opts.search_from_home) { logging_1.default.error('You passed the --search-from-home option along with --search/--search-root.'); process.exit(1); } } const ignore = add_ignore_1.default.concat(always_ignore_1.default) .filter((item, index, arr) => arr.indexOf(item) === index) .map(item => new RegExp(item)); async.autoInject({ ensureNodeModules(cb) { mkdirp(path.resolve(root + '/node_modules'), cb); }, mapSearchRoots(cb) { opts.verbosity > 3 && logging_1.default.info(`Mapping original search roots from your root project's "searchRoots" property.`); (0, map_paths_1.mapPaths)(searchRoots, root, cb); }, getMatchingProjects(mapSearchRoots, cb) { const map = {}, status = { searching: true }; const findProjects = (0, find_matching_projects_1.makeFindProjects)(mainProjectName, ignore, opts, map, projectsToAdd.slice(0), status); const q = async.queue(function (task, cb) { task(cb); }); logging_1.default.info('Search roots are:', mapSearchRoots); mapSearchRoots.forEach((v) => { q.push((cb) => { findProjects(v, cb); }); }); if (q.idle()) { return process.nextTick(cb, new Error('For some reason no items/paths ended up on the search queue.')); } let first = true; q.drain = q.error = function (err) { if (err) { status.searching = false; logging_1.default.error(chalk_1.default.magenta('There was a search queue processing error.')); } if (first) { q.kill(); cb(err, map); } first = false; }; }, runUtility(ensureNodeModules, getMatchingProjects, cb) { try { nluJSON.list = nluJSON.list.concat(projectsToAdd) .map(v => String(v || '').trim()).filter((v, i, a) => a.indexOf(v) === i); } catch (e) { return process.nextTick(cb, e); } getMatchingProjects[mainProjectName] = { name: mainProjectName, bin: pkgJSON.bin || null, isMainProject: true, linkToItself: Boolean(nluJSON.linkToItself), runInstall: Boolean(nluJSON.alwaysReinstall), path: root, deps: nluJSON.list }; let cleanMap; try { cleanMap = (0, get_clean_final_map_1.getCleanMap)(mainProjectName, getMatchingProjects, opts); } catch (err) { return process.nextTick(cb, err); } opts.verbosity > 1 && logging_1.default.info('Beginning to actually link projects together...'); (0, run_link_1.runNPMLink)(cleanMap, opts, cb); }, addToNLUJSON(runUtility, cb) { const newNluJSONstr = JSON.stringify(nluJSON, null, 2); fs.writeFile(nluJSONPath, newNluJSONstr, 'utf8', cb); }, }, function (err, results) { if (err) { logging_1.default.error('There was an error when running "nlu add".'); logging_1.default.error('Here were your command line arguments used:'); process.argv.forEach((v, i) => logging_1.default.info(chalk_1.default.gray.bold(String(i)), chalk_1.default.gray(v))); logging_1.default.error(err.message || err); return process.exit(1); } logging_1.default.veryGood(chalk_1.default.green('Looks like the nlu init routine succeeded. ') + 'Check your new .nlu.json file in the root of your project.'); process.exit(0); });