<commit_before>/// core.js --- The core of Noire assertions
//
// Copyright (c) 2012 Quildreen Motta
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

var Base = require('boo').Base
var array_p = Array.isArray
var slice   = [].slice

var Assertion = Base.derive({
  init:
  function _init(value) {
    this._prelude     = 'to'
    this._message     = ''
    this._params      = {}
    this._times       = 100

    return this.expect(value) }

, store:
  function _store(key, value) {
    this._params[key] = value
    return this }

, expect:
  function _expect(value) {
    this._expectation = value
    this.store('expected', value)
    return this }

, describe:
  function _describe(message, overwrite) {
    if (this._message && !overwrite) return this

    this._message = message
    return this }

, message:
  function _message() {
    return format( 'Expected {:expected} ' + this._prelude + ' ' + this._message
                 , this._params )}

, define:
  function _define(name, description, property) {
    var matcher = function() { this.describe(description)
                               property.apply(this, arguments)
                               return this }

    name = array_p(name)?   name
         : /* otherwise */  [name]
    name.forEach(function(key){ this[key] = matcher }, this) }

, satisfy:
  function _satisfy(property) {
    this.store('‹satisfy:property›', property)
    this.describe('satisfy {:‹satisfy:property›}.')

    if (!this._test(property, this._expectation))
      throw make_error(this.message())

    return this }

, _test:
  function _test(property) {
    return property.apply(null, slice.call(arguments, 1)) }

, not:
  function _not() {
    var test = this._test

    this._prelude = 'to not'
    this._test = function(){ return !test.apply(this, arguments) }
    return this }

, invoke:
  function _invoke(method) {
    var args = [].slice.call(arguments, 1)
    this.store('‹invoke:method›', method)
    this.store('‹invoke:args›', args)
    this._prelude = ', when invoking method {:‹invoke:method›} with '
                  + '{:‹invoke:args›} ' + this._prelude
    var test = this._test
    this._test = function(p){ this._expectation = this._expectation[method].apply(this._expectation, args)
                              this._message += ' Yielded {:‹invoke:result›} instead.'
                              this.store('‹invoke:result›', this._expectation)
                              return test.apply(this, [p, this._expectation]) }
    return this }

, all:
  function _all(generators) {
    var test   = this._test
    this._test = random_property_test
    return this

    function random_property_test(prop, expectation) {
      var ok    = true
      var times = 0
      var args, value

      while (ok && times++ < this._times) {
        args  = generators.map(function(v){ return v() })
        value = expectation.apply(null, args)
        ok    = test(prop, value) }

      this.store('‹all:times›', times)
      this.store('‹all:args›', args)
      this.store('‹all:result›', value)
      this._prelude  = ', given the arguments {:‹all:args›}, '
                     + this._prelude + ' yield values that will'
      this._message += '  Failed after {:‹all:times›} test(s) by yielding {:‹all:result›}'
      return ok }}
})

///// Function starts_with_p
// Does the `string' start with a given piece of text?
//
// starts_with_p :: String, String -> Bool
function starts_with_p(string, what) {
  return string.slice(0, what.length) == what }

///// Function format
// Evaluates a template, substituting the variables with respect to the
// environment provided by the given `mappings'.
//
// If a mapping is not given, we assume it to be empty, in which case
// the template variables are simply stripped away.
//
// A template variable is a special construct in the form:
//
//     :bnf:
//     <template-variable> ::= "{:" <any but "}"> "}"
//
// For example, provide a "Hello, world!" template, that adjusts to a
// given name, one could write:
//
//     format("Hello, {:subject}!", { subject: "world" })
//     // => "Hello, world!"
//
// A template variable can be escaped by placing a backslash between the
// open-curly braces and the colon, such that the construct would be
// output verbatim:
//
//     // Remember backslashes must be escaped inside Strings.
//     format("Hello, {\\:subject}", { subject: "world" })
//     // => "Hello, {\\:subject}"
//
//
// format :: String, { String -> String | (String... -> String) } -> String
function format(string, mappings) {
  mappings = mappings || {}
  return string.replace(/{(\\?:)([^}]+)}/g, resolve_identifier)

  function resolve_identifier(match, mod, key) {
    return starts_with_p(mod, '\\')?  '{:' + key + '}'
    :      key in mappings?           stringify(mappings[key])
    :      /* otherwise */            '' }}

function stringify(o) {
  return typeof o == 'function'?    o.name?          '[Function: ' + o.name + ']'
                                  : /* otherwise */  '`' + o.toString() + '`'
  :      /* otherwise */          JSON.stringify(o) }

function make_error(message) {
  var e = Error.call(Object.create(Error.prototype), message)
  e.name = 'AssertionError'
  return e }

function ensure(value) {
  return Assertion.make(value) }

module.exports = { ensure: ensure
                 , Assertion: Assertion

                 , internal: { make_error: make_error }
                 }<commit_msg>Makes `not' more friendly for chaining.<commit_after>/// core.js --- The core of Noire assertions
//
// Copyright (c) 2012 Quildreen Motta
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

var Base = require('boo').Base
var array_p = Array.isArray
var slice   = [].slice

var Assertion = Base.derive({
  init:
  function _init(value) {
    this._prelude     = 'to'
    this._message     = ''
    this._params      = {}
    this._times       = 100

    return this.expect(value) }

, store:
  function _store(key, value) {
    this._params[key] = value
    return this }

, expect:
  function _expect(value) {
    this._expectation = value
    this.store('expected', value)
    return this }

, describe:
  function _describe(message, overwrite) {
    if (this._message && !overwrite) return this

    this._message = message
    return this }

, message:
  function _message() {
    return format( 'Expected {:expected} ' + this._prelude + ' ' + this._message
                 , this._params )}

, define:
  function _define(name, description, property) {
    var matcher = function() { this.describe(description)
                               property.apply(this, arguments)
                               return this }

    name = array_p(name)?   name
         : /* otherwise */  [name]
    name.forEach(function(key){ this[key] = matcher }, this) }

, satisfy:
  function _satisfy(property) {
    this.store('‹satisfy:property›', property)
    this.describe('satisfy {:‹satisfy:property›}.')

    if (!this._test(property, this._expectation))
      throw make_error(this.message())

    return this }

, _test:
  function _test(property) {
    return property.apply(null, slice.call(arguments, 1)) }

, not:
  function _not() {
    var test = this._test

    this._prelude += ' not'
    this._test = function(){ return !test.apply(this, arguments) }
    return this }

, invoke:
  function _invoke(method) {
    var args = [].slice.call(arguments, 1)
    this.store('‹invoke:method›', method)
    this.store('‹invoke:args›', args)
    this._prelude = ', when invoking method {:‹invoke:method›} with '
                  + '{:‹invoke:args›} ' + this._prelude
    var test = this._test
    this._test = function(p){ this._expectation = this._expectation[method].apply(this._expectation, args)
                              this._message += ' Yielded {:‹invoke:result›} instead.'
                              this.store('‹invoke:result›', this._expectation)
                              return test.apply(this, [p, this._expectation]) }
    return this }

, all:
  function _all(generators) {
    var test   = this._test
    this._test = random_property_test
    return this

    function random_property_test(prop, expectation) {
      var ok    = true
      var times = 0
      var args, value

      while (ok && times++ < this._times) {
        args  = generators.map(function(v){ return v() })
        value = expectation.apply(null, args)
        ok    = test(prop, value) }

      this.store('‹all:times›', times)
      this.store('‹all:args›', args)
      this.store('‹all:result›', value)
      this._prelude  = ', given the arguments {:‹all:args›}, '
                     + this._prelude + ' yield values that will'
      this._message += '  Failed after {:‹all:times›} test(s) by yielding {:‹all:result›}'
      return ok }}
})

///// Function starts_with_p
// Does the `string' start with a given piece of text?
//
// starts_with_p :: String, String -> Bool
function starts_with_p(string, what) {
  return string.slice(0, what.length) == what }

