#!/usr/bin/env node
"use strict";
/**
* @module script-watch-lerna-packages
* @license MIT
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.watch = exports.bootstrap = void 0;
/**
* @file watch-lerna-packages script
*/
/**
* This file is copied and is modified as per the requirements
*
* @package - https://github.com/Dombo/node-lerna-monorepo
* {@link - https://github.com/Dombo/node-lerna-monorepo}
* @author - Dom Hutton(https://github.com/Dombo)
* @license - none
*
*/
const LERNA_PACKAGE_WATCHER = 'LERNA_PACKAGE_WATCHER'; // tslint-disable-line
const path = require("path");
const fs = require("fs");
const commander = require("commander");
const execa = require("execa");
const chokidar = require("chokidar");
commander
.version("0.0.0")
.option("-b, --bootstrap", "Bootstrap dependencies for the dependents of the current working directory.")
.option("-w, --watch", "Start a watcher for the dependents of the current working directory.")
.parse();
const manifest = (dir = undefined) => JSON.parse(fs.readFileSync(`${dir ? dir : process.cwd()}/package.json`, {
encoding: "utf8"
}));
/**
* From the context of the process.cwd(), find the package manifest name & bootstrap it's dependencies via lerna
* @since 1.0.0
*/
const bootstrap = () => {
try {
const lernaArgs = `bootstrap --scope ${manifest().name} --include-filtered-dependencies`.split(" ");
execa("lerna", lernaArgs, { stdio: "inherit" });
}
catch (error) {
throw new Error(`There was a problem trying to bootstrap the tree ${error}`);
}
};
exports.bootstrap = bootstrap;
const buildDependencyTreeMeta = () => __awaiter(void 0, void 0, void 0, function* () {
try {
const lernaArgs = `ls --all --sort --toposort --json --include-filtered-dependencies`.split(" ");
const { stdout, stderr } = yield execa("lerna", lernaArgs);
return JSON.parse(stdout);
}
catch (error) {
throw new Error(`There was an error building the dependency tree: ${error}`);
}
});
const findParentPackageManifest = changedFile => {
const startingPath = path.dirname(changedFile);
const up = node => {
let file = path.join(node, "package.json");
if (fs.existsSync(file)) {
return path.dirname(file);
}
file = path.resolve(node, "..");
return up(file);
};
return up(startingPath);
};
const pruneParentPackageTree = tree => tree.slice(1, tree.length - 1); // removes the leaf node & the tree root
const findParentPackages = (name) => __awaiter(void 0, void 0, void 0, function* () {
const lernaArgs = `ls --all --toposort --json --scope ${name} --include-filtered-dependents`.split(" ");
const { stdout } = yield execa("lerna", lernaArgs);
return JSON.parse(stdout);
});
const buildDependency = (name) => __awaiter(void 0, void 0, void 0, function* () {
const lernaArgs = `run watch:changes --scope ${name}`.split(" ");
yield execa("lerna", lernaArgs, { stdio: "inherit" });
yield execa("yarn", ["jsdoc"], { stdio: 'inherit' });
});
/*
* From the context of a modified package currently under watch via watch()
* Find the package manifest of the changed dependency
* Build said dependency
* Find the upstream dependencies of said dependency (sans the tree root & node just build)
* Build them in order
* */
const buildDependencyChain = (path) => __awaiter(void 0, void 0, void 0, function* () {
const changedPackageManifest = findParentPackageManifest(path);
const changedPackageName = manifest(changedPackageManifest).name;
yield buildDependency(changedPackageName);
const packageParents = yield findParentPackages(changedPackageName);
const buildWorthyParents = pruneParentPackageTree(packageParents);
const buildOperations = buildWorthyParents.map(dependency => buildDependency(dependency.name));
yield Promise.all(buildOperations);
});
const spawnWatcher = (paths) => __awaiter(void 0, void 0, void 0, function* () {
yield console.log(`Would spawn a watcher over ${paths}`);
const log = console.log.bind(console);
// Initialize the watcher
const watcher = chokidar.watch(paths, {
ignored: [
/(^|[\/\\])\../,
/node_modules/,
/lib|dist/,
/\*___jb_tmp___/ // ignore jetbrains IDE temp files
],
persistent: true,
ignoreInitial: true,
awaitWriteFinish: true // Helps minimising thrashing of watch events
});
// Add event listeners
return watcher
.on("add", path => {
log(`File ${path} has been added`);
buildDependencyChain(path);
})
.on("change", path => {
log(`File ${path} has been changed`);
buildDependencyChain(path);
})
.on("unlink", path => {
log(`File ${path} has been removed`);
buildDependencyChain(path);
});
});
/**
* From the context of the process.cwd(), find the package manifest name & spawn a filesystem watcher for it's tree.
* @since 1.0.0
*/
const watch = () => __awaiter(void 0, void 0, void 0, function* () {
try {
const dependencyTreeMeta = yield buildDependencyTreeMeta();
const paths = dependencyTreeMeta // We only spawn watchers for the dependencies, it's expected you watch your app
.slice(0, dependencyTreeMeta.length)
.map(dependency => dependency.location);
spawnWatcher(paths);
}
catch (error) {
throw new Error(`There was a problem trying to build the tree ${error}`);
}
});
exports.watch = watch;
if (commander.bootstrap)
bootstrap();
if (commander.watch)
watch();
//# sourceMappingURL=index.js.map