npm-link-extra
Version:
npm or yarn link common modules between a project and a monorepo/multi-packages dir
136 lines (123 loc) • 3.6 kB
JavaScript
/* eslint-disable no-console */
const fs = require('fs');
const path = require('path');
const ownPkg = require('../package.json');
const debugLogging = (...args) => {
if (process.env.NLX_DEBUG) {
console.log(...args);
}
};
const pkgHash = {
startTime: Date.now(),
cache: {},
};
function logPkgsMsg(msg, pkgs) {
return console.log(`
${msg}
=======
${pkgs.join('\n')}
`);
}
const pathToCache = path.join(__dirname, '.cache-nlx.json');
const isADir = p => fs.statSync(p).isDirectory();
const cacheExists = fs.existsSync(pathToCache);
function writeToCache(inc) {
return fs.writeFileSync(pathToCache, JSON.stringify(inc, null, 2), 'utf-8');
}
function readAndParseJSON(pathToJSON, defaultToReturn) {
if (fs.existsSync(pathToJSON)) {
try {
return JSON.parse(fs.readFileSync(pathToJSON, 'utf-8'));
} catch (error) {
console.error(error);
return defaultToReturn;
}
}
return defaultToReturn;
}
const filterOutNodeModules = arr =>
arr.filter(n => !/(node_modules|\.git|__|.DS_Store|reports|dist)/.test(n)); // NOTE - this needs to be configurable
function findInPath(name, base, fileName, f, r) {
// console.log(`Checking if ${name} package exists within this repo.`);
const files = filterOutNodeModules(f || fs.readdirSync(base));
const result = r || [];
for (let idx = 0; idx < files.length; idx += 1) {
const file = files[idx];
const newbase = path.join(base, file);
if (isADir(newbase)) {
findInPath(name, newbase, fileName, fs.readdirSync(newbase), result);
} else if (file.substr(-1 * (fileName.length + 1)) === fileName) {
// eslint-disable-next-line global-require
const pkgName = require(newbase).name; // eslint-disable-line import/no-dynamic-require
if (pkgName === name) {
debugLogging(`Found ${name} at path ${newbase}`);
result.push(newbase);
}
}
}
return result;
}
function cacheOwnModulePaths(hash) {
const updateCache = {
lastUpdated: Date.now(),
cache: {},
};
if (cacheExists) {
debugLogging('WRITING TO READ CACHE');
const readCache = readAndParseJSON(pathToCache, {});
const updated = Object.assign(readCache, {
cache: hash.cache,
});
writeToCache(updated);
} else {
debugLogging('WRITING NEW CACHE');
const newCache = Object.assign(updateCache, {
cache: hash.cache,
});
writeToCache(newCache);
}
}
function existsInOwnPath(cwd, name) {
try {
if (cacheExists) {
const { cache } = readAndParseJSON(pathToCache, {});
if (typeof cache[name] === 'boolean') {
debugLogging(`READING FROM CACHE for ${name}`);
// return cached value
return cache[name];
}
}
pkgHash.cache[name] = findInPath(name, cwd, 'package.json').length > 0;
cacheOwnModulePaths(pkgHash);
} catch (error) {
throw error;
}
return pkgHash.cache[name];
}
function checkForLink(name) {
if (name === ownPkg.name) return false;
const cwd = process.cwd();
const modulePath = path.resolve(cwd, 'node_modules', name);
if (fs.existsSync(modulePath) && isADir(modulePath)) {
const stat = fs.lstatSync(modulePath);
const isASymLink = stat.isSymbolicLink();
if (isASymLink) {
if (existsInOwnPath(cwd, name)) return false;
return true;
}
}
return false;
}
function readPkgJson(dir) {
try {
return readAndParseJSON(`${dir}/package.json`);
} catch (err) {
return console.log(`No package.json at ${dir}/package.json`);
}
}
module.exports = {
logPkgsMsg,
readPkgJson,
checkForLink,
debugLogging,
};