///// Function format
// Evaluates a template, substituting the variables with respect to the
// environment provided by the given `mappings'.
//
// If a mapping is not given, we assume it to be empty, in which case
// the template variables are simply stripped away.
//
// A template variable is a special construct in the form:
//
//     :bnf:
//     <template-variable> ::= "{:" <any but "}"> "}"
//
// For example, provide a "Hello, world!" template, that adjusts to a
// given name, one could write:
//
//     format("Hello, {:subject}!", { subject: "world" })
//     // => "Hello, world!"
//
// A template variable can be escaped by placing a backslash between the
// open-curly braces and the colon, such that the construct would be
// output verbatim:
//
//     // Remember backslashes must be escaped inside Strings.
//     format("Hello, {\\:subject}", { subject: "world" })
//     // => "Hello, {\\:subject}"
//
//
// format :: String, { String -> String | (String... -> String) } -> String
function format(string, mappings) {
  mappings = mappings || {}
  return string.replace(/{(\\?:)([^}]+)}/g, resolve_identifier)

  function resolve_identifier(match, mod, key) {
    return starts_with_p(mod, '\\')?  '{:' + key + '}'
    :      key in mappings?           stringify(mappings[key])
    :      /* otherwise */            '' }}

function stringify(o) {
  return typeof o == 'function'?    o.name?          '[Function: ' + o.name + ']'
                                  : /* otherwise */  '`' + o.toString() + '`'
  :      /* otherwise */          JSON.stringify(o) }

function make_error(message) {
  var e = Error.call(Object.create(Error.prototype), message)
  e.name = 'AssertionError'
  return e }

function ensure(value) {
  return Assertion.make(value) }

module.exports = { ensure: ensure
                 , Assertion: Assertion

                 , internal: { make_error: make_error }
                 }<|endoftext|>


