gluegun
Version:
A delightful toolkit for building Node-powered CLIs.
212 lines • 8.49 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Runtime = void 0;
// helpers
var path_1 = require("path");
var utils_1 = require("../toolbox/utils");
// domains
var command_1 = require("../domain/command");
// loaders
var command_loader_1 = require("../loaders/command-loader");
var config_loader_1 = require("../loaders/config-loader");
var plugin_loader_1 = require("../loaders/plugin-loader");
// tools
var filesystem_tools_1 = require("../toolbox/filesystem-tools");
var string_tools_1 = require("../toolbox/string-tools");
// the special run function
var run_1 = require("./run");
/**
* Loads plugins, extensions, and invokes the intended command.
*/
var Runtime = /** @class */ (function () {
/**
* Create and initialize an empty Runtime.
*/
function Runtime(brand) {
this.plugins = [];
this.extensions = [];
this.commands = [];
this.defaults = {};
this.defaultPlugin = null;
this.defaultCommand = null;
this.config = {};
this.checkUpdate = false;
this.brand = brand;
this.run = run_1.run; // awkward because node.js doesn't support async-based class functions yet.
}
/**
* Adds the core extensions. These provide the basic features
* available in gluegun, but follow a similar method
* for extending the core as 3rd party extensions do.
*/
Runtime.prototype.addCoreExtensions = function (exclude) {
var _this = this;
if (exclude === void 0) { exclude = []; }
var coreExtensions = [
'meta',
'strings',
'print',
'filesystem',
'semver',
'system',
'prompt',
'http',
'template',
'patching',
'package-manager',
];
coreExtensions.forEach(function (ex) {
if (!exclude.includes(ex)) {
_this.addExtension(ex, require("../core-extensions/".concat(ex, "-extension")));
}
});
};
/**
* Adds a command to the runtime.
*
* @param command A GluegunCommand.
* @returns This runtime.
*/
Runtime.prototype.addCommand = function (command) {
var _this = this;
if (!command.plugin && !this.defaultPlugin) {
throw new Error("Can't add command ".concat(command.name, " - no default plugin. You may have forgotten a src() on your runtime."));
}
// convert the command to a real Command object (if needed)
var newCommand = (0, utils_1.is)(command_1.Command, command) ? command : (0, command_loader_1.loadCommandFromPreload)(command);
// set the command's plugin reference to the defaultPlugin
// if it doesn't already have one
if (!newCommand.plugin) {
newCommand.plugin = this.defaultPlugin;
this.defaultPlugin.commands.push(newCommand);
}
if (newCommand.name === this.brand) {
// we want to keep a reference to the default command, so we can find it later
this.defaultCommand = newCommand;
}
// add the command to the runtime (if it isn't already there)
if (!this.commands.find(function (c) { return c.commandPath === newCommand.commandPath; })) {
this.commands.push(newCommand);
}
// now sort the commands
this.commands.sort(function (a, b) {
if (a === _this.defaultCommand)
return -1;
if (b === _this.defaultCommand)
return 1;
if (a.plugin === _this.defaultPlugin)
return -1;
if (b.plugin === _this.defaultPlugin)
return 1;
return 0;
});
return this;
};
/**
* Adds an extension so it is available when commands run. They usually live
* as the given name on the toolbox object passed to commands, but are able
* to manipulate the toolbox object however they want. The second
* parameter is a function that allows the extension to attach itself.
*
* @param name The toolbox property name.
* @param setup The setup function.
* @returns This runtime.
*/
Runtime.prototype.addExtension = function (name, setup) {
setup = setup.default || setup;
this.extensions.push({ name: name, setup: setup });
return this;
};
/**
* Loads a plugin from a directory and sets it as the default.
*
* @param directory The directory to load from.
* @param options Additional loading options.
* @returns This runtime.
*/
Runtime.prototype.addDefaultPlugin = function (directory, options) {
if (options === void 0) { options = {}; }
this.defaultPlugin = this.addPlugin(directory, __assign({ required: true, name: this.brand }, options));
// load config and set defaults
var loadedConfig = (0, config_loader_1.loadConfig)(this.brand, directory) || {};
var defaults = loadedConfig.defaults, config = __rest(loadedConfig, ["defaults"]);
this.defaults = defaults;
this.config = config;
return this;
};
/**
* Loads a plugin from a directory.
*
* @param directory The directory to load from.
* @param options Additional loading options.
* @returns The plugin that was created or null.
*/
Runtime.prototype.addPlugin = function (directory, options) {
var _this = this;
if (options === void 0) { options = {}; }
if (!filesystem_tools_1.filesystem.isDirectory(directory)) {
if (options.required) {
throw new Error("Error: couldn't load plugin (not a directory): ".concat(directory));
}
else {
return undefined;
}
}
var plugin = (0, plugin_loader_1.loadPluginFromDirectory)((0, path_1.resolve)(directory), {
brand: this.brand,
hidden: options.hidden,
name: options.name,
commandFilePattern: options.commandFilePattern,
extensionFilePattern: options.extensionFilePattern,
preloadedCommands: options.preloadedCommands,
});
this.plugins.push(plugin);
plugin.extensions.forEach(function (extension) { return _this.addExtension(extension.name, extension.setup); });
plugin.commands.forEach(function (command) { return _this.addCommand(command); });
return plugin;
};
/**
* Loads a bunch of plugins from the immediate sub-directories of a directory.
*
* @param directory The directory to grab from.
* @param options Addition loading options.
* @return This runtime.
*/
Runtime.prototype.addPlugins = function (directory, options) {
var _this = this;
if (options === void 0) { options = {}; }
if (string_tools_1.strings.isBlank(directory) || !filesystem_tools_1.filesystem.isDirectory(directory))
return [];
// find matching filesystem.subdirectories
var subdirs = filesystem_tools_1.filesystem.subdirectories(directory, false, options.matching);
// load each one using `this.plugin`
// eslint-disable-next-line @typescript-eslint/no-unused-vars
var matching = options.matching, otherOptions = __rest(options, ["matching"]); // remove "matching"
return subdirs.map(function (dir) { return _this.addPlugin(dir, otherOptions); });
};
return Runtime;
}());
exports.Runtime = Runtime;
//# sourceMappingURL=runtime.js.map