Skip to content

Commit

Permalink
✨ Add Plugin class + refactor loading of requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
skerit committed Jan 23, 2024
1 parent 32ebcb2 commit ab97ba3
Show file tree
Hide file tree
Showing 13 changed files with 607 additions and 586 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Implement new settings system
* Replace old `sputnik` dependency with a new stages system
* Add default `App` classes
* Add `Plugin` class
* Refactor loading of requirements

## 1.3.22 (2023-12-21)

Expand Down
308 changes: 308 additions & 0 deletions lib/class/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
const PLUGINS_STAGE = STAGES.getStage('load_app').getStage('plugins'),
libpath = require('path'),
libfs = require('fs'),
FLAGS = Symbol('flags');

/**
* The Plugin class:
* Represents a plugin that can be used by Alchemy
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @param {string} name The name of the plugin
* @param {string} path The path of the plugin
* @param {Object} default_settings
*/
const Plugin = Function.inherits('Alchemy.Base', function Plugin(name, path, default_settings) {

// The name of the plugin
this.name = name;

// The path of the plugin
this.path = path;

// The hard-coded default settings
this.default_settings = default_settings;

// Flags
this[FLAGS] = {
attempted_bootstrap : false,
preloaded : false,
created_settings : false,
started : false,
};
});

/**
* Preload the plugin
* (Bootstrap & settings)
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @return {boolean}
*/
Plugin.setMethod(function doPreload() {

if (this[FLAGS].preloaded) {
return false;
}

// Create settings from the `config/settings.js` file
this.loadSettingDefinitions();

// Load the bootstrap file
this.loadBootstrap();

PLUGINS_STAGE.addPostTask(() => {
return this.startPlugin();
});
});

/**
* Do the rest of the plugin loading
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @return {boolean}
*/
Plugin.setMethod(async function startPlugin() {

if (this[FLAGS].started) {
return false;
}

this[FLAGS].started = true;

await alchemy.useAppPath(this.path, {plugin: this});
});

/**
* Create the setting definitions
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @return {boolean}
*/
Plugin.setMethod(function loadSettingDefinitions() {

if (this[FLAGS].created_settings) {
return false;
}

this[FLAGS].created_settings = true;

let settings_path = libpath.resolve(this.path, 'config', 'settings.js');

// See if the file exists
if (!libfs.existsSync(settings_path)) {
return false;
}

// Get/create this plugin's group definition
let group = this.getSettingsGroup();

// Get any already-existing settings
let parent = alchemy.system_settings.get('plugins');
let existing = parent.get(this.name);

if (existing) {
// Remove the existing settings.
// They are not linked properly anyway.
parent.remove(this.name);
}

// Require the settings.js file now
this.useFile(settings_path, {client: false});

// Create the new group settings with default values
let default_group = group.generateValue();

if (this.default_settings) {
default_group.setDefaultValue(this.default_settings);
}

if (existing) {
default_group.setValueSilently(existing);
}

parent.injectSubGroupValue(this.name, default_group);

return true;
});

/**
* Load the bootstrap file
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @return {boolean}
*/
Plugin.setMethod(function loadBootstrap() {

if (this[FLAGS].attempted_bootstrap) {
return false;
}

this[FLAGS].attempted_bootstrap = true;

let bootstrap_path = libpath.resolve(this.path, 'bootstrap.js');

// See if the file exists
if (!libfs.existsSync(bootstrap_path)) {
return false;
}

// Require the bootstrap.js file now
this.useFile(bootstrap_path, {client: false});

if (this.default_settings) {
let settings_group = this.getSettingsGroup();
settings_group.setDefaultValue(this.default_settings);
}

return true;
});

/**
* Use an entire path
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @param {string} path
* @param {Object} options
*/
Plugin.setMethod(function usePath(path, options) {

if (!options) {
options = {};
}

options.plugin = this;

return alchemy.usePath(path, options);
});

/**
* Require a file of this plugin
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @param {string} path
* @param {Object} options
*
* @return {Mixed}
*/
Plugin.setMethod(function useOnce(path, options) {
return this.useFile(path, options);
});

/**
* Require a file of this plugin
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @param {string} path
* @param {Object} options
*
* @return {Mixed}
*/
Plugin.setMethod(function useFile(path, options) {

if (!options) {
options = {};
}

options.plugin = this;

if (!options.arguments) {

let argument_configuration = {
values : [
Blast,
Blast.Classes,
Blast.Types,
Blast.Collection,
Blast.Bound,
Blast.Bound.Object,
Blast.Collection.Function,
this,
],
names : [
'Blast',
'Classes',
'Types',
'Collection',
'Bound',
'Obj',
'Fn',
'Plugin',
],
};

options.arguments = argument_configuration;
}

return alchemy.useOnce(path, options);
});

/**
* Get this plugin's settings group
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @return {Alchemy.Setting.Group}
*/
Plugin.setMethod(function getSettingsGroup() {

let group = Classes.Alchemy.Setting.PLUGINS.get(this.name);

if (!group) {
group = Classes.Alchemy.Setting.PLUGINS.createGroup(this.name);
}

return group;
});

/**
* Add a route
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @return {Alchemy.Router.Route}
*/
Plugin.setMethod(function addRoute(config) {
return Router.add(config);
});

/**
* Custom Janeway representation (right side)
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @return {String}
*/
Plugin.setMethod(Symbol.for('janeway_arg_right'), function janewayInstanceInfo() {
return this.name;
});
10 changes: 4 additions & 6 deletions lib/core/alchemy.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict';

var shared_objects = {},
let shared_objects = {},
plugModules = null,
usedModules = {},
useErrors = {},
Expand All @@ -23,14 +21,14 @@ var shared_objects = {},
*/
global.Alchemy = Function.inherits('Alchemy.Base', function Alchemy() {

var that = this,
package_json;

// Only allow a single instance of the Alchemy class
if (global.alchemy) {
return global.alchemy;
}

let that = this,
package_json;

// Timestamp when alchemy started
this.start_time = Date.now();

Expand Down
2 changes: 0 additions & 2 deletions lib/core/alchemy_functions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

let mkdirp = alchemy.use('mkdirp')?.mkdirp,
ncp = alchemy.use('ncp').ncp,
fs = alchemy.use('fs'),
Expand Down
Loading

0 comments on commit ab97ba3

Please sign in to comment.