<commit_before>// mktemp Copyright(c) 2013 sasa+1
// https://github.com/sasaplus1/mktemp
// Released under the MIT License.

var fs = require('fs'),
    mkrand = require('./mkrand');

function createUniqueName(template, callback) {
  var filename = mkrand(template);

  fs.exists(filename, function(exists) {
    if (exists) {
      createUniqueName(template, callback);
      return;
    }

    callback(null, filename);
  });
}

function createUniqueNameSync(template) {
  var filename;

  do {
    filename = mkrand(template);
  } while (fs.existsSync(filename));

  return filename;
}

function createFile(template, callback) {
  createUniqueName(template, function(err, filename) {
    if (err) {
      callback(err);
      return;
    }

    fs.open(filename, 'ax+', 384 /*=0600*/, function(err, fd) {
      if (err) {
        callback(err);
        return;
      }

      fs.close(fd, function(err) {
        callback(err, filename);
      });
    });
  });
}

function createFileSync(template) {
  var filename = createUniqueNameSync(template),
      fd = fs.openSync(filename, 'ax+', 384 /*=0600*/);

  fs.closeSync(fd);

  return filename;
}

function createDir(template, mode, callback) {
  if (typeof mode === 'function' && callback === void 0) {
    callback = mode;
    mode = null;
  }

  createUniqueName(template, function(err, dirname){
    if(err) { callback(err); return; }
    fs.mkdir(dirname, mode, function(err) {
      callback(err, dirname);
    });
  });
}

function createDirSync(template, mode) {
  var dirname = createUniqueNameSync(template);
  fs.mkdirSync(dirname, mode);
  return dirname;
}

module.exports = {
  createFile: createFile,
  createFileSync: createFileSync,
  createDir: createDir,
  createDirSync: createDirSync
};
<commit_msg>ディレクトリを生成する際にパーミッションを特定の値で指定するように<commit_after>// mktemp Copyright(c) 2013 sasa+1
// https://github.com/sasaplus1/mktemp
// Released under the MIT License.

var fs = require('fs'),
    mkrand = require('./mkrand');

function createUniqueName(template, callback) {
  var filename = mkrand(template);

  fs.exists(filename, function(exists) {
    if (exists) {
      createUniqueName(template, callback);
      return;
    }

    callback(null, filename);
  });
}

function createUniqueNameSync(template) {
  var filename;

  do {
    filename = mkrand(template);
  } while (fs.existsSync(filename));

  return filename;
}

function createFile(template, callback) {
  createUniqueName(template, function(err, filename) {
    if (err) {
      callback(err);
      return;
    }

    fs.open(filename, 'ax+', 384 /*=0600*/, function(err, fd) {
      if (err) {
        callback(err);
        return;
      }

      fs.close(fd, function(err) {
        callback(err, filename);
      });
    });
  });
}

function createFileSync(template) {
  var filename = createUniqueNameSync(template),
      fd = fs.openSync(filename, 'ax+', 384 /*=0600*/);

  fs.closeSync(fd);

  return filename;
}

function createDir(template, callback) {
  createUniqueName(template, function(err, dirname) {
    if (err) {
      callbacke(err);
      return;
    }

    fs.mkdir(dirname, 448 /*=0700*/, function(err) {
      callback(err, dirname);
    });
  });
}

function createDirSync(template) {
  var dirname = createUniqueNameSync(template);

  fs.mkdirSync(dirname, 448 /*=0700*/);

  return dirname;
}

module.exports = {
  createFile: createFile,
  createFileSync: createFileSync,
  createDir: createDir,
  createDirSync: createDirSync
};
<|endoftext|>


<commit_before>var mongo = require('mongodb-wrapper');

// mongodb setup
var db = new mongo.db('127.0.0.1', 27017, 'rapleaf');
db.collection('requests'); // store all requests/responses

// webservice module config
this.title = "RapLeaf Extended API demo";
this.name = "RapLeaf Extended API";
this.version = "0.0.1";
this.endpoint = "http://localhost:8080";

// requests
exports.requests = function(options, callback) {
  db.emails.find().toArray(function(err, emails) {
    callback(err, emails);
  });
};
exports.requests.description = "Return the full request log";

// field_counts
exports.fields_count = function(options, callback) {
  db.collection('requests.outMR'); // collection for the MR result

  db.requests.outMR.drop(function(err) { // drop it first (necessary?)
    db.requests.mapReduce(function() { // MAP
      for (var k in this.result)
        emit(k, 1); // emit every attribute
    }, function(key, values) { // REDUCE
      var t = 0;
      for (var i = 0; i < values.length; ++i)
        t += values[i];
      return { count: t };
    }, { // STORED
      out: "requests.outMR"
    }, function(err) {
      if (err) {
        callback(err, null);
        return;
      }
      db.requests.outMR.find().toArray(function(err, data) {
        callback(err, data);
      });
    });
  });
};
exports.fields_count.description = "List result fields and their count";

<commit_msg>fixed typo<commit_after>var mongo = require('mongodb-wrapper');

// mongodb setup
var db = new mongo.db('127.0.0.1', 27017, 'rapleaf');
db.collection('requests'); // store all requests/responses

// webservice module config
this.title = "RapLeaf Extended API demo";
this.name = "RapLeaf Extended API";
this.version = "0.0.1";
this.endpoint = "http://localhost:8080";

// requests
exports.requests = function(options, callback) {
  db.requests.find().toArray(function(err, emails) {
    callback(err, emails);
  });
};
exports.requests.description = "Return the full request log !!!WARNING!!!";

// field_counts
exports.fields_count = function(options, callback) {
  db.collection('requests.outMR'); // collection for the MR result

  db.requests.outMR.drop(function(err) { // drop it first (necessary?)
    db.requests.mapReduce(function() { // MAP
      for (var k in this.result)
        emit(k, 1); // emit every attribute
    }, function(key, values) { // REDUCE
      var t = 0;
      for (var i = 0; i < values.length; ++i)
        t += values[i];
      return { count: t };
    }, { // STORED
      out: "requests.outMR"
    }, function(err) {
      if (err) {
        callback(err, null);
        return;
      }
      db.requests.outMR.find().toArray(function(err, data) {
        callback(err, data);
      });
    });
  });
};
exports.fields_count.description = "List result fields and their count";

<|endoftext|>


<commit_before>/**
 * Created by Vignesh Jagadeesh on 18/5/16.
 *
 *
 */

'use strict';

const client = require('mongodb').MongoClient,
  Promise = require('bluebird'),
  Redis = require('ioredis'),
  logger = require('winston'),
  EventEmitter = require('events').EventEmitter;

const Schema = require('./schema'),
  Model = require('./model');

function Movent() {
  this.models = {};
  this.modelSchemas = {};
  this.db = null;
  this.redis = null;
  this.notify = null;
}

require('util').inherits(Movent,EventEmitter);

Movent.prototype.setNotifier = function(amqpPublisher){
  this.notify = amqpPublisher;
};

Movent.prototype.connectToMongo = function (mongoUrl,options) {
  const _this = this;

  if(options.replset) options.replSet = {rs_name:options.replSet};

  console.log('--------------- MONGO DEBUG --------');
  console.log('MONGO URL ' , mongoUrl);
  console.log('OPTIONS',options);

  return new Promise((resolve, reject)=> {
    client.connect(mongoUrl,options,function(err,db){
      if(err) {
        logger.error('✗ MongoDB Connection Error. Please make sure MongoDB is running: ', err);
        return reject(err);
      }
      logger.info('Connected to mongodb',{url:mongoUrl});
      _this.db = db;
      return resolve();
    });
  });
};

Movent.prototype.connectToRedis = function(redisPort,redisUrl){
  const _this = this;
  return new Promise((resolve,reject)=>{
    _this.redis = new Redis(redisPort, redisUrl);

    //Test if redis is connected;
    _this.redis.set('test','0').then(()=>{
      logger.info(`Connected to redis server on ${redisUrl}:${redisPort}`);
      resolve();
    }).catch((err)=>{
      logger.error('✗ Redis Connection Error. Please make sure Redis Server is running: ', err);
    });
  });
};

Movent.prototype.Schema = Schema;

Movent.prototype.model = function(name,schema){
  const _this = this;

  //Return the model if no schema is given.
  if(!schema) {

    if(!_this.models[name]){
      return  new Error('Schema not initialized for model ' + name);
    }
    return this.models[name];
  }

  this.models[name] = new Model(name,schema,_this);

  return this.models[name];
};

Movent.prototype.getModelNames = function(){
  return Object.keys(this.models);
};

module.exports = new Movent();<commit_msg>Mongo connection with options<commit_after>/**
 * Created by Vignesh Jagadeesh on 18/5/16.
 *
 *
 */

'use strict';

const client = require('mongodb').MongoClient,
  Promise = require('bluebird'),
  Redis = require('ioredis'),
  logger = require('winston'),
  EventEmitter = require('events').EventEmitter;

const Schema = require('./schema'),
  Model = require('./model');

function Movent() {
  this.models = {};
  this.modelSchemas = {};
  this.db = null;
  this.redis = null;
  this.notify = null;
}

require('util').inherits(Movent,EventEmitter);

Movent.prototype.setNotifier = function(amqpPublisher){
  this.notify = amqpPublisher;
};

Movent.prototype.connectToMongo = function (mongoUrl,options) {
  const _this = this;

  if(options.replset) options.replSet = {rs_name:options.replset};

  console.log('--------------- MONGO DEBUG --------');
  console.log('MONGO URL ' , mongoUrl);
  console.log('OPTIONS',options);

  return new Promise((resolve, reject)=> {
    client.connect(mongoUrl,options,function(err,db){
      if(err) {
        logger.error('✗ MongoDB Connection Error. Please make sure MongoDB is running: ', err);
        return reject(err);
      }
      logger.info('Connected to mongodb',{url:mongoUrl});
      _this.db = db;
      return resolve();
    });
  });
};

Movent.prototype.connectToRedis = function(redisPort,redisUrl){
  const _this = this;
  return new Promise((resolve,reject)=>{
    _this.redis = new Redis(redisPort, redisUrl);

    //Test if redis is connected;
    _this.redis.set('test','0').then(()=>{
      logger.info(`Connected to redis server on ${redisUrl}:${redisPort}`);
      resolve();
    }).catch((err)=>{
      logger.error('✗ Redis Connection Error. Please make sure Redis Server is running: ', err);
    });
  });
};

Movent.prototype.Schema = Schema;

Movent.prototype.model = function(name,schema){
  const _this = this;

  //Return the model if no schema is given.
  if(!schema) {

    if(!_this.models[name]){
      return  new Error('Schema not initialized for model ' + name);
    }
    return this.models[name];
  }

  this.models[name] = new Model(name,schema,_this);

  return this.models[name];
};

Movent.prototype.getModelNames = function(){
  return Object.keys(this.models);
};

module.exports = new Movent();<|endoftext|>


