pertain
Version:
Automated pub/sub across project dependencies. Run code from any installed package based on declarative rules in package.json
82 lines • 5.43 kB
JavaScript
import makeDebug from 'debug';
import path from 'path';
import PackageJson from './PackageJson';
import PertainError from './PertainError';
const debug = makeDebug('pertain:ExplicitDependency');
/**
* A Node module that the consuming project (the one calling `pertain()`) has
* declared in `dependencies` or `devDependencies`. These are the modules that
* we check for the package property we're looking for.
*/
export default class ExplicitDependency {
/**
* Lazy-loading package.json data.
*/
pkg;
/**
* Real path on disk of this module.
*/
modulePath;
/**
* Name of this package; for use in dependency detection.
*/
get name() {
return this.pkg.name;
}
constructor(modulePath) {
this.modulePath = modulePath;
this.pkg = new PackageJson(modulePath);
}
/**
* Returns true if this module has declared an explicit peer dependency on
* the provided module name. Used to sort all pertaining modules into
* dependency order.
*
* Why only a peer dependency? Because the consuming project doesn't want
* `pertain()` to scan infinitely into the module tree; only first-level
* dependencies can pertain. So the dependency order is only relevant to
* the dependencies that the root project has directly declared.
*
* TL;DR if you're building an extension framework with `pertain()`, you
* should require extensions to use `peerDependencies` when using other
* extensions. Otherwise they're not guaranteed to run in the right order.
*/
dependsOn(name) {
return Reflect.has(this.pkg.peerDependencies, name);
}
/**
* Returns a resolvable path to a JS module declared in this `package.json`,
* at the JSON path supplied as `subject`. If no path exists, returns false.
*
* Example: If the subject is `"foo"`, AND `package.json` has a top-level
* property `"foo": "./bar.js"`, then `this.pertains("foo")` will be
* `"/path/to/this/module/bar.js"`.
*
* Dot notation lookup works: if the subject is `pwa.build`, then
* `package.json`must have a top level `pwa` object with a `build` property.
*/
pertains(subject) {
const pertaining = this.pkg.lookup(subject);
// Only strings can be file paths, so anything else does not pertain
if (!pertaining || typeof pertaining !== 'string') {
debug('%s: Subject %s resolved to %s', this.pkg.name, subject, pertaining);
return false;
}
debug('found declaration of "%s" as "%s" in "%s"', subject, pertaining, this.pkg.name);
// This is the indicated path which would pertain; is it requireable?
const subscriber = path.join(this.modulePath, pertaining);
try {
const pertainingModule = require.resolve(subscriber);
debug('found runnable module at %s', pertainingModule);
return pertainingModule;
}
catch (e) {
throw new PertainError(`"${this.pkg.name}" declares a "${subject}" module, but Node could not find a valid JS module to load from "${subscriber}"`);
}
}
/* istanbul ignore next */
toString() {
return `${this.pkg.name} @ ${this.modulePath}`;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXhwbGljaXREZXBlbmRlbmN5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0V4cGxpY2l0RGVwZW5kZW5jeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFNBQVMsTUFBTSxPQUFPLENBQUM7QUFDOUIsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sV0FBVyxNQUFNLGVBQWUsQ0FBQztBQUN4QyxPQUFPLFlBQVksTUFBTSxnQkFBZ0IsQ0FBQztBQUUxQyxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsNEJBQTRCLENBQUMsQ0FBQztBQUV0RDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE9BQU8sT0FBTyxrQkFBa0I7SUFDckM7O09BRUc7SUFDSyxHQUFHLENBQWM7SUFDekI7O09BRUc7SUFDSSxVQUFVLENBQVM7SUFFMUI7O09BRUc7SUFDSCxJQUFXLElBQUk7UUFDYixPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxZQUFZLFVBQWtCO1FBQzVCLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBQzdCLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7O09BYUc7SUFDSSxTQUFTLENBQUMsSUFBWTtRQUMzQixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBQyxJQUFJLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNJLFFBQVEsQ0FBQyxPQUFlO1FBQzdCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRTVDLG9FQUFvRTtRQUNwRSxJQUFJLENBQUMsVUFBVSxJQUFJLE9BQU8sVUFBVSxLQUFLLFFBQVEsRUFBRTtZQUNqRCxLQUFLLENBQ0gsK0JBQStCLEVBQy9CLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUNiLE9BQU8sRUFDUCxVQUFVLENBQ1gsQ0FBQztZQUNGLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7UUFFRCxLQUFLLENBQ0gsMkNBQTJDLEVBQzNDLE9BQU8sRUFDUCxVQUFVLEVBQ1YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQ2QsQ0FBQztRQUVGLHFFQUFxRTtRQUNyRSxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDMUQsSUFBSTtZQUNGLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNyRCxLQUFLLENBQUMsNkJBQTZCLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztZQUN2RCxPQUFPLGdCQUFnQixDQUFDO1NBQ3pCO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDVixNQUFNLElBQUksWUFBWSxDQUNwQixJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxpQkFBaUIsT0FBTyxxRUFBcUUsVUFBVSxHQUFHLENBQzVILENBQUM7U0FDSDtJQUNILENBQUM7SUFFRCwwQkFBMEI7SUFDbkIsUUFBUTtRQUNiLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksTUFBTSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDakQsQ0FBQztDQUNGIn0=