<commit_before>"use strict";
(function(window) {
    var config = {
      silent: false
    }
    var directives = {};
    var components = {};

    /**
    * Converts attributes into key-value pairs
    * @param {Node} node
    * @return {Object} Key-Value pairs of Attributes
    */
    var extractAttrs = function(node) {
      var attrs = {};
      if(!node.attributes) return attrs;
      var rawAttrs = node.attributes;
      for(var i = 0; i < rawAttrs.length; i++) {
        attrs[rawAttrs[i].name] = rawAttrs[i].value
      }

      return attrs;
    }

    /**
    * Compiles a template with given data
    * @param {String} template
    * @param {Object} data
    * @return {String} Template with data rendered
    */
    var compileTemplate = function(template, data) {
      var code = template,
          re = /{{([A-Za-z0-9_.\[\]]+)}}/gi;
      code.replace(re, function(match, p) {
        code = code.replace(match, "` + data." + p + " + `");
      });
      var compile = new Function("data", "var out = `" + code + "`; return out");
      var output = compile(data);
      return output;
    }

    /**
    * Gets Root Element
    * @param {String} html
    * @return {Node} Root Element
    */
    var getRootElement = function(html) {
      var dummy = document.createElement('div');
      dummy.innerHTML = html;
      return dummy.firstChild;
    }

    /**
    * Merges two Objects
    * @param {Object} obj
    * @param {Object} obj2
    * @return {Object} Merged Objects
    */
    function merge(obj, obj2) {
      for (var key in obj2) {
        if (obj2.hasOwnProperty(key)) obj[key] = obj2[key];
      }
      return obj;
    }

    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        var _hooks = opts.hooks || {created: function() {}, mounted: function() {}, updated: function() {}, destroyed: function() {}};
        var _destroyed = false;
        var self = this;
        this.$el = document.querySelector(_el);
        this.$components = merge(opts.components || {}, components);
        this.$dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.$dom.children);
            },
            configurable: true
        });

        /**
        * Logs a Message
        * @param {String} msg
        */
        this.log = function(msg) {
          if(!config.silent) console.log(msg);
        }

        /**
        * Throws an Error
        * @param {String} msg
        */
        this.error = function(msg) {
          console.log("Moon ERR: " + msg);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.$dom = vdom;
        }

        /**
        * Compiles all Components to HTML
        */
        this.compileComponents = function() {
          for(var componentName in this.$components) {
            var component = this.$components[componentName];
            var foundComponents = this.$el.getElementsByTagName(componentName);
            for(var i = 0; i < foundComponents.length; i++) {
              foundComponents[i].outerHTML = component.template;
            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          if(!_destroyed) this.build(this.$dom.children);
          if(_hooks.updated) {
            _hooks.updated();
          }
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Calls a method
        * @param {String} method
        */
        this.method = function(method) {
          _methods[method]();
        }

        this.destroy = function() {
          Object.defineProperty(this, '$data', {
            set: function(value) {
              _data = value;
            }
          });
          _destroyed = true;
          if(_hooks.destroyed) _hooks.destroyed();
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        directives["m-show"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.style.display = 'none';
          } else {
            el.style.display = 'block';
          }
        }

        directives["m-on"] = function(el, val, vdom) {
          var splitVal = val.split(":");
          var eventToCall = splitVal[0];
          var methodToCall = splitVal[1];
          el.addEventListener(eventToCall, function() {
            self.method(methodToCall);
          });
          el.removeAttribute("m-on");
          delete vdom.props["m-on"];
        }

        directives["m-model"] = function(el, val, vdom) {
          el.value = self.get(val);
          el.addEventListener("input", function() {
            self.set(val, el.value);
          });
          el.removeAttribute("m-model");
          delete vdom.props["m-model"];
        }

        directives["m-once"] = function(el, val, vdom) {
          vdom.val = el.textContent;
          for(var child in vdom.children) {
            vdom.children[child].val = compileTemplate(vdom.children[child].val, self.$data);
          }
        }

        directives["m-text"] = function(el, val, vdom) {
          el.textContent = val;
        }

        directives["m-html"] = function(el, val, vdom) {
          el.innerHTML = val;
        }

        directives["m-mask"] = function(el, val, vdom) {

        }

        // directives["m-for"] = function(el, val, vdom) {
        //   var splitVal = val.split(" in ");
        //   var alias = splitVal[0];
        //   var arr = self.get(splitVal[1]);
        //   var clone = el.cloneNode(true);
        //   var oldVal = vdom.val;
        //   var compilable = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[0]');
        //   el.innerHTML = compileTemplate(compilable, self.$data);
        //   for(var i = 1; i < arr.length; i++) {
        //     var newClone = clone.cloneNode(true);
        //     var compilable = oldVal.replace(new RegExp(alias, "gi"), splitVal[1] + '[' + i + ']');
        //     newClone.innerHTML = compileTemplate(compilable, self.$data);
        //     var parent = el.parentNode;
        //     parent.appendChild(newClone);
        //   }
        //   vdom.val = el.textContent;
        //   delete vdom.props["m-for"];
        // }

        /**
        * Builds the DOM With Data
        * @param {Array} children
        */
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  el.node.removeAttribute(prop);
                  directive(el.node, compiledProperty, el);
                }

                if(!directive) el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        /**
        * Initializes Moon
        */
        this.init = function() {
          this.log("======= Moon =======");
          if(_hooks.created) {
            _hooks.created();
          }
          this.compileComponents();
          this.createVirtualDOM(this.$el);
          this.build(this.$dom.children);
          if(_hooks.mounted) {
            _hooks.mounted();
          }
        }

        // Initialize 🎉
        this.init();
    }

    /**
    * Sets the Configuration of Moon
    * @param {Object} opts
    */
    Moon.config = function(opts) {
      if(opts.silent) {
        config.silent = opts.silent;
      }
    }

    /**
    * Runs an external Plugin
    * @param {Object} plugin
    */
    Moon.use = function(plugin) {
      plugin.init(Moon);
    }

    /**
    * Creates a Directive
    * @param {String} name
    * @param {Function} action
    */
    Moon.directive = function(name, action) {
      directives["m-" + name] = action;
    }

    /**
    * Creates a Component
    * @param {String} name
    * @param {Function} action
    */
    Moon.component = function(name, action) {
      components[name] = action;
    }

    /**
    * Makes an AJAX Request
    * @param {String} method
    * @param {String} url
    * @param {Object} params
    * @param {Function} cb
    */
    Moon.ajax = function(method, url, params, cb) {
      var xmlHttp = new XMLHttpRequest();
      method = method.toUpperCase();
      if(typeof params === "function") {
        cb = params;
      }
      var urlParams = "?";
      if(method === "POST") {
        http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        for(var param in params) {
          urlParams += param + "=" + params[param] + "&";
        }
      }
      xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        cb(JSON.parse(xmlHttp.responseText));
      }
      xmlHttp.open(method, url, true);
      xmlHttp.send(method === "POST" ? urlParams : null);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<commit_msg>don't iterate through props<commit_after>"use strict";
(function(window) {
    var config = {
      silent: false
    }
    var directives = {};
    var components = {};

    /**
    * Converts attributes into key-value pairs
    * @param {Node} node
    * @return {Object} Key-Value pairs of Attributes
    */
    var extractAttrs = function(node) {
      var attrs = {};
      if(!node.attributes) return attrs;
      var rawAttrs = node.attributes;
      for(var i = 0; i < rawAttrs.length; i++) {
        attrs[rawAttrs[i].name] = rawAttrs[i].value
      }

      return attrs;
    }

    /**
    * Compiles a template with given data
    * @param {String} template
    * @param {Object} data
    * @return {String} Template with data rendered
    */
    var compileTemplate = function(template, data) {
      var code = template,
          re = /{{([A-Za-z0-9_.\[\]]+)}}/gi;
      code.replace(re, function(match, p) {
        code = code.replace(match, "` + data." + p + " + `");
      });
      var compile = new Function("data", "var out = `" + code + "`; return out");
      var output = compile(data);
      return output;
    }

    /**
    * Gets Root Element
    * @param {String} html
    * @return {Node} Root Element
    */
    var getRootElement = function(html) {
      var dummy = document.createElement('div');
      dummy.innerHTML = html;
      return dummy.firstChild;
    }

    /**
    * Merges two Objects
    * @param {Object} obj
    * @param {Object} obj2
    * @return {Object} Merged Objects
    */
    function merge(obj, obj2) {
      for (var key in obj2) {
        if (obj2.hasOwnProperty(key)) obj[key] = obj2[key];
      }
      return obj;
    }

    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        var _hooks = opts.hooks || {created: function() {}, mounted: function() {}, updated: function() {}, destroyed: function() {}};
        var _destroyed = false;
        var self = this;
        this.$el = document.querySelector(_el);
        this.$components = merge(opts.components || {}, components);
        this.$dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.$dom.children);
            },
            configurable: true
        });

        /**
        * Logs a Message
        * @param {String} msg
        */
        this.log = function(msg) {
          if(!config.silent) console.log(msg);
        }

        /**
        * Throws an Error
        * @param {String} msg
        */
        this.error = function(msg) {
          console.log("Moon ERR: " + msg);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.$dom = vdom;
        }

        /**
        * Compiles all Components to HTML
        */
        this.compileComponents = function() {
          for(var componentName in this.$components) {
            var component = this.$components[componentName];
            var foundComponents = this.$el.getElementsByTagName(componentName);
            for(var i = 0; i < foundComponents.length; i++) {
              var foundComponent = foundComponents[i];
              foundComponent.outerHTML = component.template;

            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          if(!_destroyed) this.build(this.$dom.children);
          if(_hooks.updated) {
            _hooks.updated();
          }
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Calls a method
        * @param {String} method
        */
        this.method = function(method) {
          _methods[method]();
        }

        this.destroy = function() {
          Object.defineProperty(this, '$data', {
            set: function(value) {
              _data = value;
            }
          });
          _destroyed = true;
          if(_hooks.destroyed) _hooks.destroyed();
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        directives["m-show"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.style.display = 'none';
          } else {
            el.style.display = 'block';
          }
        }

        directives["m-on"] = function(el, val, vdom) {
          var splitVal = val.split(":");
          var eventToCall = splitVal[0];
          var methodToCall = splitVal[1];
          el.addEventListener(eventToCall, function() {
            self.method(methodToCall);
          });
          el.removeAttribute("m-on");
          delete vdom.props["m-on"];
        }

        directives["m-model"] = function(el, val, vdom) {
          el.value = self.get(val);
          el.addEventListener("input", function() {
            self.set(val, el.value);
          });
          el.removeAttribute("m-model");
          delete vdom.props["m-model"];
        }

        directives["m-once"] = function(el, val, vdom) {
          vdom.val = el.textContent;
          for(var child in vdom.children) {
            vdom.children[child].val = compileTemplate(vdom.children[child].val, self.$data);
          }
        }

        directives["m-text"] = function(el, val, vdom) {
          el.textContent = val;
        }

        directives["m-html"] = function(el, val, vdom) {
          el.innerHTML = val;
        }

        directives["m-mask"] = function(el, val, vdom) {

        }

        // directives["m-for"] = function(el, val, vdom) {
        //   var splitVal = val.split(" in ");
        //   var alias = splitVal[0];
        //   var arr = self.get(splitVal[1]);
        //   var clone = el.cloneNode(true);
        //   var oldVal = vdom.val;
        //   var compilable = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[0]');
        //   el.innerHTML = compileTemplate(compilable, self.$data);
        //   for(var i = 1; i < arr.length; i++) {
        //     var newClone = clone.cloneNode(true);
        //     var compilable = oldVal.replace(new RegExp(alias, "gi"), splitVal[1] + '[' + i + ']');
        //     newClone.innerHTML = compileTemplate(compilable, self.$data);
        //     var parent = el.parentNode;
        //     parent.appendChild(newClone);
        //   }
        //   vdom.val = el.textContent;
        //   delete vdom.props["m-for"];
        // }

        /**
        * Builds the DOM With Data
        * @param {Array} children
        */
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  el.node.removeAttribute(prop);
                  directive(el.node, compiledProperty, el);
                }

                if(!directive) el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        /**
        * Initializes Moon
        */
        this.init = function() {
          this.log("======= Moon =======");
          if(_hooks.created) {
            _hooks.created();
          }
          this.compileComponents();
          this.createVirtualDOM(this.$el);
          this.build(this.$dom.children);
          if(_hooks.mounted) {
            _hooks.mounted();
          }
        }

        // Initialize 🎉
        this.init();
    }

    /**
    * Sets the Configuration of Moon
    * @param {Object} opts
    */
    Moon.config = function(opts) {
      if(opts.silent) {
        config.silent = opts.silent;
      }
    }

    /**
    * Runs an external Plugin
    * @param {Object} plugin
    */
    Moon.use = function(plugin) {
      plugin.init(Moon);
    }

    /**
    * Creates a Directive
    * @param {String} name
    * @param {Function} action
    */
    Moon.directive = function(name, action) {
      directives["m-" + name] = action;
    }

    /**
    * Creates a Component
    * @param {String} name
    * @param {Function} action
    */
    Moon.component = function(name, action) {
      components[name] = action;
    }

    /**
    * Makes an AJAX Request
    * @param {String} method
    * @param {String} url
    * @param {Object} params
    * @param {Function} cb
    */
    Moon.ajax = function(method, url, params, cb) {
      var xmlHttp = new XMLHttpRequest();
      method = method.toUpperCase();
      if(typeof params === "function") {
        cb = params;
      }
      var urlParams = "?";
      if(method === "POST") {
        http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        for(var param in params) {
          urlParams += param + "=" + params[param] + "&";
        }
      }
      xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        cb(JSON.parse(xmlHttp.responseText));
      }
      xmlHttp.open(method, url, true);
      xmlHttp.send(method === "POST" ? urlParams : null);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<|endoftext|>


<commit_before>"use strict";
(function(window) {
    var config = {
      silent: false
    }

    /**
    * Converts attributes into key-value pairs
    * @param {Node} node
    * @return {Object} Key-Value pairs of Attributes
    */
    var extractAttrs = function(node) {
      var attrs = {};
      if(!node.attributes) return attrs;
      var rawAttrs = node.attributes;
      for(var i = 0; i < rawAttrs.length; i++) {
        attrs[rawAttrs[i].name] = rawAttrs[i].value
      }

      return attrs;
    }

    /**
    * Compiles a template with given data
    * @param {String} template
    * @param {Object} data
    * @return {String} Template with data rendered
    */
    var compileTemplate = function(template, data) {
      var code = template,
          re = /{{([A-Za-z0-9_.\[\]]+)}}/gi;
      code.replace(re, function(match, p) {
        code = code.replace(match, "` + data." + p + " + `");
      });
      var compile = new Function("data", "var out = `" + code + "`; return out");
      return compile(data);
    }

    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        var directives = {};
        var self = this;
        this.$el = document.querySelector(_el);
        this.components = opts.components;
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        /**
        * Logs a Message
        * @param {String} msg
        */
        this.log = function(msg) {
          if(!config.silent) console.log(msg);
        }

        /**
        * Throws an Error
        * @param {String} msg
        */
        this.error = function(msg) {
          console.log("Moon ERR: " + msg);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        /**
        * Turns Custom Components into their Corresponding Templates
        */
        this.componentsToHTML = function() {
          for(var component in this.components) {
            var componentsFound = document.getElementsByTagName(component);
            componentsFound = Array.prototype.slice.call(componentsFound);
            for(var i = 0; i < componentsFound.length; i++) {
              var componentFound = componentsFound[i];
              var componentProps = extractAttrs(componentFound);
              var componentDummy = document.createElement('div');
              componentDummy.innerHTML = this.components[component].template;
              componentDummy = componentDummy.firstChild;

              for(var attr in componentProps) {
                componentDummy.setAttribute(attr, componentProps[attr]);
              }

              componentFound.outerHTML = compileTemplate(componentDummy.outerHTML, {props:componentProps});
            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Makes an AJAX Request
        * @param {String} method
        * @param {String} url
        * @param {Object} params
        * @param {Function} cb
        */
        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        /**
        * Calls a method
        * @param {String} method
        */
        this.method = function(method) {
          _methods[method]();
        }

        // Directive Initialization
        this.directive = function(name, action) {
          directives["m-" + name] = action;
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        directives["m-on"] = function(el, val, vdom) {
          var splitVal = val.split(":");
          var eventToCall = splitVal[0];
          var methodToCall = splitVal[1];
          el.addEventListener(eventToCall, function() {
            self.method(methodToCall);
          });
          el.removeAttribute("m-on");
          delete vdom.props["m-on"];
        }

        directives["m-model"] = function(el, val, vdom) {
          el.value = self.get(val);
          el.addEventListener("input", function() {
            self.set(val, el.value);
          });
          el.removeAttribute("m-model");
          delete vdom.props["m-model"];
        }

        directives["m-once"] = function(el, val, vdom) {
          vdom.val = el.textContent;
          for(var child in vdom.children) {
            vdom.children[child].val = compileTemplate(vdom.children[child].val, self.$data);
          }
        }

        // directives["m-for"] = function(el, val, vdom) {
        //   var splitVal = val.split(" in ");
        //   var alias = splitVal[0];
        //   var arr = self.get(splitVal[1]);
        //   var clone = el.cloneNode(true);
        //   var compilable = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[0]');
        //   el.innerHTML = compilable;
        //   for(var i = 1; i < arr.length; i++) {
        //     var newClone = clone.cloneNode(true);
        //     newClone.innerHTML = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[' + i + ']');
        //     var parent = el.parentNode;
        //     parent.appendChild(newClone);
        //   }
        //   vdom.val = el.textContent;
        //   vdom.children = self.recursiveChildren();
        //   delete vdom.props["m-for"];
        // }

        /**
        * Builds the DOM With Data
        * @param {Array} children
        */
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  directive(el.node, compiledProperty, el);
                }

                el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        /**
        * Initializes Moon
        */
        this.init = function() {
          this.log("======= Moon =======");
          this.componentsToHTML();
          this.createVirtualDOM(this.$el);
          this.build(this.dom.children);
        }

        // Initialize 🎉
        this.init();
    }

    /**
    * Sets the Configuration of Moon
    * @param {Object} opts
    */
    Moon.config = function(opts) {
      if(opts.silent) {
        config.silent = opts.silent;
      }
    }

    /**
    * Runs an external Plugin
    * @param {Object} plugin
    */
    Moon.use = function(plugin) {
      plugin.init(Moon);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<commit_msg>don't compile with props<commit_after>"use strict";
(function(window) {
    var config = {
      silent: false
    }

    /**
    * Converts attributes into key-value pairs
    * @param {Node} node
    * @return {Object} Key-Value pairs of Attributes
    */
    var extractAttrs = function(node) {
      var attrs = {};
      if(!node.attributes) return attrs;
      var rawAttrs = node.attributes;
      for(var i = 0; i < rawAttrs.length; i++) {
        attrs[rawAttrs[i].name] = rawAttrs[i].value
      }

      return attrs;
    }

    /**
    * Compiles a template with given data
    * @param {String} template
    * @param {Object} data
    * @return {String} Template with data rendered
    */
    var compileTemplate = function(template, data) {
      var code = template,
          re = /{{([A-Za-z0-9_.\[\]]+)}}/gi;
      code.replace(re, function(match, p) {
        code = code.replace(match, "` + data." + p + " + `");
      });
      var compile = new Function("data", "var out = `" + code + "`; return out");
      return compile(data);
    }

    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        var directives = {};
        var self = this;
        this.$el = document.querySelector(_el);
        this.components = opts.components;
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        /**
        * Logs a Message
        * @param {String} msg
        */
        this.log = function(msg) {
          if(!config.silent) console.log(msg);
        }

        /**
        * Throws an Error
        * @param {String} msg
        */
        this.error = function(msg) {
          console.log("Moon ERR: " + msg);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        /**
        * Turns Custom Components into their Corresponding Templates
        */
        this.componentsToHTML = function() {
          for(var component in this.components) {
            var componentsFound = document.getElementsByTagName(component);
            componentsFound = Array.prototype.slice.call(componentsFound);
            for(var i = 0; i < componentsFound.length; i++) {
              var componentFound = componentsFound[i];
              var componentProps = extractAttrs(componentFound);
              var componentDummy = document.createElement('div');
              componentDummy.innerHTML = this.components[component].template;
              componentDummy = componentDummy.firstChild;

              for(var attr in componentProps) {
                componentDummy.setAttribute(attr, componentProps[attr]);
              }

              componentFound.outerHTML = componentDummy.outerHTML;
            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Makes an AJAX Request
        * @param {String} method
        * @param {String} url
        * @param {Object} params
        * @param {Function} cb
        */
        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        /**
        * Calls a method
        * @param {String} method
        */
        this.method = function(method) {
          _methods[method]();
        }

        // Directive Initialization
        this.directive = function(name, action) {
          directives["m-" + name] = action;
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        directives["m-on"] = function(el, val, vdom) {
          var splitVal = val.split(":");
          var eventToCall = splitVal[0];
          var methodToCall = splitVal[1];
          el.addEventListener(eventToCall, function() {
            self.method(methodToCall);
          });
          el.removeAttribute("m-on");
          delete vdom.props["m-on"];
        }

        directives["m-model"] = function(el, val, vdom) {
          el.value = self.get(val);
          el.addEventListener("input", function() {
            self.set(val, el.value);
          });
          el.removeAttribute("m-model");
          delete vdom.props["m-model"];
        }

        directives["m-once"] = function(el, val, vdom) {
          vdom.val = el.textContent;
          for(var child in vdom.children) {
            vdom.children[child].val = compileTemplate(vdom.children[child].val, self.$data);
          }
        }

        // directives["m-for"] = function(el, val, vdom) {
        //   var splitVal = val.split(" in ");
        //   var alias = splitVal[0];
        //   var arr = self.get(splitVal[1]);
        //   var clone = el.cloneNode(true);
        //   var compilable = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[0]');
        //   el.innerHTML = compilable;
        //   for(var i = 1; i < arr.length; i++) {
        //     var newClone = clone.cloneNode(true);
        //     newClone.innerHTML = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[' + i + ']');
        //     var parent = el.parentNode;
        //     parent.appendChild(newClone);
        //   }
        //   vdom.val = el.textContent;
        //   vdom.children = self.recursiveChildren();
        //   delete vdom.props["m-for"];
        // }

        /**
        * Builds the DOM With Data
        * @param {Array} children
        */
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  directive(el.node, compiledProperty, el);
                }

                el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        /**
        * Initializes Moon
        */
        this.init = function() {
          this.log("======= Moon =======");
          this.componentsToHTML();
          this.createVirtualDOM(this.$el);
          this.build(this.dom.children);
        }

        // Initialize 🎉
        this.init();
    }

    /**
    * Sets the Configuration of Moon
    * @param {Object} opts
    */
    Moon.config = function(opts) {
      if(opts.silent) {
        config.silent = opts.silent;
      }
    }

    /**
    * Runs an external Plugin
    * @param {Object} plugin
    */
    Moon.use = function(plugin) {
      plugin.init(Moon);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<|endoftext|>


<commit_before>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        this.$el = document.getElementById(_el);
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        // Utility: Raw Attributes -> Key Value Pairs
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        // Utility: Create Elements Recursively For all Children
        var recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        // Utility: Create Virtual DOM Instance
        var createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        // Build the DOM with $data
        this.build = function(children) {
          var tempData = this.$data;
          for(var i = 0; i < children.length; i++) {
            var el = children[i];
            if(el.type === "#text") {
              var tmpVal = el.val;
              el.val.replace(/{{(\w+)}}/gi, function(match, p1) {
                var newVal = tmpVal.replace(match, tempData[p1]);
                el.node.textContent = newVal;
                tmpVal = newVal;
              });
            } else {
                for(var prop in el.props) {
                  var tmpVal = el.props[prop];
                  el.props[prop].replace(/{{(\w+)}}/gi, function(match, p1) {
                    var dataToAdd = tempData[p1];
                    var newVal = tmpVal.replace(new RegExp(match, "gi"), dataToAdd);
                    el.node.setAttribute(prop, newVal);
                    tmpVal = newVal;
                  });
                }
                this.build(el.children);
            }
          }
        }

        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        this.get = function(key) {
          return this.$data[key];
        }

        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        this.method = function(method) {
          _methods[method]();
        }

        createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<commit_msg>comment create element<commit_after>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        this.$el = document.getElementById(_el);
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        // Utility: Raw Attributes -> Key Value Pairs
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        // Utility: Create Elements Recursively For all Children
        var recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        // Utility: Create Virtual DOM Instance
        var createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        // Build the DOM with $data
        this.build = function(children) {
          var tempData = this.$data;
          for(var i = 0; i < children.length; i++) {
            var el = children[i];
            if(el.type === "#text") {
              var tmpVal = el.val;
              el.val.replace(/{{(\w+)}}/gi, function(match, p1) {
                var newVal = tmpVal.replace(match, tempData[p1]);
                el.node.textContent = newVal;
                tmpVal = newVal;
              });
            } else {
                for(var prop in el.props) {
                  var tmpVal = el.props[prop];
                  el.props[prop].replace(/{{(\w+)}}/gi, function(match, p1) {
                    var dataToAdd = tempData[p1];
                    var newVal = tmpVal.replace(new RegExp(match, "gi"), dataToAdd);
                    el.node.setAttribute(prop, newVal);
                    tmpVal = newVal;
                  });
                }
                this.build(el.children);
            }
          }
        }

        // Create Virtual DOM Object from Params
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        this.get = function(key) {
          return this.$data[key];
        }

        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        this.method = function(method) {
          _methods[method]();
        }

        createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<|endoftext|>


<commit_before>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        this.$el = document.getElementById(_el);
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        // Utility: Raw Attributes -> Key Value Pairs
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        // Utility: Compile a template and return html
        var compileTemplate = function(template, data) {
          var code = template,
              re = /{{(\w.+)}}/gi;
          code.replace(re, function(match, p) {
            code = code.replace(match, "` + data." + p + " + `");
          });
          var compile = new Function("data", "var out = `" + code + "`; return out");
          return compile(data);
        }

        // Utility: Create Elements Recursively For all Children
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        // Utility: Create Virtual DOM Instance
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        // Build the DOM with $data
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            }

            this.build(this.el.children);
          }
        }

        // Create Virtual DOM Object from Params
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        // Set any value in $data
        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        // Get any value in $data
        this.get = function(key) {
          return this.$data[key];
        }

        // Make AJAX GET/POST requests
        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        // Call a method defined in _methods
        this.method = function(method) {
          _methods[method]();
        }

        // Initialize
        this.createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<commit_msg>use el, not prop<commit_after>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        this.$el = document.getElementById(_el);
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        // Utility: Raw Attributes -> Key Value Pairs
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        // Utility: Compile a template and return html
        var compileTemplate = function(template, data) {
          var code = template,
              re = /{{(\w.+)}}/gi;
          code.replace(re, function(match, p) {
            code = code.replace(match, "` + data." + p + " + `");
          });
          var compile = new Function("data", "var out = `" + code + "`; return out");
          return compile(data);
        }

        // Utility: Create Elements Recursively For all Children
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        // Utility: Create Virtual DOM Instance
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        // Build the DOM with $data
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            }

            this.build(el.children);
          }
        }

        // Create Virtual DOM Object from Params
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        // Set any value in $data
        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        // Get any value in $data
        this.get = function(key) {
          return this.$data[key];
        }

        // Make AJAX GET/POST requests
        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        // Call a method defined in _methods
        this.method = function(method) {
          _methods[method]();
        }

        // Initialize
        this.createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<|endoftext|>


<commit_before>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        this.$el = document.getElementById(_el);
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        // Utility: Raw Attributes -> Key Value Pairs
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        // Utility: Create Elements Recursively For all Children
        var recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        // Utility: Create Virtual DOM Instance
        var createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        // Build the DOM with $data
        this.build = function(children) {
          var tempData = this.$data;
          for(var i = 0; i < children.length; i++) {
            var el = children[i];
            if(el.type === "#text") {
              var tmpVal = el.val;
              el.val.replace(/{{(\w+)}}/gi, function(match, p1) {
                var newVal = tmpVal.replace(match, tempData[p1]);
                el.node.textContent = newVal;
                tmpVal = newVal;
              });
            } else {
                for(var prop in el.props) {
                  var tmpVal = el.props[prop];
                  el.props[prop].replace(/{{(\w+)}}/gi, function(match, p1) {
                    var dataToAdd = tempData[p1];
                    var newVal = tmpVal.replace(new RegExp(match, "gi"), dataToAdd);
                    el.node.setAttribute(prop, newVal);
                    tmpVal = newVal;
                  });
                }
                this.build(el.children);
            }
          }
        }

        // Create Virtual DOM Object from Params
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        this.get = function(key) {
          return this.$data[key];
        }

        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        this.method = function(method) {
          _methods[method]();
        }

        createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<commit_msg>get/set comments<commit_after>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        this.$el = document.getElementById(_el);
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        // Utility: Raw Attributes -> Key Value Pairs
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        // Utility: Create Elements Recursively For all Children
        var recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        // Utility: Create Virtual DOM Instance
        var createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        // Build the DOM with $data
        this.build = function(children) {
          var tempData = this.$data;
          for(var i = 0; i < children.length; i++) {
            var el = children[i];
            if(el.type === "#text") {
              var tmpVal = el.val;
              el.val.replace(/{{(\w+)}}/gi, function(match, p1) {
                var newVal = tmpVal.replace(match, tempData[p1]);
                el.node.textContent = newVal;
                tmpVal = newVal;
              });
            } else {
                for(var prop in el.props) {
                  var tmpVal = el.props[prop];
                  el.props[prop].replace(/{{(\w+)}}/gi, function(match, p1) {
                    var dataToAdd = tempData[p1];
                    var newVal = tmpVal.replace(new RegExp(match, "gi"), dataToAdd);
                    el.node.setAttribute(prop, newVal);
                    tmpVal = newVal;
                  });
                }
                this.build(el.children);
            }
          }
        }

        // Create Virtual DOM Object from Params
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        // Set any value in $data
        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        // Get any value in $data
        this.get = function(key) {
          return this.$data[key];
        }

        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        this.method = function(method) {
          _methods[method]();
        }

        createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var collect = require('../lib/collect');
var include = require('../lib/include');
var helpers = require('./helpers.js');

exports.CoreError = require('./error');

exports.config = function($$) {
    return {
        // Set config value
        set(path, value) {
            var parts = path.trim().split('.');
            var part;
            var config = $$.config;
            while (parts.length > 1) {
                part = parts.shift();
                if (part in config === false || !helpers.isPlainObject(config[part])) {
                    config[part] = {};
                }
                config = config[part];
            }
            config[parts[0]] = value;
            return this;
        },
        // Add values to path
        add(path, value) {
            if (typeof value !== 'object') {
                throw new Error('Value should be an object');
            }

            var parts = path.trim().split('.');
            var part;
            var config = $$.config;
            while (parts.length > 0) {
                part = parts.shift();
                if (part in config === false || !helpers.isPlainObject(config[part])) {
                    config[part] = {};
                }
                config = config[part];
            }

            helpers.merge(config, value);
            return this;
        },
        defaults(path, values) {
            if (typeof values !== 'object') {
                throw new Error('Default values should be an object');
            }

            var item = this.get(path);
            if (typeof item !== 'object') {
                item = {};
            }

            Object.getOwnPropertyNames(values).forEach(function(name){
                if (item.hasOwnProperty(name)) {
                    return;
                }
                item[name] = values[name];
            });

            this.set(path, item);
            return item;
        },
        // Get config value, or alternative value
        get(path, alt) {
            var parts = path.trim().split('.');
            var part, result;
            var config = $$.config;
            while (parts.length > 1) {
                part = parts.shift();
                if (part in config && typeof config[part] === 'object') {
                    config = config[part];
                } else {
                    return;
                }
            }

            result = config[parts[0]];
            if (alt && typeof result === 'undefined') {
                result = alt;
            }
            return result;
        },
        all() {
            return $$.config;
        }
    };
};

// Common include scope

exports.includeScope = function(config){
    return include.createScope({
        config : config
    });
};

// Application controllers

exports.controllersOptions = function(config){
    config.add('controllers', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), '/controllers')
    });
    return config.get('controllers');
};

exports.controllers = function(controllersOptions, includeScope) {
    return collect('*-controller.js', controllersOptions.dir, function(file, basename, ext, dir, root){
        var controller = include(root + '/' + file, includeScope);
        var name = basename
            .replace(/-controller$/, '')
            .replace(/\W(.)/g, (m, v) => v.toUpperCase());
        includeScope[basename + 'Controller'] = controller;
        return {
           key: name,
           value: controller
        };
    });
};

exports.eventsOptions = function(config){
    config.add('events', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), '/events')
    });
    return config.get('events');
};

exports.events = function(eventsOptions, includeScope) {
    return collect('*-events.js', eventsOptions.dir, function(file, basename, ext, dir, root){
        var event = include(root + '/' + file, includeScope);
        var name = basename
            .replace(/-events$/, '')
            .replace(/\W(.)/g, (m, v) => v.toUpperCase());

        includeScope[name + 'Events'] = event;

        return {
            key: name,
            value: event
        };
    });
};

// Application services

exports.servicesOptions = function(config){
    return {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), '/services')
    };
};