<commit_before>/*
  FlagstoneJS v3.4.0
  (c) 2015-2017 Depth Development. http://depthdev.com
  License: MIT
*/
!function(e,t){"use strict";e.flagstone=function(n){function r(n){function r(){for(var e=0,t=x.length;e<t;e++)Math.random()<O&&x.splice(e,0,!1)}function a(){p.style.visibility="hidden"}function o(){var t=[T],n=0,r=w.length;for(C=[];n<r;n++){if(n<T)x[n]?(x[n].style.top=S+"px",x[n].style[B]=k*n+(n?D*n+S:S)+"px",_&&(x[n].style.height=x[n].style.width),t[n]=w[n]+S,U(x[n],n),C.push([x[n]])):T>1&&(t[n]=k+S);else{var a=Math.min.apply(null,t),o=t.indexOf(a);x[n]?(x[n].style.top=a+D+"px",x[n].style[B]=k*o+(o?D*o+S:S)+"px",_&&(x[n].style.height=x[n].style.width),t[o]+=w[n]+D,U(x[n],n),C[o].push(x[n])):T>1&&(t[o]+=k+D)}p.style.height=(Math.max.apply(null,t)||w[0]+S)+S+"px"}e.setTimeout(function(){p.style.visibility="visible"})}function s(t){if(x.length){L=p.getBoundingClientRect().width,L<E+(S?2*S:0)&&(L=E),b=Math.floor(L/E),T=b>y?y:b,k=L/T-(D*(T-1)+2*S)/T,w=[];for(var n=0,r=x.length;n<r;n++)x[n]&&(x[n].style.width=k+"px",x[n].style.marginTop="0px"),w.push(_||!x[n]?k:x[n].offsetHeight);L===p.getBoundingClientRect().width||t?o():s(!0),t||e.setTimeout(function(){s(!0)},F)}}function i(){var t=Date.now(),n=p.getElementsByTagName("img");n.length&&!function(){var r=e.setInterval(function(){for(var a=[],o=0,i=n.length;o<i;o++)a[o]=n[o].naturalHeight;(a.indexOf(0)===-1||t+q<Date.now())&&(e.clearInterval(r),e.setTimeout(function(){s(!0)}))},I)}()}function l(t){if("keydown"!==t.type||13===t.keyCode||32===t.keyCode){for(var n=t.target;n&&!n.classList.contains(M);)n=n.parentElement;p.removeChild(n),e.MutationObserver||$()}}function g(t){"keydown"===t.type&&13!==t.keyCode&&32!==t.keyCode||e.setTimeout(s,j)}function d(t){function n(){var t=r.getBoundingClientRect().height+a;for(i=0;i<g;i++)o[i].style.marginTop=t-c+"px";G=e[(J?"request":"cancel")+"AnimationFrame"](n)}if("keydown"!==t.type||13===t.keyCode||32===t.keyCode){for(var r=t.target;r&&!r.classList.contains(M);)r=r.parentElement;for(var a=e.parseFloat(r.style.top),o=[],s=!1,i=0,l=0,g=C.length,d=0;i<g&&!s;i++)for(l=0,d=C[i].length;l<d;l++)s&&o.push(C[i][l]),C[i][l]===r&&(s=!0);if(o.length){var c=e.parseFloat(o[0].style.top)-D;g=o.length,J=!1,e.cancelAnimationFrame(G),e.clearTimeout(K),J=!0,G=e.requestAnimationFrame(n),K=e.setTimeout(function(){J=!1,e.cancelAnimationFrame(G)},Y)}}}function c(){e.clearTimeout(V),V=e.setTimeout(s,R)}function v(){a(),e.clearTimeout(Z),Z=e.setTimeout($)}function f(){e.removeEventListener("resize",c),t.head.removeChild(t.getElementById("flagstone-"+m+"-styles"))}function u(e){e.margin||0===e.margin?(S=e.margin,D=e.margin):(S=e.bedPadding||S,D=e.stonesMargin||D),E=e.minWidth||E,y=e.maxColumns||y,W=e.dragAndDrop===!0||e.dragAndDrop===!1?e.dragAndDrop:W,Q=e.dropCallback||Q,U=e.callback||U,$()}var m=e.flagstone.index,h=n?n.nodeName?{elem:n}:n:{elem:t.getElementsByClassName("flagstone")[0]},p=h.elem,S=h.margin||0===h.margin?h.margin:h.bedPadding||0===h.bedPadding?h.bedPadding:10,L=0,E=h.minWidth||280,y=h.maxColumns||5,b=0,T=0,x=[],D=h.margin||0===h.margin?h.margin:h.stonesMargin||0===h.stonesMargin?h.stonesMargin:10,k=L/T-D*(T+1)/T,w=[],C=[],M="flagstone-"+m+"-bed__stone",A=h.flow,B=h.direction?h.direction.toLowerCase():"left",P=h.random,O=h.spaceFrequency||.4,z=h.space,F=h.animationDuration||0,N=h.animationDuration?h.animationDuration/1e3:0,X=h.animationTimingFunction||"linear",R=h.resizeDelay||0===h.resizeDelay?h.resizeDelay:250,_=h.square,q=h.imagesLoadedQueryDuration||2500,I=h.imagesLoadedQueryFrequency||100,W=h.dragAndDrop,H=h.dragAndDropAutoDelay,Q=h.dropCallback||function(){return!0},j=h.eventResetDelay||0,Y=h.eventResizeDuration||0,G=null,J=!1,K=null,U=h.callback||function(){},V=null,Z=null,$=null,ee={dragStone:null,targetStone:null,targetStoneMouseXPercent:0,autoDropTimer:null,autoDrop:function(){ee.targetStone.classList.contains(M)&&(ee.targetStoneMouseXPercent<.5?ee.dragStone!==ee.targetStone.previousElementSibling&&(ee.targetStone.parentElement.insertBefore(ee.dragStone,ee.targetStone),ee.targetStone.classList.remove("flagstone-left"),ee.targetStone.classList.remove("flagstone-dragover")):ee.dragStone!==ee.targetStone.nextElementSibling&&(ee.targetStone.parentElement.insertBefore(ee.dragStone,ee.targetStone.nextElementSibling),ee.targetStone.classList.remove("flagstone-right"),ee.targetStone.classList.remove("flagstone-dragover")),e.clearTimeout(ee.autoDropTimer),ee.autoDropTimer=e.setTimeout(ee.autoDrop,H))},clear:function(){ee.targetStone.classList.remove("flagstone-dragover"),ee.targetStone.classList.remove("flagstone-left"),ee.targetStone.classList.remove("flagstone-right"),ee.dragStone.classList.remove("flagstone-drag"),p.classList.remove("flagstone-dragover")},dragStart:function(e){e.dataTransfer&&e.dataTransfer.setData("text",this.id),ee.dragStone=this,ee.dragStone.classList.add("flagstone-drag")},dragEnter:function(t){t.preventDefault(),t.stopPropagation(),this!==ee.dragStone&&this!==ee.targetStone&&this!==p&&(e.clearTimeout(ee.autoDropTimer),ee.autoDropTimer=e.setTimeout(ee.autoDrop,H))},touchMove:function(e){e.preventDefault(),e.stopPropagation();for(var n=t.elementFromPoint(e.touches[0].clientX,e.touches[0].clientY);n&&!n.hasAttribute("draggable");)n=n.parentElement;n&&(ee.targetStone&&ee.targetStone!==n&&(ee.targetStone.classList.remove("flagstone-dragover"),ee.targetStone.classList.remove("flagstone-left")),ee.targetStone=n,ee.targetStone===p?ee.targetStone.classList.add("flagstone-dragover"):ee.targetStone.classList.contains("flagstone-lock")||(ee.targetStone.classList.add("flagstone-dragover"),ee.targetStone.classList.add("flagstone-left")))},dragOver:function(e){e.preventDefault(),e.stopPropagation(),e.dataTransfer.dropEffect="move",this!==ee.dragStone&&this.hasAttribute("draggable")?(ee.targetStone=this,ee.targetStone.classList.add("flagstone-dragover"),ee.targetStoneMouseXPercent=e.offsetX/this.offsetWidth,ee.targetStoneMouseXPercent<.5?(ee.targetStone.classList.remove("flagstone-right"),ee.targetStone.classList.add("flagstone-left")):(ee.targetStone.classList.remove("flagstone-left"),ee.targetStone.classList.add("flagstone-right")),this.classList.remove("flagstone-dragover"),ee.targetStone!==p&&p.classList.remove("flagstone-dragover")):this===p&&this.classList.add("flagstone-dragover")},dragEnd:function(){ee.dragStone.classList.remove("flagstone-drag")},touchEnd:function(){ee.targetStone&&!ee.targetStone.classList.contains("flagstone-lock")&&Q(ee.dropStone,ee.targetStone)&&p.insertBefore(ee.dragStone,ee.targetStone),ee.clear()},dragLeave:function(){ee.targetStone&&(p.classList.remove("flagstone-dragover"),ee.targetStone.classList.remove("flagstone-dragover"),ee.targetStone.classList.remove("flagstone-left"),ee.targetStone.classList.remove("flagstone-right"))},drop:function(t){if(t.stopPropagation(),e.clearTimeout(ee.autoDropTimer),ee.dragStone!==this&&(this.hasAttribute("draggable")||this===p)){if(ee.targetStone=this,ee.targetStone===p){if(!Q(ee.dragStone,ee.targetStone))return ee.clear(),!1;ee.targetStone.appendChild(ee.dragStone)}else if(ee.targetStoneMouseXPercent<.5){if(!Q(ee.dragStone,ee.targetStone))return ee.clear(),!1;ee.targetStone.parentElement.insertBefore(ee.dragStone,ee.targetStone)}else{if(!Q(ee.dragStone,ee.targetStone.nextElementSibling))return ee.clear(),!1;ee.targetStone.parentElement.insertBefore(ee.dragStone,ee.targetStone.nextElementSibling)}ee.clear(),e.MutationObserver||$()}return!1}};return $=function(){x=Array.prototype.slice.call(p.children);for(var t=0,n=x.length;t<n;t++)x[t].classList.add(M);for(t=0;t<n;t++)x[t].setAttribute("draggable","false"),x[t].removeEventListener("dragstart",ee.dragStart),x[t].removeEventListener("touchstart",ee.dragStart),x[t].removeEventListener("touchmove",ee.touchMove),x[t].removeEventListener("dragover",ee.dragOver),x[t].removeEventListener("dragleave",ee.dragLeave),x[t].removeEventListener("dragend",ee.dragEnd),x[t].removeEventListener("touchend",ee.touchEnd),x[t].removeEventListener("drop",ee.drop),x[t].removeEventListener("touchend",ee.drop),x[t].removeEventListener("dragenter",ee.dragEnter),p.removeEventListener("dragover",ee.dragOver),p.removeEventListener("drop",ee.drop);if(W)for(t=0;t<n;t++)x[t].classList.contains("flagstone-lock")||(x[t].setAttribute("draggable","true"),x[t].addEventListener("dragstart",ee.dragStart),x[t].addEventListener("touchstart",ee.dragStart),x[t].addEventListener("touchmove",ee.touchMove),x[t].addEventListener("dragover",ee.dragOver),x[t].addEventListener("dragleave",ee.dragLeave),x[t].addEventListener("dragend",ee.dragEnd),x[t].addEventListener("touchend",ee.touchEnd),x[t].addEventListener("drop",ee.drop),x[t].addEventListener("touchend",ee.drop),H&&x[t].addEventListener("dragenter",ee.dragEnter),p.addEventListener("dragover",ee.dragOver),p.addEventListener("drop",ee.drop));(P||z)&&(P&&x.sort(function(){return.5-Math.random()}),z&&r());var a=p.getElementsByClassName("flagstone-remove");for(t=0,n=a.length;t<n;t++)a[t].removeEventListener("click",l),a[t].addEventListener("click",l),a[t].removeEventListener("keydown",l),a[t].addEventListener("keydown",l);for(a=p.getElementsByClassName("flagstone-reset"),t=0,n=a.length;t<n;t++)a[t].removeEventListener("click",g),a[t].addEventListener("click",g),a[t].removeEventListener("keydown",g),a[t].addEventListener("keydown",g);for(a=p.getElementsByClassName("flagstone-resize"),t=0,n=a.length;t<n;t++)a[t].removeEventListener("click",d),a[t].addEventListener("click",d),a[t].removeEventListener("keydown",d),a[t].addEventListener("keydown",d);s(),F&&e.setTimeout(i,F),e.setTimeout(function(){s(!0)},F)},function(){if(p.classList.add("flagstone-"+m+"-bed"),!t.getElementById("flagstone-"+m+"-styles")){var n=".flagstone-"+m+"-bed{box-sizing:border-box;list-style-type:none;overflow:hidden;position:relative;min-width:"+(E+2*S)+"px;}",r=".flagstone-"+m+"-bed__stone{box-sizing:border-box;position:absolute;top:0px;"+B+":0px;margin:0;}",a=".flagstone-"+m+"-bed__stone{transition:top "+N+"s "+X+","+B+" "+N+"s "+X+(A?",width "+N+"s "+X:"")+";}",o=n+r+a,s=t.createElement("style");s.type="text/css",s.id="flagstone-"+m+"-styles",s.appendChild(t.createTextNode(o)),t.head.appendChild(s)}if($(),e.removeEventListener("resize",c),e.addEventListener("resize",c),e.MutationObserver){var i=new MutationObserver(v);i.observe(p,{childList:!0})}}(),{adjust:u,destroy:f,hide:a,reset:c,hardReset:$}}return e.flagstone.index++,new r(n)},e.flagstone.index=-1}(window,document);<commit_msg>Delete flagstone-3.4.0.min.js<commit_after><|endoftext|>


