UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

209 lines (174 loc) 6.49 kB
# NoFlo - Flow-Based Programming for JavaScript # (c) 2013-2017 Flowhub UG # (c) 2013 Henri Bergius, Nemein # NoFlo may be freely distributed under the MIT license # # This is the browser version of the ComponentLoader. internalSocket = require './InternalSocket' fbpGraph = require 'fbp-graph' {EventEmitter} = require 'events' registerLoader = require './loader/register' class ComponentLoader extends EventEmitter constructor: (@baseDir, @options = {}) -> @components = null @libraryIcons = {} @processing = false @ready = false @setMaxListeners 0 if typeof @setMaxListeners is 'function' getModulePrefix: (name) -> return '' unless name return '' if name is 'noflo' name = name.replace /\@[a-z\-]+\//, '' if name[0] is '@' name.replace 'noflo-', '' listComponents: (callback) -> if @processing @once 'ready', => callback null, @components return return callback null, @components if @components @ready = false @processing = true @components = {} registerLoader.register @, (err) => if err return callback err if callback throw err @processing = false @ready = true @emit 'ready', true callback null, @components if callback return load: (name, callback, metadata) -> unless @ready @listComponents (err) => return callback err if err @load name, callback, metadata return component = @components[name] unless component # Try an alias for componentName of @components if componentName.split('/')[1] is name component = @components[componentName] break unless component # Failure to load callback new Error "Component #{name} not available with base #{@baseDir}" return if @isGraph component if typeof process isnt 'undefined' and process.execPath and process.execPath.indexOf('node') isnt -1 # nextTick is faster on Node.js process.nextTick => @loadGraph name, component, callback, metadata else setTimeout => @loadGraph name, component, callback, metadata , 0 return @createComponent name, component, metadata, (err, instance) => return callback err if err if not instance callback new Error "Component #{name} could not be loaded." return instance.baseDir = @baseDir if name is 'Graph' instance.componentName = name if typeof name is 'string' @setIcon name, instance callback null, instance # Creates an instance of a component. createComponent: (name, component, metadata, callback) -> implementation = component unless implementation return callback new Error "Component #{name} not available" # If a string was specified, attempt to `require` it. if typeof implementation is 'string' if typeof registerLoader.dynamicLoad is 'function' registerLoader.dynamicLoad name, implementation, metadata, callback return return callback Error "Dynamic loading of #{implementation} for component #{name} not available on this platform." # Attempt to create the component instance using the `getComponent` method. if typeof implementation.getComponent is 'function' instance = implementation.getComponent metadata # Attempt to create a component using a factory function. else if typeof implementation is 'function' instance = implementation metadata else callback new Error "Invalid type #{typeof(implementation)} for component #{name}." return callback null, instance isGraph: (cPath) -> # Live graph instance return true if typeof cPath is 'object' and cPath instanceof fbpGraph.Graph # Graph JSON definition return true if typeof cPath is 'object' and cPath.processes and cPath.connections return false unless typeof cPath is 'string' # Graph file path cPath.indexOf('.fbp') isnt -1 or cPath.indexOf('.json') isnt -1 loadGraph: (name, component, callback, metadata) -> @createComponent name, @components['Graph'], metadata, (err, graph) => return callback err if err graphSocket = internalSocket.createSocket() graph.loader = @ graph.baseDir = @baseDir graph.inPorts.remove 'graph' graph.setGraph component, (err) => return callback err if err @setIcon name, graph callback null, graph return return setIcon: (name, instance) -> # See if component has an icon return if not instance.getIcon or instance.getIcon() # See if library has an icon [library, componentName] = name.split '/' if componentName and @getLibraryIcon library instance.setIcon @getLibraryIcon library return # See if instance is a subgraph if instance.isSubgraph() instance.setIcon 'sitemap' return instance.setIcon 'square' return getLibraryIcon: (prefix) -> if @libraryIcons[prefix] return @libraryIcons[prefix] return null setLibraryIcon: (prefix, icon) -> @libraryIcons[prefix] = icon normalizeName: (packageId, name) -> prefix = @getModulePrefix packageId fullName = "#{prefix}/#{name}" fullName = name unless packageId fullName registerComponent: (packageId, name, cPath, callback) -> fullName = @normalizeName packageId, name @components[fullName] = cPath do callback if callback registerGraph: (packageId, name, gPath, callback) -> @registerComponent packageId, name, gPath, callback registerLoader: (loader, callback) -> loader @, callback setSource: (packageId, name, source, language, callback) -> unless registerLoader.setSource return callback new Error 'setSource not allowed' unless @ready @listComponents (err) => return callback err if err @setSource packageId, name, source, language, callback return registerLoader.setSource @, packageId, name, source, language, callback getSource: (name, callback) -> unless registerLoader.getSource return callback new Error 'getSource not allowed' unless @ready @listComponents (err) => return callback err if err @getSource name, callback return registerLoader.getSource @, name, callback clear: -> @components = null @ready = false @processing = false exports.ComponentLoader = ComponentLoader