@mjcctech/meteor-desktop
Version:
Build a Meteor's desktop client with hot code push.
192 lines (175 loc) • 6.91 kB
JavaScript
;var module1=module;module1.export({default:()=>DependenciesManager});var regeneratorRuntime;module1.link('regenerator-runtime/runtime',{default(v){regeneratorRuntime=v}},0);var forEach,assignIn,intersection;module1.link('lodash',{forEach(v){forEach=v},assignIn(v){assignIn=v},intersection(v){intersection=v}},1);var Log;module1.link('./log',{default(v){Log=v}},2);// eslint-disable-next-line no-unused-vars
/**
* Utility class designed for merging dependencies list with simple validation and duplicate
* detection.
*
* @class
*/
class DependenciesManager {
/**
* @param {MeteorDesktop} $ - context
* @param {Object} defaultDependencies - core dependencies list
* @constructor
*/
constructor($, defaultDependencies) {
this.log = new Log('dependenciesManager');
this.$ = $;
this.dependencies = defaultDependencies;
// Regexes for matching certain types of dependencies version.
// https://docs.npmjs.com/files/package.json#dependencies
this.regexes = {
local: /^(\.\.\/|~\/|\.\/|\/)/,
git: /^git(\+(ssh|http)s?)?/,
github: /^\w+-?\w+(?!-)\//,
http: /^https?.+tar\.gz/,
file: /^file:/
};
// Check for commit hashes.
const gitCheck = {
type: 'regex',
regex: /#[a-f0-9]{7,40}/,
test: 'match',
message: 'git or github link must have a commit hash'
};
// Check for displaying warnings when npm package from local path is used.
const localCheck = {
onceName: 'localCheck',
type: 'warning',
message: 'using dependencies from local paths is permitted' +
' but dangerous - read more in README.md'
};
this.checks = {
local: localCheck,
file: localCheck,
git: gitCheck,
github: gitCheck,
version: {
type: 'regex',
// Matches all the semver ranges operators, empty strings and `*`.
regex: /[\^|><= ~-]|\.x|^$|^\*$/,
test: 'do not match',
message: 'semver ranges are forbidden, please specify exact version'
}
};
}
/**
* Just a public getter.
* @returns {Object}
*/
getDependencies() {
return this.dependencies;
}
/**
* Returns local dependencies.
* @returns {Object}
*/
getLocalDependencies() {
return Object
.keys(this.dependencies)
.filter(
dependency =>
this.regexes.local.test(this.dependencies[dependency]) ||
this.regexes.file.test(this.dependencies[dependency])
)
.reduce(
(localDependencies, currentDependency) =>
Object.assign(
localDependencies,
{ [currentDependency]: this.dependencies[currentDependency] }
),
{}
);
}
/**
* Returns remote dependencies.
* @returns {Object}
*/
getRemoteDependencies() {
return Object
.keys(this.dependencies)
.filter(
dependency =>
!this.regexes.local.test(this.dependencies[dependency]) &&
!this.regexes.file.test(this.dependencies[dependency])
)
.reduce(
(localDependencies, currentDependency) =>
Object.assign(
localDependencies,
{ [currentDependency]: this.dependencies[currentDependency] }
),
{}
);
}
/**
* Merges dependencies into one list.
*
* @param {string} from - describes where the dependencies were set
* @param {Object} dependencies - dependencies list
*/
mergeDependencies(from, dependencies) {
if (this.validateDependenciesVersions(from, dependencies)) {
this.detectDuplicatedDependencies(from, dependencies);
assignIn(this.dependencies, dependencies);
}
}
/**
* Detects dependency version type.
* @param {string} version - version string of the dependency
* @return {string}
*/
detectDependencyVersionType(version) {
const type = Object.keys(this.regexes)
.find(dependencyType => this.regexes[dependencyType].test(version));
return type || 'version';
}
/**
* Validates semver and detect ranges.
*
* @param {string} from - describes where the dependencies were set
* @param {Object} dependencies - dependencies list
*/
validateDependenciesVersions(from, dependencies) {
const warningsShown = {};
forEach(dependencies, (version, name) => {
const type = this.detectDependencyVersionType(version);
if (this.checks[type]) {
const check = this.checks[type];
if (check.type === 'regex') {
const checkResult = check.test === 'match' ?
this.checks[type].regex.test(version) :
!this.checks[type].regex.test(version);
if (!checkResult) {
throw new Error(`dependency ${name}:${version} from ${from} failed version ` +
`check with message: ${this.checks[type].message}`);
}
}
if (check.type === 'warning' && !warningsShown[check.onceName]) {
warningsShown[check.onceName] = true;
this.log.warn(`dependency ${name}:${version} from ${from} caused a` +
` warning: ${check.message}`);
}
}
});
return true;
}
/**
* Detects duplicates.
*
* @param {string} from - describes where the dependencies were set
* @param {Object} dependencies - dependencies list
*/
detectDuplicatedDependencies(from, dependencies) {
const duplicates = intersection(Object.keys(dependencies), Object.keys(this.dependencies));
if (duplicates.length > 0) {
duplicates.forEach((name) => {
if (dependencies[name] !== this.dependencies[name]) {
throw new Error(`While processing dependencies from ${from}, a dependency ` +
`${name}: ${dependencies[name]} was found to be conflicting with a ` +
`dependency (${this.dependencies[name]}) that was already declared in ` +
'other module or it is used in core of the electron app.');
}
});
}
}
}