exports.services = function($$, servicesOptions, includeScope) {
    var names = [];
    var services = collect('*-service.js', servicesOptions.dir, function(file, basename, ext, dir, root) {
        var moduleExports = include(root + '/' + file, includeScope);

        if (typeof moduleExports !== 'function') {
            return;
        }

        var moduleName = basename.replace(/(^|\W)(.)/g, (m,p,v) => v.toUpperCase());

        names.push(moduleName);
        $$.factory(moduleName, moduleExports);

        return {key: moduleName, value : moduleExports};
    });

    names.forEach(function(name){

        Object.defineProperty(includeScope, name, {
            get : function() {
                return $$.get(name);
            }
        });
    });

    return services;
};

exports.modelsOptions = function(config){
    return config.defaults('models', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), '/models')
    });
};

exports.models = function(modelsOptions, includeScope) {
    var models = {};

    collect('*.js', modelsOptions.dir, function(file, basename, ext, dir, root){
        var moduleModels = include(root + '/' + file, includeScope);
        var name, value;

        for (name in moduleModels) {
            if (! moduleModels.hasOwnProperty(name)) {
                continue;
            }

            value = moduleModels[name];

            if (value && (typeof value === 'function' || typeof value === 'object')) {
                models[name] = value;
                includeScope[name] = value;
            }
        }
    });

    return models;
};

