zombiebox
Version:
ZombieBox is a JavaScript framework for development of Smart TV and STB applications
157 lines (129 loc) • 3.33 kB
JavaScript
/*
* This file is part of the ZombieBox package.
*
* Copyright © 2012-2019, Interfaced
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const {findPackageJson} = require('../utils');
const AbstractAddon = require('./abstract-addon');
const AbstractPlatform = require('./abstract-platform');
const AbstractExtension = require('./abstract-extension');
/* eslint-disable global-require */
/**
*/
class AddonLoader {
/**
* @param {string} projectModulesDir
*/
constructor(projectModulesDir) {
/**
* @type {string}
* @private
*/
this._projectModulesDir = projectModulesDir;
/**
* @type {Array<LoadedAddon>}
* @private
*/
this._loadedAddons = [];
}
/**
* @return {Array<Object>}
*/
getPackageJsons() {
return this._loadedAddons.map((addon) => addon.packageJson)
.filter(Boolean);
}
/**
* @return {Array<AbstractAddon>}
*/
getAddons() {
return this._loadedAddons.map((addon) => addon.instance);
}
/**
* @return {Array<AbstractExtension>}
*/
getExtensions() {
return this.getAddons()
.filter((addon) => addon instanceof AbstractExtension);
}
/**
* @return {Array<AbstractPlatform>}
*/
getPlatforms() {
return this.getAddons()
.filter((addon) => addon instanceof AbstractPlatform);
}
/**
* @param {Object} packageJson
*/
loadFromPackageJson(packageJson) {
Object.keys(packageJson['dependencies'] || {})
.filter((packageName) => packageName.startsWith(PACKAGE_PREFIX))
.map((packageName) => this._resolvePackagePath(packageName))
.forEach((packagePath) => this.loadAddon(packagePath));
}
/**
* @param {string} addonPath
*/
loadAddon(addonPath) {
const Addon = require(addonPath);
const addon = /** @type {AbstractAddon} */ (new Addon());
const packageJson = require(findPackageJson(addonPath));
this.addAddon(addon, packageJson);
}
/**
* @param {AbstractAddon} addon
* @param {Object=} packageJson
*/
addAddon(addon, packageJson = null) {
if (!(addon instanceof AbstractAddon)) {
throw new Error(`Trying to add not addon: ${addon}`);
}
if (this._isLoaded(addon)) {
throw new Error(`Addon with name ${chalk.bold(addon.getName())} is already loaded`);
}
this._loadedAddons.push({instance: addon, packageJson});
const type =
addon instanceof AbstractPlatform ? 'Platform' :
addon instanceof AbstractExtension ? 'Extension' :
'Addon';
console.log(`${type} ${chalk.green(addon.getName())} loaded`);
}
/**
* @param {string} packageName
* @return {string}
* @protected
*/
_resolvePackagePath(packageName) {
const localPackage = path.join(this._projectModulesDir, packageName);
return fs.existsSync(localPackage) ? localPackage : require.resolve(packageName);
}
/**
* @param {AbstractAddon} addon
* @return {boolean}
* @protected
*/
_isLoaded(addon) {
return this._loadedAddons.some((loadedAddon) =>
loadedAddon.instance.getName() === addon.getName()
);
}
}
/**
* @const {string}
*/
const PACKAGE_PREFIX = 'zombiebox-';
/**
* @typedef {{
* instance: AbstractAddon,
* packageJson: ?Object
* }}
*/
let LoadedAddon;
module.exports = AddonLoader;