<commit_before>import jessy from 'jessy';

const {isArray} = Array;

const maybeArray = (a) => isArray(a) ? a : [a];

const isUndefined = (a) => typeof a === 'undefined';

const paths = [
    '^scripts.wisdom',
    '^scripts.wisdom:type',
    'changelog',
    '!changelog',
    ':version',
    '^scripts.wisdom:build',
    ':commit',
    'tag',
    '!tag',
    ':release',
    '-private',
    '^scripts.wisdom:done',
];

const check = (info) => (data) => {
    const [path] = maybeArray(data);

    if (path.startsWith(':'))
        return true;

    const cleanPath = path.replace(/[!^:]/, '');
    const result = jessy(cleanPath, info);

    if (path.startsWith('-'))
        return !result || isUndefined(result);

    if (path.startsWith('!'))
        return !result;

    if (path.startsWith('^'))
        return Boolean(result);

    return Boolean(result) || isUndefined(result);
};

export const parse = (info) => {
    return paths.filter(check(info));
};

<commit_msg>fix: wisdom: changelog<commit_after>import jessy from 'jessy';

const {isArray} = Array;

const maybeArray = (a) => isArray(a) ? a : [a];

const isUndefined = (a) => typeof a === 'undefined';

const paths = [
    '^scripts.wisdom',
    '^scripts.wisdom:type',
    'changelog',
    '!changelog',
    ':version',
    '^scripts.wisdom:build',
    ':commit',
    'tag',
    '!tag',
    ':release',
    '-private',
    '^scripts.wisdom:done',
];

const check = (info) => (data) => {
    const [path] = maybeArray(data);

    if (path.startsWith(':'))
        return true;

    const cleanPath = path.replace(/[!^:]/, '');
    const result = jessy(cleanPath, info);

    if (path.startsWith('-'))
        return !result || isUndefined(result);

    if (path.startsWith('!'))
        return result === false;

    if (path.startsWith('^'))
        return Boolean(result);

    return Boolean(result) || isUndefined(result);
};

export const parse = (info) => {
    return paths.filter(check(info));
};

<|endoftext|>


<commit_before>'use strict';

// parse the data of documents
// only used by DAO

var parser = module.exports = {};

var glob        = require('glob');
var marked      = require('marked');
var highlight   = require('highlight.js');
var node_path   = require('path');
var sep         = node_path.sep;
var node_fs     = require('fs');
var lang        = require('./lang');
var async       = require('async');

// parse the tree structure of the document
// basic infomations
// @param {path} dir absolute dir of the document root

// tree:
// {
//     index: 'README.md',
//     // relative depth
//     rel_depth: 0,
//     pages: {
//         '1_a.md': {
//             name: '1_a.md',
//             parent: <recursive>,
//             rel_depth: 1,
//             // empty array indicates there're no sub pages
//             pages: {}
//         }
//     }
// }
parser.raw_tree = function (dir, callback) {
    glob('**/*.md', {
        cwd: dir,
        strict: true

    }, function (err, files) {
        if ( err ) {
            return callback(err);
        }

        var tree = {
            // rel_depth: 0,
            pages: {},
            type: 'dir'
        };

        files.forEach(function (file) {
            parser._save_item(tree, file, dir);
        });

        callback(null, tree);
    });
};

parser._save_item = function (tree, path, root) {
    var parent = tree;
    var abs = root;

    path.split(sep).some(function (slice, i) {
        abs = node_path.join(abs, slice);

        if ( slice === 'README.md' ) {
            parent.path = abs;
            return true;
        }

        var current = parent.pages[slice];

        if ( !current ) {
            current = parent.pages[slice] = {
                // duplicate data for more easily parsing
                name: slice,
                // recursive data
                parent: parent,
                // rel_depth: i + 1,
                path: abs
            };

            if ( node_fs.statSync(abs).isDirectory() ) {
                if ( !current.pages ) {
                    current.pages = {};
                }

                current.type = 'folder';
                parent = current;

            } else {
                current.type = 'file';
                // if file occurs, skip parsing
                return true;
            }
        }

        parent = current;
    });
};

// TODO
var REGEX_NAME_SPLITTER = /_/g;
var REGEX_INT = /^\d+$/;

parser.cook_name = function (name) {
    var split = name.split(REGEX_NAME_SPLITTER).filter(Boolean);

    var first = split[0];

    // number string
    if ( REGEX_INT.test(first) ) {
        split.shift();
    }

    return {
        // '01_abc_def' -> 'Abc Def'
        display_name: split.map(function (part) {
            return lang.capitalize(part);
        }).join(' '),

        // '01_abc_def' -> 'abc-def'
        uri_name    : split.map(function (part) {
            return part.toLowerCase();
        }).join('-')
    }
};

// @param {Object=} languages
// {
//     "zh-CN": {
//     }
// }
parser.language_tree = function (raw_tree, languages) {
    if ( lang.isEmptyObject(languages) ) {
        languages = null;
    }

    var ret = {};

    if ( languages ) {
        var root = raw_tree.pages || {};

        lang.each(languages, function (name, language) {
            var root_tree = root[language] || {};
            delete root_tree.parent;

            // it's hard to detect the closest match if user had a wrong configuration
            // convert to lowercase to make it easier
            ret[language.toLowerCase()] = {
                name: name,
                tree: root_tree
            };
        });

        return ret;

    } else {
        return {
            default: {
                tree: raw_tree
            }
        };
    }
};

var SUPPORTED_LANG = Object.keys(highlight.LANGUAGES);

var marked_opt = {
    breaks: false,
    gfm: true,
    langPrefix: 'language-',
    pedantic: false,
    sanitize: false,
    silent: false,
    smartLists: false,
    smartypants: false,
    tables: true,
    highlight: function (code, lang) {
        if ( ~ SUPPORTED_LANG.indexOf(lang) ) {
            return highlight.highlight(lang, code).value;
        } else {
            return highlight.highlightAuto(code).value;
        }
    }
};

// options.
parser.markdown = function (code, callback) {
    marked(code, marked_opt, callback);
};

var REGEX_MATCH_H1 = /<h1>(.*?)<\/h1>/i;

parser.get_title = function (html) {
    html = html || '';

    var match = html.match(REGEX_MATCH_H1);

    return match ? match[1] : undefined;
};

// @param {Object} options
// - define
parser.sort_pages = function (pages) {
    pages.sort(function (a, b) {
        return a.name < b.name ? - 1 : 1;
    });
};

// create a cache
parser.create_data = function (language_tree, callback) {
    var counter = Object.keys(language_tree).length;
    var error;
    var nodes = [];

    function iterator (data, done) {
        var node = data.node;
        var descend = data.descend;

        nodes.push(node);

        if ( node.type === 'file' ) {
            var file = node.path;

            node_fs.readFile(file, function (err, content) {
                if ( err ) {
                    return done(err);
                }

                parser.markdown(content.toString(), function (err, html) {
                    if ( err ) {
                        return done(err);
                    }

                    node.html = html;

                    var title = parser.get_title(html);

                    parser._generate_url(node, title);
                    done(null);
                });
            });

        } else {
            parser._generate_url(node);

            var pages = node.pages;

            if ( pages ) {
                // `pages` from object to array
                node.pages = Object.keys(pages).map(function (name) {
                    return pages[name];
                });

                parser.sort_pages(node.pages);
            }

            descend();
            done(null);
        }
    };

    lang.each(language_tree, function (l, language) {
        parser.walk(l.tree, iterator, function (err) {
            if ( err ) {
                error = err;
                return callback(err);

            } else if (error) {
                return;

            } else if ( -- counter === 0 ) {
                nodes.forEach(function (node) {
                    if ( node ) {
                        // remove recursive property
                        delete node.parent;
                        // remove private data
                        delete node.path;
                    }
                });
                // free
                nodes.length = 0;

                return callback(null, language_tree);
            }
        });
    });
};

// TODO: #7
parser._generate_url = function (node, name) {
    if ( !node.parent ) {
        node.url = '';
    } else {
        name = name || node.name;

        var cooked = parser.cook_name(name);
        node.display_name = cooked.display_name;
        node.uri_name = cooked.uri_name;

        node.url = node.parent.url + '/' + node.uri_name;
    }
};

// walk and traverse a tree
parser.walk = function (tree, iterator, callback) {
    var q = async.queue(iterator);
    var errors = [];

    q.drain = function () {
        callback( errors.length ? errors : null );
    };

    function walk (node, depth) {
        node.depth = depth;

        q.push({
            node: node,

            // descend a specific node or descend all
            descend: function (sub_node) {
                if ( sub_node ) {
                    walk(sub_node, depth + 1);

                } else if ( node.pages ) {
                    node.pages.forEach(function (sub_node, name) {
                        walk(sub_node, depth + 1);
                    });
                }
            }

        }, function (err){
            if ( err ) {
                errors.push(err);
            }
        });
    }

    walk(tree, 0);
};

<commit_msg>fix index file<commit_after>'use strict';

// parse the data of documents
// only used by DAO

var parser = module.exports = {};

var glob        = require('glob');
var marked      = require('marked');
var highlight   = require('highlight.js');
var node_path   = require('path');
var sep         = node_path.sep;
var node_fs     = require('fs');
var lang        = require('./lang');
var async       = require('async');

// parse the tree structure of the document
// basic infomations
// @param {path} dir absolute dir of the document root

