UNPKG

jaune-util

Version:
148 lines (115 loc) 4.19 kB
###* * @file Source code for Reflection utility. * @author Alvaro Juste ### 'use strict' {join} = require 'path' INST_REGEX = /^\[(\w{1})\((.*)\)\]$/ GLOBAL_REGEX = /^\[g\((.*)\)\]$/ TOKEN_REQUIRE = 'r' TOKEN_MODULE = 'm' TOKEN_NAMESPACE = 'n' TOKEN_CALL = 'c' TOKEN_INSTANCE = 'i' ###* * Create an instance of the given constructor with the given arguments. * @param {Function} constructor The constructing function. * @param {Array} args Arguments for the constructor * @returns The instance. ### applyNew = (constructor, args) -> inst = Object.create constructor.prototype constructor.apply inst, args inst ###* * @function Creates an instance of the given name * @param {String} fullName The name of the reference to be looked up * @param {Object} [args] Arguments for the function * @param {Object} [context] Initial search point for look up * @param {Object} [globals] References that might be required in look up * @returns {Object} Instantiated object ### createInstance = (fullName, args, context, globals) -> {fn, args} = evaluateNameAndArgs fullName, args, context, globals applyNew fn, args ###* * @function Evaluates a function and its arguments * @param {String} fullName The name of the reference to be looked up * @param {Object} [args] Arguments for the function * @param {Object} [context] Initial search point for look up * @param {Object} [globals] References that might be required in look up * @returns {Object} Object with function and arguments ### evaluateNameAndArgs = (fullName, args = [], context, globals) -> fn = evaluateName fullName, context, args, globals resolvedArguments = args unless typeof fn is 'function' throw new Error "Full name points to invalid function #{fullName}" if typeof globals is 'object' resolvedArguments = args .map (e) -> if typeof e is 'string' and e.indexOf('_') is 0 globals[e.substring(1)] else e {fn, args : resolvedArguments} ###* * @function Returns a compiled expression * @param {String} expr The name of the reference to be compiled * @param {Object} [args] Arguments for the function * @param {Object} [globals] References that might be required in look up * @returns {Array} Compiled nodes ### compileExpression = (expr, args = {}, globals = {}) -> expr .split '.' .map (e) -> isOperation = INST_REGEX.test e operation = (if isOperation e.replace INST_REGEX, '$1' else TOKEN_NAMESPACE) params = if isOperation then e.replace INST_REGEX, '$2' else e switch operation when TOKEN_CALL, TOKEN_INSTANCE params = for param in params.split(',') continue unless (param = param.trim()).length value = args[param] if GLOBAL_REGEX.test value globals[value.replace GLOBAL_REGEX, '$1'] else value {params, operation} executeNode = (current, node) -> {operation, params} = node switch operation when TOKEN_REQUIRE node = require if params.indexOf('/') isnt -1 join(process.cwd(), params) else params when TOKEN_MODULE node = require params when TOKEN_NAMESPACE node = current[params] when TOKEN_CALL unless typeof current is 'function' throw new Error 'Call instruction can only be perfomed on functions' node = current.apply undefined, params when TOKEN_INSTANCE unless typeof current is 'function' throw new Error 'New instruction can only be perfomed on functions' node = applyNew current, node.params else throw new Error "Unsupported node type: #{operation}" throw new Error 'Full name points to invalid reference' unless node node evaluateName = (exprs, args, context, globals) -> unless typeof exprs is 'string' throw new Error 'Expression should be a string' compileExpression(exprs, args, globals).reduce executeNode, context ? global module.exports = Reflection : {createInstance, evaluateNameAndArgs, compileExpression, evaluateName, executeNode}