noflo
Version:
Flow-Based Programming environment for JavaScript
295 lines (270 loc) • 9.62 kB
JavaScript
(function() {
var CoffeeScript, ComponentLoader, babel, fs, internalSocket, loader, manifest, nofloGraph, path, utils, _,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
_ = require('underscore')._;
path = require('path');
fs = require('fs');
loader = require('../ComponentLoader');
internalSocket = require('../InternalSocket');
utils = require('../Utils');
nofloGraph = require('../Graph');
manifest = require('fbp-manifest');
CoffeeScript = require('coffee-script');
if (typeof CoffeeScript.register !== 'undefined') {
CoffeeScript.register();
}
babel = require('babel-core');
ComponentLoader = (function(_super) {
__extends(ComponentLoader, _super);
function ComponentLoader() {
return ComponentLoader.__super__.constructor.apply(this, arguments);
}
ComponentLoader.prototype.writeCache = function(options, modules, callback) {
var filePath;
filePath = path.resolve(this.baseDir, options.manifest);
return fs.writeFile(filePath, JSON.stringify(modules, null, 2), {
encoding: 'utf-8'
}, callback);
};
ComponentLoader.prototype.readCache = function(options, callback) {
options.discover = false;
return manifest.load.load(this.baseDir, options, callback);
};
ComponentLoader.prototype.prepareManifestOptions = function() {
var options;
options = {};
options.runtimes = this.options.runtimes || [];
if (options.runtimes.indexOf('noflo') === -1) {
options.runtimes.push('noflo');
}
options.recursive = typeof this.options.recursive === 'undefined' ? true : this.options.recursive;
if (!options.manifest) {
options.manifest = 'fbp.json';
}
return options;
};
ComponentLoader.prototype.readModules = function(modules, callback) {
var c, compatible, done, loaderPath, m, _i, _j, _len, _len1, _ref, _ref1;
compatible = modules.filter(function(m) {
var _ref;
return (_ref = m.runtime) === 'noflo' || _ref === 'noflo-nodejs';
});
for (_i = 0, _len = compatible.length; _i < _len; _i++) {
m = compatible[_i];
if (m.icon) {
this.libraryIcons[m.name] = m.icon;
}
if ((_ref = m.noflo) != null ? _ref.loader : void 0) {
loaderPath = path.resolve(this.baseDir, m.base, m.noflo.loader);
this.componentLoaders.push(loaderPath);
}
_ref1 = m.components;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
c = _ref1[_j];
this.components["" + m.name + "/" + c.name] = path.resolve(this.baseDir, c.path);
}
}
if (path.extname(__filename) === '.js') {
this.components.Graph = path.resolve(__dirname, '../../components/Graph.js');
} else {
this.components.Graph = path.resolve(__dirname, '../../components/Graph.coffee');
}
if (!this.componentLoaders.length) {
return callback(null);
}
done = _.after(this.componentLoaders.length, callback);
return this.componentLoaders.forEach((function(_this) {
return function(loaderPath) {
loader = require(loaderPath);
return _this.registerLoader(loader, function(err) {
if (err) {
return callback(err);
}
return done(null);
});
};
})(this));
};
ComponentLoader.prototype.listComponents = function(callback) {
var manifestOptions;
if (this.processing) {
this.once('ready', (function(_this) {
return function() {
return callback(null, _this.components);
};
})(this));
return;
}
if (this.components) {
return callback(null, this.components);
}
this.ready = false;
this.processing = true;
manifestOptions = this.prepareManifestOptions();
if (this.options.cache && !this.failedCache) {
this.readCache(manifestOptions, (function(_this) {
return function(err, modules) {
if (err) {
_this.failedCache = true;
_this.processing = false;
if (!_this.options.discover) {
return callback(err);
}
return _this.listComponents(callback);
}
_this.components = {};
return _this.readModules(modules.modules, function(err) {
_this.ready = true;
_this.processing = false;
_this.emit('ready', true);
if (callback) {
return callback(null, _this.components);
}
});
};
})(this));
return;
}
this.components = {};
return manifest.list.list(this.baseDir, manifestOptions, (function(_this) {
return function(err, modules) {
if (err) {
return callback(err);
}
return _this.readModules(modules, function(err) {
_this.processing = false;
if (err) {
return callback(err);
}
_this.ready = true;
_this.emit('ready', true);
if (!_this.options.cache) {
return callback(null, _this.components);
}
return _this.writeCache(manifestOptions, modules, function(err) {
if (err) {
return callback(err);
}
return callback(null, _this.components);
});
});
};
})(this));
};
ComponentLoader.prototype.setSource = function(packageId, name, source, language, callback) {
var Module, e, implementation, moduleImpl, modulePath;
if (!this.ready) {
this.listComponents((function(_this) {
return function(err) {
if (err) {
return callback(err);
}
return _this.setSource(packageId, name, source, language, callback);
};
})(this));
return;
}
Module = require('module');
if (language === 'coffeescript') {
try {
source = CoffeeScript.compile(source, {
bare: true
});
} catch (_error) {
e = _error;
return callback(e);
}
} else if (language === 'es6' || language === 'es2015') {
try {
source = babel.transform(source).code;
} catch (_error) {
e = _error;
return callback(e);
}
}
try {
modulePath = path.resolve(this.baseDir, "./components/" + name + ".js");
moduleImpl = new Module(modulePath, module);
moduleImpl.paths = Module._nodeModulePaths(path.dirname(modulePath));
moduleImpl.filename = modulePath;
moduleImpl._compile(source, modulePath);
implementation = moduleImpl.exports;
} catch (_error) {
e = _error;
return callback(e);
}
if (!(implementation || implementation.getComponent)) {
return callback(new Error('Provided source failed to create a runnable component'));
}
return this.registerComponent(packageId, name, implementation, function() {
return callback(null);
});
};
ComponentLoader.prototype.getSource = function(name, callback) {
var component, componentName, nameParts;
if (!this.ready) {
this.listComponents((function(_this) {
return function(err) {
if (err) {
return callback(err);
}
return _this.getSource(name, callback);
};
})(this));
return;
}
component = this.components[name];
if (!component) {
for (componentName in this.components) {
if (componentName.split('/')[1] === name) {
component = this.components[componentName];
name = componentName;
break;
}
}
if (!component) {
return callback(new Error("Component " + name + " not installed"));
}
}
if (typeof component !== 'string') {
return callback(new Error("Can't provide source for " + name + ". Not a file"));
}
nameParts = name.split('/');
if (nameParts.length === 1) {
nameParts[1] = nameParts[0];
nameParts[0] = '';
}
if (this.isGraph(component)) {
nofloGraph.loadFile(component, function(err, graph) {
if (err) {
return callback(err);
}
if (!graph) {
return callback(new Error('Unable to load graph'));
}
return callback(null, {
name: nameParts[1],
library: nameParts[0],
code: JSON.stringify(graph.toJSON()),
language: 'json'
});
});
return;
}
return fs.readFile(component, 'utf-8', function(err, code) {
if (err) {
return callback(err);
}
return callback(null, {
name: nameParts[1],
library: nameParts[0],
language: utils.guessLanguageFromFilename(component),
code: code
});
});
};
return ComponentLoader;
})(loader.ComponentLoader);
exports.ComponentLoader = ComponentLoader;
}).call(this);