// tree:
// {
//     index: 'README.md',
//     // relative depth
//     rel_depth: 0,
//     pages: {
//         '1_a.md': {
//             name: '1_a.md',
//             parent: <recursive>,
//             rel_depth: 1,
//             // empty array indicates there're no sub pages
//             pages: {}
//         }
//     }
// }
parser.raw_tree = function (dir, index_file, callback) {
    glob('**/*.md', {
        cwd: dir,
        strict: true

    }, function (err, files) {
        if ( err ) {
            return callback(err);
        }

        var tree = {
            // rel_depth: 0,
            pages: {},
            type: 'dir'
        };

        files.forEach(function (file) {
            parser._save_item(tree, file, dir, index_file);
        });

        callback(null, tree);
    });
};

parser._save_item = function (tree, path, root, index_file) {
    var parent = tree;
    var abs = root;

    path.split(sep).some(function (slice, i) {
        abs = node_path.join(abs, slice);

        if ( slice === index_file && node_fs.statSync(abs).isFile() ) {
            parent.path = abs;
            return true;
        }

        var current = parent.pages[slice];

        if ( !current ) {
            current = parent.pages[slice] = {
                // duplicate data for more easily parsing
                name: slice,
                // recursive data
                parent: parent
            };

            if ( node_fs.statSync(abs).isDirectory() ) {
                if ( !current.pages ) {
                    current.pages = {};
                }

                current.type = 'folder';
                parent = current;

            } else {
                current.type = 'file';
                current.path = abs;
                // if file occurs, skip parsing
                return true;
            }
        }

        parent = current;
    });
};

// TODO
var REGEX_NAME_SPLITTER = /[_\s]+/g;
var REGEX_INT = /^\d+$/;

parser.cook_name = function (name) {
    var split = name.split(REGEX_NAME_SPLITTER).filter(Boolean);

    var first = split[0];

    // number string
    if ( REGEX_INT.test(first) ) {
        split.shift();
    }

    return {
        // '01_abc_def' -> 'Abc Def'
        display_name: split.map(function (part) {
            return lang.capitalize(part);
        }).join(' '),

        // '01_abc_def' -> 'abc-def'
        uri_name    : split.map(function (part) {
            return part.toLowerCase();
        }).join('-')
    }
};

// @param {Object=} languages
// {
//     "zh-CN": {
//     }
// }
parser.language_tree = function (raw_tree, languages) {
    if ( lang.isEmptyObject(languages) ) {
        languages = null;
    }

    var ret = {};

    if ( languages ) {
        var root = raw_tree.pages || {};

        lang.each(languages, function (name, language) {
            var root_tree = root[language] || {};
            delete root_tree.parent;

            // It's hard to detect the closest match if user had a wrong configuration
            // convert to lowercase to make it easier
            ret[language.toLowerCase()] = {
                name: name,
                tree: root_tree
            };
        });

        return ret;

    } else {
        return {
            default: {
                tree: raw_tree
            }
        };
    }
};

var SUPPORTED_LANG = Object.keys(highlight.LANGUAGES);

var marked_opt = {
    breaks: false,
    gfm: true,
    langPrefix: 'language-',
    pedantic: false,
    sanitize: false,
    silent: false,
    smartLists: false,
    smartypants: false,
    tables: true,
    highlight: function (code, lang) {
        if ( ~ SUPPORTED_LANG.indexOf(lang) ) {
            return highlight.highlight(lang, code).value;
        } else {
            return highlight.highlightAuto(code).value;
        }
    }
};

// options.
parser.markdown = function (code, callback) {
    marked(code, marked_opt, callback);
};

var REGEX_MATCH_H1 = /<h1>(.*?)<\/h1>/i;

parser.get_title = function (html) {
    html = html || '';

    var match = html.match(REGEX_MATCH_H1);

    return match ? match[1] : undefined;
};

// @param {Object} options
// - define
parser.sort_pages = function (pages) {
    pages.sort(function (a, b) {
        return a.name < b.name ? - 1 : 1;
    });
};

// create a cache
parser.create_data = function (language_tree, callback) {
    var counter = Object.keys(language_tree).length;
    var error;
    var nodes = [];

    function iterator (data, done) {
        var node = data.node;
        var descend = data.descend;

        nodes.push(node);

        parser._parse_content(node, function (err, html) {
            if ( err ) {
                return done(err);
            }

            var title;

            if ( html ) {
                node.html = html;
                title = parser.get_title(html);
            } else {
                title = node.name;
            }

            parser._generate_url(node, title);

            var pages = node.pages;

            if ( pages ) {
                // `pages` from object to array
                node.pages = Object.keys(pages).map(function (name) {
                    return pages[name];
                });

                parser.sort_pages(node.pages);
            }

            descend();
            done(null);
        });
    };

    lang.each(language_tree, function (l, language) {
        parser.walk(l.tree, iterator, function (err) {
            if ( err ) {
                error = err;
                return callback(err);

            } else if (error) {
                return;

            } else if ( -- counter === 0 ) {
                nodes.forEach(function (node) {
                    if ( node ) {
                        // remove recursive property
                        delete node.parent;
                        // remove private data
                        delete node.path;
                    }
                });
                // free
                nodes.length = 0;

                return callback(null, language_tree);
            }
        });
    });
};

parser._parse_content = function (node, callback) {
    var file = node.path;

    if ( file ) {
        node_fs.readFile(file, function (err, content) {
            if ( err ) {
                return done(err);
            }

            parser.markdown(content.toString(), callback);
        });

    } else {
        callback(null);
    }
};

// TODO: #7
parser._generate_url = function (node, name) {
    if ( !node.parent ) {
        node.url = '';

    } else {
        var cooked = parser.cook_name(name);
        node.display_name = cooked.display_name;
        node.uri_name = cooked.uri_name;

        node.url = node.parent.url + '/' + node.uri_name;
    }
};

// walk and traverse a tree
parser.walk = function (tree, iterator, callback) {
    var q = async.queue(iterator);
    var errors = [];

    q.drain = function () {
        callback( errors.length ? errors : null );
    };

    function walk (node, depth) {
        node.depth = depth;

        q.push({
            node: node,

            // descend a specific node or descend all
            descend: function (sub_node) {
                if ( sub_node ) {
                    walk(sub_node, depth + 1);

                } else if ( node.pages ) {
                    node.pages.forEach(function (sub_node, name) {
                        walk(sub_node, depth + 1);
                    });
                }
            }

        }, function (err){
            if ( err ) {
                errors.push(err);
            }
        });
    }

    walk(tree, 0);
};

<|endoftext|>


<commit_before>var _= require('underscore'),
    ret= require('ret');

const _soa = function (o, s, v)
      {
            s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            s = s.replace(/^\./, '');           // strip a leading dot
            var a = s.split('.'),
                prop= a.pop();

            while (a.length)
            {
                var n = a.shift();
                o = o[n] || (o[n]={});
            }

            o[prop]= v;
      },
      _oa = function(o, s)
      {
             s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
             s = s.replace(/^\./, '');           // strip a leading dot
             var a = s.split('.');
             while (a.length) {
                 var n = a.shift();
                 if (n in o) {
                     o = o[n];
                 } else {
                     return;
                 }
             }
             return o;
      },
      _buildFilter= function (query)
      {
           var cond= query.cond,
               filter= query.$filter= {},
               canFind= true;

           Object.keys(cond).every(function (field)
           {
                   var val= cond[field], type= typeof val,
                       _field= function (field,val,op)
                       {
                          filter[field]= { values: val===undefined ? [] : (Array.isArray(val) ? val : [ val ]),
                                               op: op };
                       },
                       _regexp= function (field,val)
                       {
                          var tks= ret(val.source),
                              _chars= function (start)
                              {
                                  return _.collect(tks.stack.slice(start),
                                           function (tk) { return String.fromCharCode(tk.value); })
                                          .join('');
                              };

                          if (tks.stack
                              &&tks.stack[0]
                              &&tks.stack[0].type==ret.types.POSITION
                              &&tks.stack[0].value=='^'
                              &&!_.filter(tks.stack.slice(1),function (tk) { return tk.type!=ret.types.CHAR; }).length)
                          {
                            var val= _chars(1);
                            if (val!='')
                              _field(field,val,'BEGINS_WITH');
                          }
                          else
                          if (tks.stack
                              &&!_.filter(tks.stack,function (tk) { return tk.type!=ret.types.CHAR; }).length)
                          {
                            var val= _chars(0);
                            if (val!='')
                              _field(field,val,'CONTAINS');
                          }
                          else
                              _field(field,val,'REGEXP');
                       };

                   if (type=='object')
                   {
                       if (Array.isArray(val))
                            _field(field,val,'IN');
                       else
                       {
                            if (val instanceof RegExp)
                              _regexp(field,val);
                            else
                            if (val.$ne!==undefined)
                              _field(field,val.$ne,'NE');
                            else
                            if (val.$gt!==undefined)
                              _field(field,val.$gt,'GT');
                            else
                            if (val.$lt!==undefined)
                              _field(field,val.$lt,'LT');
                            else
                            if (val.$gte!==undefined)
                              _field(field,val.$gte,'GE');
                            else
                            if (val.$lte!==undefined)
                              _field(field,val.$lte,'LE');
                            else
                            if (val.$in!==undefined)
                              _field(field,val.$in,'IN');
                            else
                            if (val.$exists!==undefined)
                              _field(field,undefined, val.$exists ? 'NOT_NULL' : 'NULL');
                            else
                              return canFind= false;
                       }
                   }
                   else
                     _field(field,val,'EQ');

                   return true;
           });

           return canFind;
      };

module.exports= function (dyn)
{
    var parser= {};

    parser.parse= function (table,modifiers,cond,projection,identity)
    {
        var p= dyn.promise('parsed'),
            query= { table: table, cond: cond || {}, projection: { root: {} } },
            _projection= function (root)
            {
              var proj= { include: ['$id','$ref'], exclude: []};

              _.keys(root).forEach(function (attr)
              {
                  if (root[attr].$include)
                  {
                    proj.include.push(attr);
                    proj.include.push('$$'+attr);
                    proj.include.push('$$$'+attr);
                  }
                  else
                  if (root[attr].$exclude)
                  {
                    proj.exclude.push(attr);
                    proj.exclude.push('$$'+attr);
                    proj.exclude.push('$$$'+attr);
                  }
              });

              if (proj.include.length==2)
                proj.include= undefined;

              return proj;
            };

        table.name= table._dynamo.TableName;
        table.indexes= table.indexes || [];

        query.project= _projection;
        query.soa= _soa;
        query.oa= _oa;

        if (modifiers.orderby)
        {
               var fields= [];

               Object.keys(modifiers.orderby).forEach(function (name)
               {
                   fields.push({ name: name, dir: modifiers.orderby[name] });
               });

               query.$orderby= fields;
        }

        query.toprojection= function (root)
        {
              var proj= {};

              _.keys(root || {}).forEach(function (attr)
              {
                  if (root[attr].$include)
                    proj[attr]= 1;
                  else
                  if (root[attr].$exclude)
                    proj[attr]= -1;
              });

              return proj;
        };

        if (projection&&_.keys(projection).length)
        {
          query.identity= {};

          query.identity.get= function ($id, $pos, done)
          {
             done();
          }

          query.identity.set= function (item)
          {
          }
        }
        else
        {
          if (identity&&identity.map)
              query.identity= identity;
          else
          {
              query.identity= {};
              query.identity.map= {};

              query.identity.get= function ($id, $pos, cb)
              {
                 var item= query.identity.map[$id+':'+$pos];

                 if (!item)
                 {
                   query.identity.map[$id+':'+$pos]= true;
                   cb();
                 }
                 else
                 if (item===true)
                   setTimeout(query.identity.get,100,$id,$pos,cb);
                 else
                   cb(item);
              }

              query.identity.set= function ($id, $pos, item)
              {
                 query.identity.map[$id+':'+$pos]= item;
              }
          }
        }

        process.nextTick(function ()
        {

            _.extend(query,modifiers);

            if (projection)
            {
                _.keys(projection).every(function (attr)
                {
                       if (projection[attr]==1)
                         _soa(query.projection.root,attr,{ $include: true });
                       else
                       if (projection[attr]==-1)
                         _soa(query.projection.root,attr,{ $exclude: true });
                       else
                       {
                         p.trigger.error(new Error('unknown projection value '+JSON.stringify(projection[attr])));
                         return false;
                       }

                       return true;
                });

                _.extend(query.projection,query.project(query.projection.root));
            }

            query.$supported= _buildFilter(query);
            query.$filtered= [];

            query.filterComplete= function ()
            {
               return Object.keys(query.$filter).length==0;
            };

            query.sortComplete= function ()
            {
               return !(query.orderby&&!query.sorted);
            };

            query.limitComplete= function ()
            {
               return !((query.limit!==undefined||query.skip!==undefined)&&!query.limited);
            };

            query.canLimit= function ()
            {
               return !query.limited
                    &&query.sortComplete()
                    &&query.filterComplete();
            };

            query.canCount= function ()
            {
               return query.filterComplete()
                    &&query.limitComplete();
            };

            p.trigger.parsed(query);

        });

        return p;
    };

    return parser;
};
<commit_msg>fail on logical operators<commit_after>var _= require('underscore'),
    ret= require('ret');

