npm-link-up
Version:
Use this package to link your projects together for local development.
198 lines (197 loc) • 8.31 kB
JavaScript
;
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.`);
map_paths_1.mapPaths(searchRoots, root, cb);
},
getMatchingProjects(mapSearchRoots, cb) {
const map = {}, status = { searching: true };
const findProjects = 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 = 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...');
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);
});