exports.responsesOptions = function(config) {
    return config.defaults('responses', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), '/responces')
    });
};

exports.responses = function(config, responsesOptions, includeScope) {
    var options = config.get('responses');
    var dir = path.resolve(config.get('dir'), options.dir);
    return collect('*.js', dir, function(file, basename){
        return {
            key : basename,
            value : include(dir + '/' + file, includeScope)
        };
    });
};

// Policies options

exports.policiesOptions = function(config) {
    return config.defaults('policies', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), '/policies')
    });
};

// Policies loader
exports.policies = function(policiesOptions, config, includeScope) {
    var dir = path.resolve(config.get('dir'), policiesOptions.dir);
    return collect('*.js', dir, function(file, basename){
        return {
            key : basename,
            value : include(dir + '/' + file, includeScope)
        };
    });
};

// Autoload modules options

exports.modulesOptions = function(config) {
    return config.defaults('modules', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), '/modules')
    });
};

// Autoload modules

exports.modules = function($$, modulesOptions, config) {
    var dir = path.resolve(config.get('dir'), modulesOptions.dir);
    return collect('*.js', dir, function(file, basename){
        var module = require(dir + '/' + file);
        $$.module(module);
        return {
            key : basename,
            value : module
        };
    });
};

// Self initialization

exports.init = function($$, config) {
    // Initialize dependent modules. Uses config option `init`.
    return config.get('init', []).map(function(name){
        $$.get(name);
        return name;
    });
};
<commit_msg>Move core modules configuration to core namespace<commit_after>'use strict';