const _soa = function (o, s, v)
      {
            s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            s = s.replace(/^\./, '');           // strip a leading dot
            var a = s.split('.'),
                prop= a.pop();

            while (a.length)
            {
                var n = a.shift();
                o = o[n] || (o[n]={});
            }

            o[prop]= v;
      },
      _oa = function(o, s)
      {
             s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
             s = s.replace(/^\./, '');           // strip a leading dot
             var a = s.split('.');
             while (a.length) {
                 var n = a.shift();
                 if (n in o) {
                     o = o[n];
                 } else {
                     return;
                 }
             }
             return o;
      },
      _buildFilter= function (query)
      {
           var cond= query.cond,
               filter= query.$filter= {},
               canFind= true;

           Object.keys(cond).every(function (field)
           {
                   var val= cond[field], type= typeof val,
                       _field= function (field,val,op)
                       {
                          filter[field]= { values: val===undefined ? [] : (Array.isArray(val) ? val : [ val ]),
                                               op: op };
                       },
                       _regexp= function (field,val)
                       {
                          var tks= ret(val.source),
                              _chars= function (start)
                              {
                                  return _.collect(tks.stack.slice(start),
                                           function (tk) { return String.fromCharCode(tk.value); })
                                          .join('');
                              };

                          if (tks.stack
                              &&tks.stack[0]
                              &&tks.stack[0].type==ret.types.POSITION
                              &&tks.stack[0].value=='^'
                              &&!_.filter(tks.stack.slice(1),function (tk) { return tk.type!=ret.types.CHAR; }).length)
                          {
                            var val= _chars(1);
                            if (val!='')
                              _field(field,val,'BEGINS_WITH');
                          }
                          else
                          if (tks.stack
                              &&!_.filter(tks.stack,function (tk) { return tk.type!=ret.types.CHAR; }).length)
                          {
                            var val= _chars(0);
                            if (val!='')
                              _field(field,val,'CONTAINS');
                          }
                          else
                              _field(field,val,'REGEXP');
                       };

                   if (type=='object')
                   {
                       if (Array.isArray(val))
                       {
                            if (val.length>0&&(typeof val[0]!='object'))
                             _field(field,val,'IN');
                            else
                             return canFind= false;
                       }
                       else
                       {
                            if (val instanceof RegExp)
                              _regexp(field,val);
                            else
                            if (val.$ne!==undefined)
                              _field(field,val.$ne,'NE');
                            else
                            if (val.$gt!==undefined)
                              _field(field,val.$gt,'GT');
                            else
                            if (val.$lt!==undefined)
                              _field(field,val.$lt,'LT');
                            else
                            if (val.$gte!==undefined)
                              _field(field,val.$gte,'GE');
                            else
                            if (val.$lte!==undefined)
                              _field(field,val.$lte,'LE');
                            else
                            if (val.$in!==undefined)
                              _field(field,val.$in,'IN');
                            else
                            if (val.$exists!==undefined)
                              _field(field,undefined, val.$exists ? 'NOT_NULL' : 'NULL');
                            else
                              return canFind= false;
                       }
                   }
                   else
                     _field(field,val,'EQ');

                   return true;
           });

           return canFind;
      };

module.exports= function (dyn)
{
    var parser= {};

    parser.parse= function (table,modifiers,cond,projection,identity)
    {
        var p= dyn.promise('parsed'),
            query= { table: table, cond: cond || {}, projection: { root: {} } },
            _projection= function (root)
            {
              var proj= { include: ['$id','$ref'], exclude: []};

              _.keys(root).forEach(function (attr)
              {
                  if (root[attr].$include)
                  {
                    proj.include.push(attr);
                    proj.include.push('$$'+attr);
                    proj.include.push('$$$'+attr);
                  }
                  else
                  if (root[attr].$exclude)
                  {
                    proj.exclude.push(attr);
                    proj.exclude.push('$$'+attr);
                    proj.exclude.push('$$$'+attr);
                  }
              });

              if (proj.include.length==2)
                proj.include= undefined;

              return proj;
            };

        table.name= table._dynamo.TableName;
        table.indexes= table.indexes || [];

        query.project= _projection;
        query.soa= _soa;
        query.oa= _oa;

        if (modifiers.orderby)
        {
               var fields= [];

               Object.keys(modifiers.orderby).forEach(function (name)
               {
                   fields.push({ name: name, dir: modifiers.orderby[name] });
               });

               query.$orderby= fields;
        }

        query.toprojection= function (root)
        {
              var proj= {};

              _.keys(root || {}).forEach(function (attr)
              {
                  if (root[attr].$include)
                    proj[attr]= 1;
                  else
                  if (root[attr].$exclude)
                    proj[attr]= -1;
              });

              return proj;
        };

        if (projection&&_.keys(projection).length)
        {
          query.identity= {};

          query.identity.get= function ($id, $pos, done)
          {
             done();
          }

          query.identity.set= function (item)
          {
          }
        }
        else
        {
          if (identity&&identity.map)
              query.identity= identity;
          else
          {
              query.identity= {};
              query.identity.map= {};

              query.identity.get= function ($id, $pos, cb)
              {
                 var item= query.identity.map[$id+':'+$pos];

                 if (!item)
                 {
                   query.identity.map[$id+':'+$pos]= true;
                   cb();
                 }
                 else
                 if (item===true)
                   setTimeout(query.identity.get,100,$id,$pos,cb);
                 else
                   cb(item);
              }

              query.identity.set= function ($id, $pos, item)
              {
                 query.identity.map[$id+':'+$pos]= item;
              }
          }
        }

        process.nextTick(function ()
        {

            _.extend(query,modifiers);

            if (projection)
            {
                _.keys(projection).every(function (attr)
                {
                       if (projection[attr]==1)
                         _soa(query.projection.root,attr,{ $include: true });
                       else
                       if (projection[attr]==-1)
                         _soa(query.projection.root,attr,{ $exclude: true });
                       else
                       {
                         p.trigger.error(new Error('unknown projection value '+JSON.stringify(projection[attr])));
                         return false;
                       }

                       return true;
                });

                _.extend(query.projection,query.project(query.projection.root));
            }

            query.$supported= _buildFilter(query);
            query.$filtered= [];

            query.filterComplete= function ()
            {
               return Object.keys(query.$filter).length==0;
            };

            query.sortComplete= function ()
            {
               return !(query.orderby&&!query.sorted);
            };

            query.limitComplete= function ()
            {
               return !((query.limit!==undefined||query.skip!==undefined)&&!query.limited);
            };

            query.canLimit= function ()
            {
               return !query.limited
                    &&query.sortComplete()
                    &&query.filterComplete();
            };

            query.canCount= function ()
            {
               return query.filterComplete()
                    &&query.limitComplete();
            };

            p.trigger.parsed(query);

        });

        return p;
    };

    return parser;
};
<|endoftext|>


<commit_before>(function() {

	var sys = require('sys');
	var events = require('events');
	var ntwitter = require('ntwitter');

	function TDTwitterStream(options) {
		if (!(this instanceof TDTwitterStream)) { return new TDTwitterStream(options); }

		if (typeof options != "undefined")
		{
			this.set_options(options);
		}
	}

	TDTwitterStream.prototype = new events.EventEmitter();

	TDTwitterStream.prototype.set_options = function(options)
	{
		if (typeof options != "object")
		{
			this.emit("error", "Options must be an object");
		}

		this.options = options;
	}

	TDTwitterStream.prototype.get_options = function()
	{
		var defaults = {
			"auth": {
		      "consumer_key": null,
		      "consumer_secret": null,
		      "access_token_key": null,
		      "access_token_secret": null,
		    },
			"follow": [],
			"with": "followings"
		};

		return defaults.extend(this.options);
	}

	TDTwitterStream.prototype.check_options = function()
	{
		// Check we have all the info that we need
		var opts = this.get_options();

		// Starting with OAuth tokens (They're all required)
		for (i in opts.auth)
		{
			if (opts.auth[i] == null)
			{
				this.emit("error", "Option "+i+" is required");
			}
		}

		// Then a list of people to follow
		if (opts.follow.length < 1)
		{
			this.emit("error", "You need to follow at least one person's stream");
		}
	}

	TDTwitterStream.prototype.run = function()
	{
		var self = this; // Aliasing for later
		self.check_options(); // Check everything's valid

		// Fire up the ntwitter stream
		ntwit = new ntwitter(self.options.auth);
		ntwit.stream('site', {"follow": self.options.follow, "with": self.options.with}, function(stream) {

			stream.on("error", function (error) {
				console.log(sys.inspect(error));

				// Exit process so Forever can restart it
				stream.destroy();
				process.exit(1);
			});

			stream.on("end", function (end) {
				console.log(sys.inspect(end));

				// Exit process so Forever can restart it
				stream.destroy();
				process.exit(1);
			});

			var fs = require('fs');
			var file = fs.createWriteStream("/tmp/incoming_data");
			stream.on('data', function (data) {
				file.write( sys.inspect(data) + "\n\n" );

				// Run it through all our checks

				// Aimed at the system
				self._control(data);

				// Aimed at a user
				if (typeof data.for_user != "undefined")
				{
					self._connect(data.for_user, data.message);
				}

			});
		});

	}

	// "Private" methods of taking an envelope and checking if we need to do anything with it

	TDTwitterStream.prototype._control = function(data)
	{
		if (typeof data.control != "undefined")
		{
			this.emit("control", data.control.control_uri);
		}
	}

	TDTwitterStream.prototype._connect = function(recipient, data)
	{
		if (typeof data.friends != "undefined")
		{
			this.emit("connect", data.friends);
		}
	}

	TDTwitterStream.prototype._list = function(recipient, data)
	{
		if (typeof data.friends != "undefined")
		{
			this.emit("connect", data.friends);
		}
	}

	module.exports = TDTwitterStream;
}).call(this);

