noflo
Version:
Flow-Based Programming environment for JavaScript
189 lines (163 loc) • 6.18 kB
text/coffeescript
# NoFlo - Flow-Based Programming for JavaScript
# (c) 2013-2016 TheGrid (Rituwall Inc.)
# (c) 2013 Henri Bergius, Nemein
# NoFlo may be freely distributed under the MIT license
#
# This is the Node.js version of the ComponentLoader.
{_} = require 'underscore'
path = require 'path'
fs = require 'fs'
loader = require '../ComponentLoader'
internalSocket = require '../InternalSocket'
utils = require '../Utils'
nofloGraph = require '../Graph'
manifest = require 'fbp-manifest'
# We allow components to be un-compiled CoffeeScript
CoffeeScript = require 'coffee-script'
if typeof CoffeeScript.register != 'undefined'
CoffeeScript.register()
babel = require 'babel-core'
class ComponentLoader extends loader.ComponentLoader
writeCache: (options, modules, callback) ->
filePath = path.resolve , options.manifest
fs.writeFile filePath, JSON.stringify(modules, null, 2),
encoding: 'utf-8'
, callback
readCache: (options, callback) ->
options.discover = false
manifest.load.load , options, callback
prepareManifestOptions: ->
options = {}
options.runtimes = .runtimes or []
options.runtimes.push 'noflo' if options.runtimes.indexOf('noflo') is -1
options.recursive = if typeof .recursive is 'undefined' then true else .recursive
options.manifest = 'fbp.json' unless options.manifest
options
readModules: (modules, callback) ->
compatible = modules.filter (m) -> m.runtime in ['noflo', 'noflo-nodejs']
for m in compatible
[m.name] = m.icon if m.icon
if m.noflo?.loader
loaderPath = path.resolve , m.base, m.noflo.loader
.push loaderPath
for c in m.components
["#{m.name}/#{c.name}"] = path.resolve , c.path
# Inject subgraph component
if path.extname(__filename) is '.js'
.Graph = path.resolve __dirname, '../../components/Graph.js'
else
.Graph = path.resolve __dirname, '../../components/Graph.coffee'
return callback null unless .length
done = _.after .length, callback
.forEach (loaderPath) =>
loader = require loaderPath
loader, (err) ->
return callback err if err
done null
listComponents: (callback) ->
if
'ready', =>
callback null,
return
return callback null, if
= false
= true
manifestOptions =
if .cache and not
manifestOptions, (err, modules) =>
if err
= true
= false
return callback err unless .discover
return callback
= {}
modules.modules, (err) =>
= true
= false
'ready', true
callback null, if callback
return
= {}
manifest.list.list , manifestOptions, (err, modules) =>
return callback err if err
modules, (err) =>
= false
return callback err if err
= true
'ready', true
return callback null, unless .cache
manifestOptions, modules, (err) =>
return callback err if err
callback null,
setSource: (packageId, name, source, language, callback) ->
unless
(err) =>
return callback err if err
packageId, name, source, language, callback
return
Module = require 'module'
if language is 'coffeescript'
try
source = CoffeeScript.compile source,
bare: true
catch e
return callback e
else if language in ['es6', 'es2015']
try
source = babel.transform(source).code
catch e
return callback e
try
# Use the Node.js module API to evaluate in the correct directory context
modulePath = path.resolve , "./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 e
return callback e
unless implementation or implementation.getComponent
return callback new Error 'Provided source failed to create a runnable component'
packageId, name, implementation, ->
callback null
getSource: (name, callback) ->
unless
(err) =>
return callback err if err
name, callback
return
component = [name]
unless component
# Try an alias
for componentName of
if componentName.split('/')[1] is name
component = [componentName]
name = componentName
break
unless component
return callback new Error "Component #{name} not installed"
if typeof component isnt 'string'
return callback new Error "Can't provide source for #{name}. Not a file"
nameParts = name.split '/'
if nameParts.length is 1
nameParts[1] = nameParts[0]
nameParts[0] = ''
if component
nofloGraph.loadFile component, (err, graph) ->
return callback err if err
return callback new Error 'Unable to load graph' unless graph
callback null,
name: nameParts[1]
library: nameParts[0]
code: JSON.stringify graph.toJSON()
language: 'json'
return
fs.readFile component, 'utf-8', (err, code) ->
return callback err if err
callback null,
name: nameParts[1]
library: nameParts[0]
language: utils.guessLanguageFromFilename component
code: code
exports.ComponentLoader = ComponentLoader