var path = require('path');
var collect = require('../lib/collect');
var include = require('../lib/include');
var helpers = require('./helpers.js');

exports.CoreError = require('./error');

exports.config = function($$) {
    return {
        // Set config value
        set(path, value) {
            var parts = path.trim().split('.');
            var part;
            var config = $$.config;
            while (parts.length > 1) {
                part = parts.shift();
                if (part in config === false || !helpers.isPlainObject(config[part])) {
                    config[part] = {};
                }
                config = config[part];
            }
            config[parts[0]] = value;
            return this;
        },
        // Add values to path
        add(path, value) {
            if (typeof value !== 'object') {
                throw new Error('Value should be an object');
            }

            var parts = path.trim().split('.');
            var part;
            var config = $$.config;
            while (parts.length > 0) {
                part = parts.shift();
                if (part in config === false || !helpers.isPlainObject(config[part])) {
                    config[part] = {};
                }
                config = config[part];
            }

            helpers.merge(config, value);
            return this;
        },
        defaults(path, values) {
            if (typeof values !== 'object') {
                throw new Error('Default values should be an object');
            }

            var item = this.get(path);
            if (typeof item !== 'object') {
                item = {};
            }

            Object.getOwnPropertyNames(values).forEach(function(name){
                if (item.hasOwnProperty(name)) {
                    return;
                }
                item[name] = values[name];
            });

            this.set(path, item);
            return item;
        },
        // Get config value, or alternative value
        get(path, alt) {
            var parts = path.trim().split('.');
            var part, result;
            var config = $$.config;
            while (parts.length > 1) {
                part = parts.shift();
                if (part in config && typeof config[part] === 'object') {
                    config = config[part];
                } else {
                    return;
                }
            }

            result = config[parts[0]];
            if (alt && typeof result === 'undefined') {
                result = alt;
            }
            return result;
        },
        all() {
            return $$.config;
        }
    };
};