// Helpers

// via http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});<commit_msg>Events being emitted when a tweet comes in<commit_after>(function() {

	var sys = require('sys');
	var events = require('events');
	var ntwitter = require('ntwitter');

	function TDTwitterStream(options) {
		if (!(this instanceof TDTwitterStream)) { return new TDTwitterStream(options); }

		if (typeof options != "undefined")
		{
			this.set_options(options);
		}
	}

	TDTwitterStream.prototype = new events.EventEmitter();

	TDTwitterStream.prototype.set_options = function(options)
	{
		if (typeof options != "object")
		{
			this.emit("error", "Options must be an object");
		}

		this.options = options;
	}

	TDTwitterStream.prototype.merge_options = function()
	{
		var defaults = {
			"auth": {
				"consumer_key": null,
				"consumer_secret": null,
				"access_token_key": null,
				"access_token_secret": null,
			},
			"follow": [],
			"with": "followings"
		};

		this.options = defaults.extend(this.options);

		this.check_options();
	}

	TDTwitterStream.prototype.check_options = function()
	{
		// Starting with OAuth tokens (They're all required)
		for (i in this.options.auth)
		{
			if (this.options.auth[i] == null)
			{
				this.emit("error", "Option "+i+" is required");
			}
		}

		// Then a list of people to follow
		if (this.options.follow.length < 1)
		{
			this.emit("error", "You need to follow at least one person's stream");
		}

	}

	TDTwitterStream.prototype.run = function()
	{
		var self = this; // Aliasing for later
		self.merge_options(); // Make sure we use defaults if we need

		// Fire up the ntwitter stream
		ntwit = new ntwitter(self.options.auth);
		ntwit.stream('site', {"follow": self.options.follow, "with": self.options.with}, function(stream) {

			stream.on("error", function (error) {
				console.log(sys.inspect(error));

				// Exit process so Forever can restart it
				stream.destroy();
				process.exit(1);
			});

			stream.on("end", function (end) {
				console.log(sys.inspect(end));

				// Exit process so Forever can restart it
				stream.destroy();
				process.exit(1);
			});

			stream.on('data', function (data) {
				// Aimed at the system
				self._control(data);

				// Aimed at a user
				// We call all of these functions, but most won't do anything
				if (typeof data.for_user != "undefined")
				{
					self._connect(data.for_user, data.message);
					self._tweet(data.for_user, data.message);
				}

				//console.log(data);

			});
		});

	}

	// "Private" methods of taking an envelope and checking if we need to do anything with it

	TDTwitterStream.prototype._control = function(data)
	{
		if (typeof data.control != "undefined")
		{
			this.emit("control", data.control.control_uri);
		}
	}

	TDTwitterStream.prototype._connect = function(recipient, data)
	{
		if (typeof data.friends != "undefined")
		{
			this.emit("connect", data.friends);
		}
	}

	TDTwitterStream.prototype._tweet = function(recipient, data)
	{
		if (typeof data.text != "undefined")
		{
			// If it was a retweet
			if ( typeof data.retweeted_status != "undefined" )
			{
				this.emit("tweet", data.retweeted_status, data.retweeted_status.user);
				this.emit("retweet", data.retweeted_status, data);
				this.emit("user", data.retweeted_status.user);
			}
			else
			{
				this.emit("tweet", data, data.user);
			}

			// Always save the person that RT'd
			this.emit("user", data.user);

		}
	}

	module.exports = TDTwitterStream;
}).call(this);

// Helpers

// via http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});<|endoftext|>


<commit_before>/*
 * loopback-webpack-plugin
 * https://github.com/SimonDegraeve/loopback-webpack-plugin
 *
 * Copyright 2014, Simon Degraeve
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path');
var fs = require('fs');
var temp = require('temp').track();
var mockEmpty = 'webpack/node_modules/node-libs-browser/mock/empty';
var loopbackCompiler = resolveAndRequire('loopback-boot/lib/compiler');
var DefinePlugin = resolveAndRequire('webpack/lib/DefinePlugin');
var NormalModuleReplacementPlugin = resolveAndRequire('webpack/lib/NormalModuleReplacementPlugin');
var ContextReplacementPlugin = resolveAndRequire('webpack/lib/ContextReplacementPlugin');

module.exports = LoopbackBootPlugin;

function LoopbackBootPlugin(options) {
  // Same options as loopback-boot
  this.options = options || {};
}

LoopbackBootPlugin.prototype.apply = function(compiler) {
  var _this = this;

  // Default: Set the appRootDir to the last entry dirname
  var appRootDir = _this.options.appRootDir;
  if (!appRootDir) {
    var entry = compiler.options.entry;
    if (typeof entry === 'string') {
      appRootDir = path.dirname(entry);
    } else if (entry instanceof Array && entry.length > 0) {
      appRootDir = path.dirname(entry[entry.length - 1]);
    }
  }
  _this.options.appRootDir = path.resolve(process.cwd(), appRootDir || '');

  // Get compiled config from loopback and clean the absolute path
  _this.config = cleanPathInConfig(loopbackCompiler(_this.options));

  // Write config to a temp file
  _this.configPath = writeConfig(_this.config);

  // Get adapters from config
  _this.adapters = getAdaptersInConfig(_this.config);

  // Disable AMD => bugs with semver and eventemitter2
  new DefinePlugin({'define.amd': false}).apply(compiler);

  // Replacement
  [
    {regExp: /^loopback-boot#instructions$/, path: _this.configPath},
    {regExp: /^\.\/express-middleware$/, path: mockEmpty},
    {regExp: /^fs$/, path: mockEmpty},
    {regExp: /^ejs$/, path: 'ejs/ejs.js'}
  ].forEach(function(module) {
    new NormalModuleReplacementPlugin(module.regExp, module.path).apply(compiler);
  });

  var isModels = true;
  new ContextReplacementPlugin(/\./, function(result) {
    // Ignore useless modules
    if (/loopback\/lib(\/connectors)?$/.test(result.context) ||
        /loopback-datasource-juggler(\/lib)?$/.test(result.context)) {
      result.recursive = false;
      result.regExp = /^$/;
    }
    // Include remoting adapters
    if (/strong-remoting\/lib$/.test(result.context)) {
      result.recursive = false;
      result.regExp = new RegExp('^./(' + _this.adapters.join('|') + ')-adapter$');
    }
    // Include models/bootscripts and ignore middleware
    if (/loopback-boot\/lib$/.test(result.context)) {
      if (result.request === './middleware') {
        result.recursive = false;
        result.regExp = /^$/;
      } else {
        var items = isModels ? _this.config.models : _this.config.files.boot;
        var filePaths = items.filter(function(item) {
          return isModels ? typeof item.sourceFile !== 'undefined' : true;
        }).map(function(item) {
          return isModels ? item.sourceFile : item;
        });
        if (filePaths.length) {
          result.context = process.cwd();
          result.recursive = true;
          result.regExp = new RegExp('(' + filePaths.join('|') + ')$');
        }
        isModels = false;
      }
    }
  }).apply(compiler);

  // Remove warnings that we are handling
  compiler.plugin('done', function(stats) {
    stats.compilation.warnings = stats.compilation.warnings.filter(function(warning) {
      var request = warning.module.request;
      return warning.name === 'CriticalDependenciesWarning' &&
        !/loopback\/lib\/(connectors\/mail|application)\.js$/.test(request) &&
        !/loopback-boot\/lib\/executor\.js$/.test(request) &&
        !/loopback-datasource-juggler\/(index|lib\/(datasource|utils))\.js$/.test(request);
    });
  });
};

function cleanPathInConfig(config) {
  config.files.boot.forEach(function(bootScript, index) {
    config.files.boot[index] = './' + path.relative(process.cwd(), bootScript);
  });
  config.models.forEach(function(model, index) {
    if (model.sourceFile) {
      config.models[index].sourceFile = './' + path.relative(process.cwd(), model.sourceFile);
    }
  });
  return config;
}

function getAdaptersInConfig(config) {
  return Object.keys(config.dataSources).filter(function(key) {
    return config.dataSources[key].connector === 'remote';
  }).map(function(key) {
    return config.dataSources[key].adapter || 'rest';
  });
}

function writeConfig(config) {
  var file = temp.openSync({prefix: 'loopback-config-', suffix: '.json'});
  fs.writeSync(file.fd, JSON.stringify(config));
  fs.closeSync(file.fd);
  return file.path;
}

function resolveAndRequire(module) {
  return require(path.resolve(process.cwd(), 'node_modules/' + module));
}
<commit_msg>Fix bug when removing warning<commit_after>/*
 * loopback-webpack-plugin
 * https://github.com/SimonDegraeve/loopback-webpack-plugin
 *
 * Copyright 2014, Simon Degraeve
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path');
var fs = require('fs');
var temp = require('temp').track();
var mockEmpty = 'webpack/node_modules/node-libs-browser/mock/empty';
var loopbackCompiler = resolveAndRequire('loopback-boot/lib/compiler');
var DefinePlugin = resolveAndRequire('webpack/lib/DefinePlugin');
var NormalModuleReplacementPlugin = resolveAndRequire('webpack/lib/NormalModuleReplacementPlugin');
var ContextReplacementPlugin = resolveAndRequire('webpack/lib/ContextReplacementPlugin');

module.exports = LoopbackBootPlugin;

function LoopbackBootPlugin(options) {
  // Same options as loopback-boot
  this.options = options || {};
}

LoopbackBootPlugin.prototype.apply = function(compiler) {
  var _this = this;

  // Default: Set the appRootDir to the last entry dirname
  var appRootDir = _this.options.appRootDir;
  if (!appRootDir) {
    var entry = compiler.options.entry;
    if (typeof entry === 'string') {
      appRootDir = path.dirname(entry);
    } else if (entry instanceof Array && entry.length > 0) {
      appRootDir = path.dirname(entry[entry.length - 1]);
    }
  }
  _this.options.appRootDir = path.resolve(process.cwd(), appRootDir || '');

  // Get compiled config from loopback and clean the absolute path
  _this.config = cleanPathInConfig(loopbackCompiler(_this.options));

  // Write config to a temp file
  _this.configPath = writeConfig(_this.config);

  // Get adapters from config
  _this.adapters = getAdaptersInConfig(_this.config);

  // Disable AMD => bugs with semver and eventemitter2
  new DefinePlugin({'define.amd': false}).apply(compiler);

  // Replacement
  [
    {regExp: /^loopback-boot#instructions$/, path: _this.configPath},
    {regExp: /^\.\/express-middleware$/, path: mockEmpty},
    {regExp: /^fs$/, path: mockEmpty},
    {regExp: /^ejs$/, path: 'ejs/ejs.js'}
  ].forEach(function(module) {
    new NormalModuleReplacementPlugin(module.regExp, module.path).apply(compiler);
  });

  var isModels = true;
  new ContextReplacementPlugin(/\./, function(result) {
    // Ignore useless modules
    if (/loopback\/lib(\/connectors)?$/.test(result.context) ||
        /loopback-datasource-juggler(\/lib)?$/.test(result.context)) {
      result.recursive = false;
      result.regExp = /^$/;
    }
    // Include remoting adapters
    if (/strong-remoting\/lib$/.test(result.context)) {
      result.recursive = false;
      result.regExp = new RegExp('^./(' + _this.adapters.join('|') + ')-adapter$');
    }
    // Include models/bootscripts and ignore middleware
    if (/loopback-boot\/lib$/.test(result.context)) {
      if (result.request === './middleware') {
        result.recursive = false;
        result.regExp = /^$/;
      } else {
        var items = isModels ? _this.config.models : _this.config.files.boot;
        var filePaths = items.filter(function(item) {
          return isModels ? typeof item.sourceFile !== 'undefined' : true;
        }).map(function(item) {
          return isModels ? item.sourceFile : item;
        });
        if (filePaths.length) {
          result.context = process.cwd();
          result.recursive = true;
          result.regExp = new RegExp('(' + filePaths.join('|') + ')$');
        }
        isModels = false;
      }
    }
  }).apply(compiler);

  // Remove warnings that we are handling
  compiler.plugin('done', function(stats) {
    stats.compilation.warnings = stats.compilation.warnings.filter(function(warning) {
      var request = warning.module && warning.module.request;
      return warning.name === 'CriticalDependenciesWarning' &&
        !/loopback\/lib\/(connectors\/mail|application)\.js$/.test(request) &&
        !/loopback-boot\/lib\/executor\.js$/.test(request) &&
        !/loopback-datasource-juggler\/(index|lib\/(datasource|utils))\.js$/.test(request);
    });
  });
};

function cleanPathInConfig(config) {
  config.files.boot.forEach(function(bootScript, index) {
    config.files.boot[index] = './' + path.relative(process.cwd(), bootScript);
  });
  config.models.forEach(function(model, index) {
    if (model.sourceFile) {
      config.models[index].sourceFile = './' + path.relative(process.cwd(), model.sourceFile);
    }
  });
  return config;
}

function getAdaptersInConfig(config) {
  return Object.keys(config.dataSources).filter(function(key) {
    return config.dataSources[key].connector === 'remote';
  }).map(function(key) {
    return config.dataSources[key].adapter || 'rest';
  });
}

function writeConfig(config) {
  var file = temp.openSync({prefix: 'loopback-config-', suffix: '.json'});
  fs.writeSync(file.fd, JSON.stringify(config));
  fs.closeSync(file.fd);
  return file.path;
}

function resolveAndRequire(module) {
  return require(path.resolve(process.cwd(), 'node_modules/' + module));
}
<|endoftext|>


<commit_before>/*!
 * Expose `Poplar`.
 */