// Common include scope

exports.includeScope = function(config){
    return include.createScope({
        config : config
    });
};

// Application controllers

exports.controllersOptions = function(config){
    return config.defaults('core.controllers', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), 'controllers')
    });
};

exports.controllers = function(controllersOptions, includeScope) {
    return collect('*-controller.js', controllersOptions.dir, function(file, basename, ext, dir, root){
        var controller = include(root + '/' + file, includeScope);
        var name = basename
            .replace(/-controller$/, '')
            .replace(/\W(.)/g, (m, v) => v.toUpperCase());
        includeScope[basename + 'Controller'] = controller;
        return {
           key: name,
           value: controller
        };
    });
};

exports.eventsOptions = function(config){
    return config.defaults('core.events', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), 'events')
    });
};

exports.events = function(eventsOptions, includeScope) {
    return collect('*-events.js', eventsOptions.dir, function(file, basename, ext, dir, root){
        var event = include(root + '/' + file, includeScope);
        var name = basename
            .replace(/-events$/, '')
            .replace(/\W(.)/g, (m, v) => v.toUpperCase());

        includeScope[name + 'Events'] = event;

        return {
            key: name,
            value: event
        };
    });
};

// Application services

exports.servicesOptions = function(config){
    return config.defaults('core.services', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), 'services')
    });
};