module.exports = Poplar;

/*!
 * Module dependencies.
 */

var EventEmitter = require('events').EventEmitter;
var debug = require('debug')('poplar:apis');
var util = require('util');
var Url = require('url');
var inherits = util.inherits;
var assert = require('assert');
var path = require('path');
var _ = require('lodash');
var minimatch = require('minimatch');

var Dynamic = require('./dynamic');
var ApiBuilder = require('./api_builder');

function Poplar(options) {
  EventEmitter.call(this);
  // Avoid warning: possible EventEmitter memory leak detected
  this.setMaxListeners(16);
  this.options = options || {};
  this._apiBuilders = {};
  this._methods = {};
  this._listenerTree = {};
};

/*!
 * Simplified APIs
 */

Poplar.create = function(options) {
  return new Poplar(options);
};

/*!
 * Inherit from `EventEmitter`.
 */

inherits(Poplar, EventEmitter);

/**
 * Get all methods
 */

Poplar.prototype.allMethods = function() {
  return _.values(this._methods) || [];
};

/**
 * Use a ApiBuilder
 */

Poplar.prototype.use = function(apiBuilder) {
  if (_.isObject(apiBuilder) && !(apiBuilder instanceof ApiBuilder)) {
    apiBuilder = new ApiBuilder(apiBuilder);
  }

  var name = apiBuilder.name;
  var self = this;

  // look up apiBuilder for the collection.
  if (!this._apiBuilders[name]) {
    if (apiBuilder) {
      // cache it so we only apply apiBuilders once
      this._apiBuilders[name] = apiBuilder;
      mergeListeners(apiBuilder);
      mergeMethods(apiBuilder);
    }
  } else {
    assert(false, util.format('Can\'t use the same ApiBuilder: %s more than once!', name));
  }

  // look up all ApiBuilder listeners then add it to api
  function mergeListeners(emitter) {
    var events = emitter._events;
    _.each(events, function(fns, type) {
      if (Array.isArray(fns)) {
        _.each(fns, function(fn) {
          if (_.isFunction(fn)) {
            self.on(type, fn);
          }
        })
      } else if (_.isFunction(fns)) {
        self.on(type, fns);
      }
    })
  };

  // look up all ApiBuilder methods then add it to api
  function mergeMethods(builder) {
    var methods = builder.methods();
    _.each(methods, function(fn, methodName) {
      // e.g.: users.getUserInfo
      self._methods[util.format('%s.%s', name, methodName)] = fn;
    });
  };
};

/**
 * Create a handler from the given adapter.
 *
 * @param {String} name Adapter name
 * @param {Object} options Adapter options
 * @return {Function}
 */

Poplar.prototype.handler = function(name, options) {
  var Adapter = this.adapter(name);
  var adapter = new Adapter(this, options);
  var handler = adapter.createHandler();

  if (handler) {
    // allow adapter reference from handler
    handler.adapter = adapter;
  }

  return handler;
};

/**
 * Get an adapter by name.
 * @param {String} name The adapter name
 * @return {Adapter}
 */
Poplar.prototype.adapter = function(name) {
  return require(path.join(__dirname, 'adapters', name));
};

/**
 * Define a named type conversion. The conversion is used when a
 * `ApiMethod` argument defines a type with the given `name`.
 *
 * ```js
 * api.defineType('MyType', function(val, ctx) {
 *   // use the val and ctx objects to return the concrete value
 *   return new MyType(val);
 * });
 * ```
 *
 * @param {String} name The type name
 * @param {Function} converter
 */

Poplar.defineType = function(name, fn) {
  Dynamic.define(name, fn);
};

/**
 * Execute the given function before the matched method string.
 *
 * **Examples:**
 *
 * ```js
 * // Do something before our `user.greet` example, earlier.
 * api.before('user.greet', function(ctx, next) {
 *   if ((ctx.req.param('password') || '').toString() !== '1234') {
 *     next(new Error('Bad password!'));
 *   } else {
 *     next();
 *   }
 * });
 *
 * // Do something before any `user` method.
 * api.before('user.*', function(ctx, next) {
 *   console.log('Calling a user method.');
 *   next();
 * });
 *
 * // Do something before a `dog` instance method.
 * api.before('dog.*', function(ctx, next) {
 *   var dog = this;
 *   console.log('Calling a method on "%s".', dog.name);
 *   next();
 * });
 * ```
 *
 * @param {String} methodMatch The glob to match a method string
 * @callback {Function} hook
 * @param {Context} ctx The adapter specific context
 * @param {Function} next Call with an optional error object
 * @param {ApiMethod} method The ApiMethod object
 */

Poplar.prototype.before = function(methodMatch, fn) {
  this.on('before.' + methodMatch, fn);
};

/**
 * Execute the given `hook` function after the matched method string.
 *
 * **Examples:**
 *
 * ```js
 * // Do something after the `speak` instance method.
 * // NOTE: you cannot cancel a method after it has been called.
 * api.after('dog.speak', function(ctx, next) {
 *   console.log('After speak!');
 *   next();
 * });
 *
 * // Do something before all methods.
 * api.before('**', function(ctx, next, method) {
 *   console.log('Calling:', method.name);
 *   next();
 * });
 *
 * // Modify all returned values named `result`.
 * api.after('**', function(ctx, next) {
 *   ctx.result += '!!!';
 *   next();
 * });
 * ```
 *
 * @param {String} methodMatch The glob to match a method string
 * @callback {Function} hook
 * @param {Context} ctx The adapter specific context
 * @param {Function} next Call with an optional error object
 * @param {ApiMethod} method The ApiMethod object
 */

Poplar.prototype.after = function(methodMatch, fn) {
  this.on('after.' + methodMatch, fn);
};

/**
 * Execute the given `hook` function after the method matched by the method
 * string failed.
 *
 * **Examples:**
 *
 * ```js
 * // Do something after the `speak` instance method failed.
 * api.afterError('dog.speak', function(ctx, next) {
 *   console.log('Cannot speak!', ctx.error);
 *   next();
 * });
 *
 * // Do something before all methods.
 * api.afterError('**', function(ctx, next, method) {
 *   console.log('Failed', method.name, ctx.error);
 *   next();
 * });
 *
 * // Modify all returned errors
 * api.after('**', function(ctx, next) {
 *   if (!ctx.error.details) ctx.result.details = {};
 *   ctx.error.details.info = 'intercepted by a hook';
 *   next();
 * });
 *
 * // Report a different error
 * api.after('dog.speak', function(ctx, next) {
 *   console.error(ctx.error);
 *   next(new Error('See server console log for details.'));
 * });
 * ```
 *
 * @param {String} methodMatch The glob to match a method string
 * @callback {Function} hook
 * @param {Context} ctx The adapter specific context
 * @param {Function} next Call with an optional error object
 * @param {ApiMethod} method The ApiMethod object
 */

Poplar.prototype.afterError = function(methodMatch, fn) {
  this.on('afterError.' + methodMatch, fn);
};

/*!
 * Execute Hooks by type and method.
 */

Poplar.prototype.execHooks = function(when, method, ctx, next) {
  var methodName = method.fullName();
  var stack = [];

  var listenerNames = this.searchListenerTree(methodName, when);

  if (_.isEmpty(stack)) {
    listenerNames = this.searchListeners(methodName, when);
  }

  var self = this;

  listenerNames.forEach(function(listenerName) {
    addToStack(self.listeners(listenerName));
  });

  function addToStack(fn) {
    stack = stack.concat(fn);
  }

  function execStack(err) {
    if (err) return next(err);

    var cur = stack.shift();

    if (cur) {
      try {
        var result = cur.call(method, ctx, execStack, method);
        if (result && typeof result.then === 'function') {
          result.then(function() { next(); }, next);
        }
      } catch (err) {
        next(err);
      }
    } else {
      next();
    }
  }

  return execStack();
};

/**
 * Invoke the given api method using the supplied context.
 * Execute registered before/after hooks.
 * @param {Object} ctx
 * @param {Object} method
 * @param {function(Error=)} cb
 */
Poplar.prototype.invokeMethodInContext = function(ctx, method, cb) {
  var self = this;

  self.execHooks('before', method, ctx, function(err) {
    if (err) return triggerErrorAndCallBack(err);

    method.invoke(ctx, function(err, result) {
      ctx.result = result;
      if (err) return cb(err);

      self.execHooks('after', method, ctx, function(err) {
        if (err) return triggerErrorAndCallBack(err);
        cb();
      });
    });

  });

  function triggerErrorAndCallBack(err) {
    ctx.error = err;
    self.execHooks('afterError', method, ctx, function(hookErr) {
      cb(hookErr || err);
    });
  }
};

/*!
 * Search listeners before or after a given method is called
 * @param {String} methodName name for method
 * @param {String} type: `before`, `after`, `afterError`
 */

Poplar.prototype.searchListeners = function(methodName, type) {
  var allListenerNames = Object.keys(this._events);
  var listenerNames = [];
  var fullType = util.format('%s.%s', type, methodName);
  _.each(allListenerNames, function(name) {
    if (minimatch(fullType, name)) {
      listenerNames.push(name);
    }
  })
  return listenerNames;
};