exports.services = function($$, servicesOptions, includeScope) {
    var names = [];
    var services = collect('*-service.js', servicesOptions.dir, function(file, basename, ext, dir, root) {
        var moduleExports = include(root + '/' + file, includeScope);

        if (typeof moduleExports !== 'function') {
            return;
        }

        var moduleName = basename.replace(/(^|\W)(.)/g, (m,p,v) => v.toUpperCase());

        names.push(moduleName);
        $$.factory(moduleName, moduleExports);

        return {key: moduleName, value : moduleExports};
    });

    names.forEach(function(name){

        Object.defineProperty(includeScope, name, {
            get : function() {
                return $$.get(name);
            }
        });
    });

    return services;
};

exports.modelsOptions = function(config){
    return config.defaults('core.models', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), 'models')
    });
};

exports.models = function(modelsOptions, includeScope) {
    var models = {};

    collect('*.js', modelsOptions.dir, function(file, basename, ext, dir, root){
        var moduleModels = include(root + '/' + file, includeScope);
        var name, value;

        for (name in moduleModels) {
            if (! moduleModels.hasOwnProperty(name)) {
                continue;
            }

            value = moduleModels[name];

            if (value && (typeof value === 'function' || typeof value === 'object')) {
                models[name] = value;
                includeScope[name] = value;
            }
        }
    });

    return models;
};

exports.responsesOptions = function(config) {
    return config.defaults('core.responses', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), 'responces')
    });
};

exports.responses = function(config, responsesOptions, includeScope) {
    var options = config.get('core.responses');
    var dir = path.resolve(config.get('dir'), options.dir);
    return collect('*.js', dir, function(file, basename){
        return {
            key : basename,
            value : include(dir + '/' + file, includeScope)
        };
    });
};

// Policies options

exports.policiesOptions = function(config) {
    return config.defaults('core.policies', {
        dir : path.join(config.get('dir'), config.get('apiDir', 'api'), 'policies')
    });
};

// Policies loader
exports.policies = function(policiesOptions, config, includeScope) {
    var dir = path.resolve(config.get('dir'), policiesOptions.dir);
    return collect('*.js', dir, function(file, basename){
        return {
            key : basename,
            value : include(dir + '/' + file, includeScope)
        };
    });
};

// Autoload modules options

exports.modulesOptions = function(config) {
    return config.defaults('core.modules', {
        dir : path.join(config.get('dir'), 'modules')
    });
};

// Autoload modules

exports.modules = function($$, modulesOptions, config) {
    var dir = path.resolve(config.get('dir'), modulesOptions.dir);
    return collect('*.js', dir, function(file, basename){
        var module = require(dir + '/' + file);
        $$.module(module);
        return {
            key : basename,
            value : module
        };
    });
};

// Self initialization

exports.init = function($$, config) {
    // Initialize dependent modules. Uses config option `init`.
    return config.get('init', []).map(function(name){
        $$.get(name);
        return name;
    });
};
<|endoftext|>