/*!
 * Search listenerTree before or after a given method is called
 * @param {String} methodName name for method
 * @param {String} type: `before`, `after`, `afterError`
 */

Poplar.prototype.searchListenerTree = function(methodName, type) {
  var listeners = this._listenerTree[methodName];
  if (listeners) {
    return listeners[type];
  } else {
    return [];
  }
};

/*!
 * Analyze all listeners coorespond with methods
 *
 * {
 *   'users.info': {
 *     before: ['before.users.*', 'before.users.info'],
 *     after: ['after.users.*', 'after.users.info'],
 *     afterError: ['afterError.users.*', 'afterError.users.info']
 *   }
 * }
 */

Poplar.prototype.analyzeListenerTree = function() {
  var methods = this._methods;
  var listenerTree = {};
  var self = this;

  _.each(methods, function(fn, name) {
    listenerTree[name] = listenerTree[name] || {};
    ['before', 'after', 'afterError'].forEach(function(type) {
      listenerTree[name][type] = self.searchListeners(name, type) || [];
    });
  });

  this._listenerTree = listenerTree;
};
<commit_msg>edit comments<commit_after>/*!
 * Expose `Poplar`.
 */

module.exports = Poplar;

/*!
 * Module dependencies.
 */

var EventEmitter = require('events').EventEmitter;
var debug = require('debug')('poplar:apis');
var util = require('util');
var Url = require('url');
var inherits = util.inherits;
var assert = require('assert');
var path = require('path');
var _ = require('lodash');
var minimatch = require('minimatch');

var Dynamic = require('./dynamic');
var ApiBuilder = require('./api_builder');

function Poplar(options) {
  EventEmitter.call(this);
  // Avoid warning: possible EventEmitter memory leak detected
  this.setMaxListeners(16);
  this.options = options || {};
  this._apiBuilders = {};
  this._methods = {};
  this._listenerTree = {};
};

/*!
 * Simplified APIs
 */
Poplar.create = function(options) {
  return new Poplar(options);
};

/*!
 * Inherit from `EventEmitter`.
 */
inherits(Poplar, EventEmitter);

/**
 * Get all methods
 */
Poplar.prototype.allMethods = function() {
  return _.values(this._methods) || [];
};

/**
 * Use a ApiBuilder
 */
Poplar.prototype.use = function(apiBuilder) {
  if (_.isObject(apiBuilder) && !(apiBuilder instanceof ApiBuilder)) {
    apiBuilder = new ApiBuilder(apiBuilder);
  }

  var name = apiBuilder.name;
  var self = this;

  // look up apiBuilder for the collection.
  if (!this._apiBuilders[name]) {
    if (apiBuilder) {
      // cache it so we only apply apiBuilders once
      this._apiBuilders[name] = apiBuilder;
      mergeListeners(apiBuilder);
      mergeMethods(apiBuilder);
    }
  } else {
    assert(false, util.format('Can\'t use the same ApiBuilder: %s more than once!', name));
  }

  // look up all ApiBuilder listeners then add it to api
  function mergeListeners(emitter) {
    var events = emitter._events;
    _.each(events, function(fns, type) {
      if (Array.isArray(fns)) {
        _.each(fns, function(fn) {
          if (_.isFunction(fn)) {
            self.on(type, fn);
          }
        })
      } else if (_.isFunction(fns)) {
        self.on(type, fns);
      }
    })
  };

  // look up all ApiBuilder methods then add it to api
  function mergeMethods(builder) {
    var methods = builder.methods();
    _.each(methods, function(fn, methodName) {
      // e.g.: users.getUserInfo
      self._methods[util.format('%s.%s', name, methodName)] = fn;
    });
  };
};

/**
 * Create a handler from the given adapter.
 *
 * @param {String} name Adapter name
 * @param {Object} options Adapter options
 * @return {Function}
 */
Poplar.prototype.handler = function(name, options) {
  var Adapter = this.adapter(name);
  var adapter = new Adapter(this, options);
  var handler = adapter.createHandler();

  if (handler) {
    // allow adapter reference from handler
    handler.adapter = adapter;
  }

  return handler;
};

/**
 * Get an adapter by name.
 * @param {String} name The adapter name
 * @return {Adapter}
 */
Poplar.prototype.adapter = function(name) {
  return require(path.join(__dirname, 'adapters', name));
};

/**
 * Define a named type conversion. The conversion is used when a
 * `ApiMethod` argument defines a type with the given `name`.
 *
 * ```js
 * api.defineType('MyType', function(val, ctx) {
 *   // use the val and ctx objects to return the concrete value
 *   return new MyType(val);
 * });
 * ```
 *
 * @param {String} name The type name
 * @param {Function} converter
 */
Poplar.defineType = function(name, fn) {
  Dynamic.define(name, fn);
};

/**
 * Execute the given function before the matched method string.
 *
 * **Examples:**
 *
 * ```js
 * // Do something before our `user.greet` example, earlier.
 * api.before('user.greet', function(ctx, next) {
 *   if ((ctx.req.param('password') || '').toString() !== '1234') {
 *     next(new Error('Bad password!'));
 *   } else {
 *     next();
 *   }
 * });
 *
 * // Do something before any `user` method.
 * api.before('user.*', function(ctx, next) {
 *   console.log('Calling a user method.');
 *   next();
 * });
 *
 * // Do something before a `dog` instance method.
 * api.before('dog.*', function(ctx, next) {
 *   var dog = this;
 *   console.log('Calling a method on "%s".', dog.name);
 *   next();
 * });
 * ```
 *
 * @param {String} methodMatch The glob to match a method string
 * @callback {Function} hook
 * @param {Context} ctx The adapter specific context
 * @param {Function} next Call with an optional error object
 * @param {ApiMethod} method The ApiMethod object
 */
Poplar.prototype.before = function(methodMatch, fn) {
  this.on('before.' + methodMatch, fn);
};

/**
 * Execute the given `hook` function after the matched method string.
 *
 * **Examples:**
 *
 * ```js
 * // Do something after the `speak` instance method.
 * // NOTE: you cannot cancel a method after it has been called.
 * api.after('dog.speak', function(ctx, next) {
 *   console.log('After speak!');
 *   next();
 * });
 *
 * // Do something before all methods.
 * api.before('**', function(ctx, next, method) {
 *   console.log('Calling:', method.name);
 *   next();
 * });
 *
 * // Modify all returned values named `result`.
 * api.after('**', function(ctx, next) {
 *   ctx.result += '!!!';
 *   next();
 * });
 * ```
 *
 * @param {String} methodMatch The glob to match a method string
 * @callback {Function} hook
 * @param {Context} ctx The adapter specific context
 * @param {Function} next Call with an optional error object
 * @param {ApiMethod} method The ApiMethod object
 */
Poplar.prototype.after = function(methodMatch, fn) {
  this.on('after.' + methodMatch, fn);
};

/**
 * Execute the given `hook` function after the method matched by the method
 * string failed.
 *
 * **Examples:**
 *
 * ```js
 * // Do something after the `speak` instance method failed.
 * api.afterError('dog.speak', function(ctx, next) {
 *   console.log('Cannot speak!', ctx.error);
 *   next();
 * });
 *
 * // Do something before all methods.
 * api.afterError('**', function(ctx, next, method) {
 *   console.log('Failed', method.name, ctx.error);
 *   next();
 * });
 *
 * // Modify all returned errors
 * api.after('**', function(ctx, next) {
 *   if (!ctx.error.details) ctx.result.details = {};
 *   ctx.error.details.info = 'intercepted by a hook';
 *   next();
 * });
 *
 * // Report a different error
 * api.after('dog.speak', function(ctx, next) {
 *   console.error(ctx.error);
 *   next(new Error('See server console log for details.'));
 * });
 * ```
 *
 * @param {String} methodMatch The glob to match a method string
 * @callback {Function} hook
 * @param {Context} ctx The adapter specific context
 * @param {Function} next Call with an optional error object
 * @param {ApiMethod} method The ApiMethod object
 */
Poplar.prototype.afterError = function(methodMatch, fn) {
  this.on('afterError.' + methodMatch, fn);
};

/*!
 * Execute Hooks by type and method.
 */
Poplar.prototype.execHooks = function(when, method, ctx, next) {
  var methodName = method.fullName();
  var stack = [];

  var listenerNames = this.searchListenerTree(methodName, when);

  if (_.isEmpty(stack)) {
    listenerNames = this.searchListeners(methodName, when);
  }

  var self = this;

  listenerNames.forEach(function(listenerName) {
    addToStack(self.listeners(listenerName));
  });

  function addToStack(fn) {
    stack = stack.concat(fn);
  }

  function execStack(err) {
    if (err) return next(err);

    var cur = stack.shift();

    if (cur) {
      try {
        var result = cur.call(method, ctx, execStack, method);
        if (result && typeof result.then === 'function') {
          result.then(function() { next(); }, next);
        }
      } catch (err) {
        next(err);
      }
    } else {
      next();
    }
  }

  return execStack();
};

/**
 * Invoke the given api method using the supplied context.
 * Execute registered before/after hooks.
 * @param {Object} ctx
 * @param {Object} method
 * @param {function(Error=)} cb
 */
Poplar.prototype.invokeMethodInContext = function(ctx, method, cb) {
  var self = this;

  self.execHooks('before', method, ctx, function(err) {
    if (err) return triggerErrorAndCallBack(err);

    method.invoke(ctx, function(err, result) {
      ctx.result = result;
      if (err) return cb(err);

      self.execHooks('after', method, ctx, function(err) {
        if (err) return triggerErrorAndCallBack(err);
        cb();
      });
    });

  });

  function triggerErrorAndCallBack(err) {
    ctx.error = err;
    self.execHooks('afterError', method, ctx, function(hookErr) {
      cb(hookErr || err);
    });
  }
};

/*!
 * Search listeners before or after a given method is called
 * @param {String} methodName name for method
 * @param {String} type: `before`, `after`, `afterError`
 */
Poplar.prototype.searchListeners = function(methodName, type) {
  var allListenerNames = Object.keys(this._events);
  var listenerNames = [];
  var fullType = util.format('%s.%s', type, methodName);
  _.each(allListenerNames, function(name) {
    if (minimatch(fullType, name)) {
      listenerNames.push(name);
    }
  })
  return listenerNames;
};

/*!
 * Search listenerTree before or after a given method is called
 * @param {String} methodName name for method
 * @param {String} type: `before`, `after`, `afterError`
 */
Poplar.prototype.searchListenerTree = function(methodName, type) {
  var listeners = this._listenerTree[methodName];
  if (listeners) {
    return listeners[type];
  } else {
    return [];
  }
};

/*!
 * Analyze all listeners coorespond with methods
 *
 * {
 *   'users.info': {
 *     before: ['before.users.*', 'before.users.info'],
 *     after: ['after.users.*', 'after.users.info'],
 *     afterError: ['afterError.users.*', 'afterError.users.info']
 *   }
 * }
 */
Poplar.prototype.analyzeListenerTree = function() {
  var methods = this._methods;
  var listenerTree = {};
  var self = this;

  _.each(methods, function(fn, name) {
    listenerTree[name] = listenerTree[name] || {};
    ['before', 'after', 'afterError'].forEach(function(type) {
      listenerTree[name][type] = self.searchListeners(name, type) || [];
    });
  });

  this._listenerTree = listenerTree;
};
<|endoftext|>