<commit_before>const _ = require('lodash');

const configure = require('./configure');

const branches = require('./utils/branches');
const execution = require('./utils/execution');

module.exports = (() => {
  const ARGUMENTS = {
    NEW_VERSION_BRANCH: {
      name: 'version',
      alias: 'v',
      describe: 'Version to use to create a new version branch',
      type: 'string'
    },
    NEW_FEATURE_BRANCH: {
      name: 'feature',
      alias: 'f',
      describe: 'Feature to use to create a new feature branch',
      type: 'string'
    },
    NEW_DEV_BRANCH: {
      name: 'dev',
      alias: 'd',
      describe: 'Description to use to create a new dev branch',
      type: 'string'
    },
    TICKET_NUMBER: {
      name: 'ticket-number',
      alias: 'n',
      describe: 'Specifies the ticket number when creating a new branch',
      type: 'integer'
    },
    IS_BUILDABLE: {
      name: 'buildable',
      alias: 'b',
      describe: 'Specifies if the new branch should be buildable (only available on feature branches)',
      type: 'boolean'
    }
  };

  const createBranch = (newParsedBranch, gutOptions) => {
    const newBranchDescription = _.cloneDeep(newParsedBranch);
    newBranchDescription.author = gutOptions.accounts.github; // TODO: change when adding new git servers
    newBranchDescription.baseBranch = branches.getCurrentBranch();

    const newBranchName = branches.buildBranchName(newParsedBranch);

    execution.execute(`git checkout -b ${newBranchName}`);
    execution.execute(`git config branch.${newBranchName}.description '${JSON.stringify(newParsedBranch)}'`);
  };

  const createVersionBranch = (parsedBranch, args, gutOptions) => {
    const newVersion = args[ ARGUMENTS.NEW_VERSION_BRANCH.name ];
    if (!branches.isMasterBranch(parsedBranch)) {
      throw Error('It is only allowed to create version branches from master!'.red);
    }

    const newParsedBranch = _.cloneDeep(parsedBranch);
    newParsedBranch.version = newVersion;
    newParsedBranch.type = branches.BRANCH_TYPES.VERSION.name;

    createBranch(newParsedBranch, gutOptions);
  };

  const createFeatureBranch = (parsedBranch, args, gutOptions) => {
    const newFeature = args[ ARGUMENTS.NEW_FEATURE_BRANCH.name ];
    const isBuildable = args[ ARGUMENTS.IS_BUILDABLE.name ];
    if (!branches.isMasterBranch(parsedBranch) && !branches.isVersionBranch(parsedBranch)) {
      throw Error('It is only allowed to create feature branches from version branches or master!'.red);
    }

    const newParsedBranch = _.cloneDeep(parsedBranch);
    newParsedBranch.feature = newFeature;
    newParsedBranch.isBuildable = isBuildable;
    newParsedBranch.type = branches.BRANCH_TYPES.FEATURE.name;

    createBranch(newParsedBranch, gutOptions);
  };

  const createDevBranch = (parsedBranch, args, gutOptions) => {
    const newDescription = args[ ARGUMENTS.NEW_DEV_BRANCH.name ];
    const newTicketNumber = args[ ARGUMENTS.TICKET_NUMBER.name ] || '';
    if (!branches.isVersionBranch(parsedBranch) && !branches.isFeatureBranch(parsedBranch)) {
      throw Error('It is only allowed to create dev branches from version or feature branches!'.red);
    }

    const newParsedBranch = _.cloneDeep(parsedBranch);
    newParsedBranch.ticketNumber = newTicketNumber;
    newParsedBranch.description = newDescription;
    newParsedBranch.type = branches.BRANCH_TYPES.DEV.name;

    createBranch(newParsedBranch, gutOptions);
  };

  const hasNoneOf = (forbiddenCharacters, argument, argumentName) => {
    const hasForbiddenCharacters = _.some(
      forbiddenCharacters,
      forbiddenCharacter => argument.includes(forbiddenCharacter)
    );
    if (hasForbiddenCharacters) {
      const forbiddenCharactersAsString = _.map(forbiddenCharacters, char => `'${char}'`); // TODO: stringification via lodash ?
      throw Error(`Argument ${argumentName} can't contain any of these characters [ ${forbiddenCharactersAsString} ]`.red);
    }
    return argument;
  };

  return {

    burgeon: (yargs) => {
      configure.configureGutIfNeeded()
        .then(gutOptions => {
          const args = yargs
            .usage('usage: $0 burgeon [options]')
            .option(ARGUMENTS.NEW_VERSION_BRANCH.name, ARGUMENTS.NEW_VERSION_BRANCH)
            .option(ARGUMENTS.NEW_FEATURE_BRANCH.name, ARGUMENTS.NEW_FEATURE_BRANCH)
            .option(ARGUMENTS.NEW_DEV_BRANCH.name, ARGUMENTS.NEW_DEV_BRANCH)
            .option(ARGUMENTS.TICKET_NUMBER.name, ARGUMENTS.TICKET_NUMBER)
            .option(ARGUMENTS.IS_BUILDABLE.name, ARGUMENTS.IS_BUILDABLE)
            .check(currentArguments => {
              const newFeatureBranch = currentArguments[ ARGUMENTS.NEW_FEATURE_BRANCH.name ];
              const newDevBranch = currentArguments[ ARGUMENTS.NEW_DEV_BRANCH.name ];

              if (currentArguments[ ARGUMENTS.TICKET_NUMBER.name ] && !newDevBranch) {
                throw Error(`Argument ${ARGUMENTS.TICKET_NUMBER.name} only makes sense when creating a dev branch`.red);
              }

              if (currentArguments[ ARGUMENTS.IS_BUILDABLE.name ] && !newFeatureBranch) {
                throw Error(`Argument ${ARGUMENTS.IS_BUILDABLE.name} only makes sense when creating a feature branch`.red);
              }

              return true;
            })
            .coerce(ARGUMENTS.NEW_VERSION_BRANCH.name, argument => {
              if (_.isEmpty(argument)) {
                return argument;
              }

              if (!/[0.9]+\.[0.9]+\.[0.9]+(\.[0.9]+)?/.test(argument)) { // TODO: Use semver instead
                throw Error(`Argument ${ARGUMENTS.NEW_VERSION_BRANCH.name} must follow semver!`.red);
              }
              return argument;
            })
            .coerce(ARGUMENTS.NEW_FEATURE_BRANCH.name, argument => hasNoneOf([ '_', '#' ], argument, ARGUMENTS.NEW_FEATURE_BRANCH.name))
            .coerce(ARGUMENTS.NEW_DEV_BRANCH.name, argument => hasNoneOf([ '_', '#' ], argument, ARGUMENTS.NEW_DEV_BRANCH.name))
            .argv;

          const parsedBranch = branches.parseBranchName();
          if (args[ ARGUMENTS.NEW_VERSION_BRANCH.name ]) {
            createVersionBranch(parsedBranch, args, gutOptions);
          } else if (args[ ARGUMENTS.NEW_FEATURE_BRANCH.name ]) {
            createFeatureBranch(parsedBranch, args, gutOptions);
          } else {
            createDevBranch(parsedBranch, args, gutOptions);
          }
        });
    }
  };
})();
<commit_msg>:bug: Fix burgeon not adding base branch and author<commit_after>const _ = require('lodash');

const configure = require('./configure');

const branches = require('./utils/branches');
const execution = require('./utils/execution');

module.exports = (() => {
  const ARGUMENTS = {
    NEW_VERSION_BRANCH: {
      name: 'version',
      alias: 'v',
      describe: 'Version to use to create a new version branch',
      type: 'string'
    },
    NEW_FEATURE_BRANCH: {
      name: 'feature',
      alias: 'f',
      describe: 'Feature to use to create a new feature branch',
      type: 'string'
    },
    NEW_DEV_BRANCH: {
      name: 'dev',
      alias: 'd',
      describe: 'Description to use to create a new dev branch',
      type: 'string'
    },
    TICKET_NUMBER: {
      name: 'ticket-number',
      alias: 'n',
      describe: 'Specifies the ticket number when creating a new branch',
      type: 'integer'
    },
    IS_BUILDABLE: {
      name: 'buildable',
      alias: 'b',
      describe: 'Specifies if the new branch should be buildable (only available on feature branches)',
      type: 'boolean'
    }
  };

  const createBranch = (newParsedBranch, gutOptions) => {
    const newBranchDescription = _.cloneDeep(newParsedBranch);
    newBranchDescription.author = gutOptions.accounts.github; // TODO: change when adding new git servers
    newBranchDescription.baseBranch = branches.getCurrentBranch();

    const newBranchName = branches.buildBranchName(newBranchDescription);

    execution.execute(`git checkout -b ${newBranchName}`);
    execution.execute(`git config branch.${newBranchName}.description '${JSON.stringify(newBranchDescription)}'`);
  };

  const createVersionBranch = (parsedBranch, args, gutOptions) => {
    const newVersion = args[ ARGUMENTS.NEW_VERSION_BRANCH.name ];
    if (!branches.isMasterBranch(parsedBranch)) {
      throw Error('It is only allowed to create version branches from master!'.red);
    }

    const newParsedBranch = _.cloneDeep(parsedBranch);
    newParsedBranch.version = newVersion;
    newParsedBranch.type = branches.BRANCH_TYPES.VERSION.name;

    createBranch(newParsedBranch, gutOptions);
  };

  const createFeatureBranch = (parsedBranch, args, gutOptions) => {
    const newFeature = args[ ARGUMENTS.NEW_FEATURE_BRANCH.name ];
    const isBuildable = args[ ARGUMENTS.IS_BUILDABLE.name ];
    if (!branches.isMasterBranch(parsedBranch) && !branches.isVersionBranch(parsedBranch)) {
      throw Error('It is only allowed to create feature branches from version branches or master!'.red);
    }

    const newParsedBranch = _.cloneDeep(parsedBranch);
    newParsedBranch.feature = newFeature;
    newParsedBranch.isBuildable = isBuildable;
    newParsedBranch.type = branches.BRANCH_TYPES.FEATURE.name;

    createBranch(newParsedBranch, gutOptions);
  };

  const createDevBranch = (parsedBranch, args, gutOptions) => {
    const newDescription = args[ ARGUMENTS.NEW_DEV_BRANCH.name ];
    const newTicketNumber = args[ ARGUMENTS.TICKET_NUMBER.name ] || '';
    if (!branches.isVersionBranch(parsedBranch) && !branches.isFeatureBranch(parsedBranch)) {
      throw Error('It is only allowed to create dev branches from version or feature branches!'.red);
    }

    const newParsedBranch = _.cloneDeep(parsedBranch);
    newParsedBranch.ticketNumber = newTicketNumber;
    newParsedBranch.description = newDescription;
    newParsedBranch.type = branches.BRANCH_TYPES.DEV.name;

    createBranch(newParsedBranch, gutOptions);
  };

  const hasNoneOf = (forbiddenCharacters, argument, argumentName) => {
    const hasForbiddenCharacters = _.some(
      forbiddenCharacters,
      forbiddenCharacter => argument.includes(forbiddenCharacter)
    );
    if (hasForbiddenCharacters) {
      const forbiddenCharactersAsString = _.map(forbiddenCharacters, char => `'${char}'`); // TODO: stringification via lodash ?
      throw Error(`Argument ${argumentName} can't contain any of these characters [ ${forbiddenCharactersAsString} ]`.red);
    }
    return argument;
  };

  return {

    burgeon: (yargs) => {
      configure.configureGutIfNeeded()
        .then(gutOptions => {
          const args = yargs
            .usage('usage: $0 burgeon [options]')
            .option(ARGUMENTS.NEW_VERSION_BRANCH.name, ARGUMENTS.NEW_VERSION_BRANCH)
            .option(ARGUMENTS.NEW_FEATURE_BRANCH.name, ARGUMENTS.NEW_FEATURE_BRANCH)
            .option(ARGUMENTS.NEW_DEV_BRANCH.name, ARGUMENTS.NEW_DEV_BRANCH)
            .option(ARGUMENTS.TICKET_NUMBER.name, ARGUMENTS.TICKET_NUMBER)
            .option(ARGUMENTS.IS_BUILDABLE.name, ARGUMENTS.IS_BUILDABLE)
            .check(currentArguments => {
              const newFeatureBranch = currentArguments[ ARGUMENTS.NEW_FEATURE_BRANCH.name ];
              const newDevBranch = currentArguments[ ARGUMENTS.NEW_DEV_BRANCH.name ];

              if (currentArguments[ ARGUMENTS.TICKET_NUMBER.name ] && !newDevBranch) {
                throw Error(`Argument ${ARGUMENTS.TICKET_NUMBER.name} only makes sense when creating a dev branch`.red);
              }

              if (currentArguments[ ARGUMENTS.IS_BUILDABLE.name ] && !newFeatureBranch) {
                throw Error(`Argument ${ARGUMENTS.IS_BUILDABLE.name} only makes sense when creating a feature branch`.red);
              }

              return true;
            })
            .coerce(ARGUMENTS.NEW_VERSION_BRANCH.name, argument => {
              if (_.isEmpty(argument)) {
                return argument;
              }

              if (!/[0.9]+\.[0.9]+\.[0.9]+(\.[0.9]+)?/.test(argument)) { // TODO: Use semver instead
                throw Error(`Argument ${ARGUMENTS.NEW_VERSION_BRANCH.name} must follow semver!`.red);
              }
              return argument;
            })
            .coerce(ARGUMENTS.NEW_FEATURE_BRANCH.name, argument => hasNoneOf([ '_', '#' ], argument, ARGUMENTS.NEW_FEATURE_BRANCH.name))
            .coerce(ARGUMENTS.NEW_DEV_BRANCH.name, argument => hasNoneOf([ '_', '#' ], argument, ARGUMENTS.NEW_DEV_BRANCH.name))
            .argv;

          const parsedBranch = branches.parseBranchName();
          if (args[ ARGUMENTS.NEW_VERSION_BRANCH.name ]) {
            createVersionBranch(parsedBranch, args, gutOptions);
          } else if (args[ ARGUMENTS.NEW_FEATURE_BRANCH.name ]) {
            createFeatureBranch(parsedBranch, args, gutOptions);
          } else {
            createDevBranch(parsedBranch, args, gutOptions);
          }
        });
    }
  };
})();
<|endoftext|>


<commit_before>'use strict'
var Observable = require('vigour-js/lib/observable')
var isEmpty = require('vigour-js/lib/util/is/empty')
var Clients = new Observable({
  ChildConstructor: require('./client'),
  noContext: true,
  on: {
    property: {
      removeScope (data) {
        console.error('PROP FIRES!', data)
        if (data && this._scope && this.parent.autoRemoveScopes && data.removed) {
          if (isEmpty(this)) {
            console.error('OK LETS REMOVE THIS! (if scope)', this._path)
          }
        }
      }
    }
  }
}).Constructor

exports.properties = {
  clients (data, event) {
    if (!this.hasOwnProperty('clients')) {
      this.clients = new Clients(data, event, this, 'clients')
    } else {
      this.clients.set(data, event)
    }
  }
}
<commit_msg>correct location to remove scope when clients is empty<commit_after>'use strict'
var Observable = require('vigour-js/lib/observable')
var isEmpty = require('vigour-js/lib/util/is/empty')
var Clients = new Observable({
  ChildConstructor: require('./client'),
  noContext: true,
  on: {
    property: {
      removeScope (data) {
        if (data && this.parent._scope && this.parent.autoRemoveScopes && data.removed) {
          if (isEmpty(this)) {
            console.error('OK LETS REMOVE THIS! (if scope)', this._path)
          }
        }
      }
    }
  }
}).Constructor

exports.properties = {
  clients (data, event) {
    if (!this.hasOwnProperty('clients')) {
      this.clients = new Clients(data, event, this, 'clients')
    } else {
      this.clients.set(data, event)
    }
  }
}
<|endoftext|>


<commit_before>var path   = require("path"),
    fs     = require("fs"),
    nomnom = require("nomnom"),
    yawp  = require("./yawp"),
    config = {};

// Configuration file
nomnom.option("config", {
    abbr      : "c",
    help      : "Yawp run configuration file",
    default   : ".yawpfile",
    transform : function(loc) {
        if(!loc) return;
        config = JSON.parse(fs.readFileSync(path.resolve(loc), "utf8"));
        return loc;
    }
});

// Json source file
nomnom.option("source", {
    abbr      : "s",
    help      : "Path to JSON source file"
});

// Directory to putput to
nomnom.option("output", {
    abbr      : "o",
    help      : "Path to output file"
});

// Name of initial template
nomnom.option("template", {
    abbr      : "t",
    help      : "Name of main template"
});

// Path to template directory
nomnom.option("template-dir", {
    abbr      : "td",
    help      : "Path to templates directory"
});

function checkConfig(opts) {
    var valid = ["source", "output", "template-dir"];

    valid = valid.every(function(name) {
        var loc;

        if(loc = opts[name]) {
            config[name] = path.resolve(loc);
        } else if(loc = config[name]) {
            config[name] = path.resolve(loc);
        }

        return !!loc;
    });

    return valid;
}

if(checkConfig(nomnom.parse())) {
    yawp.run(config);
}
<commit_msg>Will now load yawpfile from default location when no params provided<commit_after>var path       = require("path"),
    fs         = require("fs"),
    nomnom     = require("nomnom"),
    yawp       = require("./yawp"),
    configPath = "./.yawpfile",
    config     = {};

// Configuration file
nomnom.option("config", {
    abbr      : "c",
    help      : "Yawp run configuration file",
    default   : "./.yawpfile",
    transform : function(loc) {
        if(!loc) return;
        configPath = loc; //JSON.parse(fs.readFileSync(path.resolve(loc), "utf8"));
        return loc;
    }
});

// Json source file
nomnom.option("source", {
    abbr      : "s",
    help      : "Path to JSON source file"
});

// Directory to putput to
nomnom.option("output", {
    abbr      : "o",
    help      : "Path to output file"
});

// Name of initial template
nomnom.option("template", {
    abbr      : "t",
    help      : "Name of main template"
});

// Path to template directory
nomnom.option("template-dir", {
    abbr      : "td",
    help      : "Path to templates directory"
});

function checkConfig(opts) {
    var valid = ["source", "output", "template-dir"];

    valid = valid.every(function(name) {
        var loc;

        if(loc = opts[name]) {
            config[name] = path.resolve(loc);
        } else if(loc = config[name]) {
            config[name] = path.resolve(loc);
        }

        return !!loc;
    });

    return valid;
}

config = JSON.parse(fs.readFileSync(path.resolve(configPath), "utf8"));

if(checkConfig(nomnom.parse())) {
    yawp.run(config);
}
<|endoftext|>


<commit_before>(function () {
if (typeof(window) === 'undefined') {
    var nearley = require('../lib/nearley.js');
} else {
    var nearley = window.nearley;
}

function Compile(structure, opts) {
    var uns = {};

    function unique(name) {
        var un = uns[name] = (uns[name] || 0) + 1;
        return name + '$' + un;
    }

    function joiner(d) {
        return d.join('');
    }

    var outputRules = [];
    var body = []; // @directives list

    function buildProcessedRule(ruleName, rule) {
        var tokenList = [];

        rule.tokens.forEach(function(token) {
            if (token.literal) {
                var str = token.literal;
                if (str.length > 1) {
                    var rules = str.split("").map(function(d) {
                        return {
                            literal: d
                        };
                    });

                    var newname = unique(ruleName + "$string");
                    buildProcessedRule(newname, {
                        tokens: rules,
                        postprocess: joiner
                    });
                    tokenList.push(newname);
                } else if (str.length === 1) {
                    tokenList.push({
                        literal: str
                    });
                }
            } else if (token.subexpression) {
                var data = token.subexpression;
                var name = unique(ruleName + "$subexpression");
                structure.push({"name": name, "rules": data});
                tokenList.push(name);
            } else if (token.ebnf) {
                var data = token.ebnf;
                var modifier = token.modifier;
                var name = unique(ruleName + "$ebnf");
                var arrconcat = (function(d) {
                    return [d[0]].concat(d[1]);
                }).toString();

                switch (modifier) {
                    case ":+":
                        structure.push({
                            "name": name,
                            "rules": [{
                                "tokens": [data],
                            }, {
                                "tokens": [data, name],
                                "postprocess": arrconcat
                            }]
                        });
                        tokenList.push(name);
                        break;
                    case ":*":
                        structure.push({
                            "name": name,
                            "rules": [{
                                "tokens": [],
                            }, {
                                "tokens": [data, name],
                                "postprocess": arrconcat
                            }]
                        });
                        tokenList.push(name);
                        break;
                    case ":?":
                        structure.push({
                            "name": name,
                            "rules": [{
                                "tokens": [data],
                                "postprocess": "id"
                            }, {
                                "tokens": [],
                                "postprocess": "function(d) {return null;}"
                            }]
                        });
                        tokenList.push(name);
                        break;
                }
            } else if (typeof(token) === 'string') {
                if (token !== 'null') tokenList.push(token);
            } else if (token instanceof RegExp) {
                tokenList.push(token);
            } else {
                throw new Error("Should never get here");
            }
        });

        var out = new nearley.Rule(
            ruleName,
            tokenList,
            (opts.nojs ? null : rule.postprocess)
        );

        outputRules.push(out);
    }

    var firstName;

    var i=0;
    while (i<structure.length) {
        var productionRule = structure[i];
        if (productionRule.body) {
            // This isn't a rule, it's an @directive.
            if (!opts.nojs) body.push(productionRule.body);
        } else {
            var rules = productionRule.rules;
            if (!firstName) firstName = productionRule.name;
            rules.forEach(function(rule) {
                buildProcessedRule(productionRule.name, rule);
            });
        }
        i++;
    }

    return {
        rules: outputRules,
        body: body,
        start: firstName
    };
}

if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
    module.exports = Compile;
} else {
    window.Compile = Compile;
}
})();
<commit_msg>lib/compile: while -> for<commit_after>(function () {
if (typeof(window) === 'undefined') {
    var nearley = require('../lib/nearley.js');
} else {
    var nearley = window.nearley;
}

function Compile(structure, opts) {
    var uns = {};

    function unique(name) {
        var un = uns[name] = (uns[name] || 0) + 1;
        return name + '$' + un;
    }

    function joiner(d) {
        return d.join('');
    }

    var outputRules = [];
    var body = []; // @directives list

    function buildProcessedRule(ruleName, rule) {
        var tokenList = [];

        rule.tokens.forEach(function(token) {
            if (token.literal) {
                var str = token.literal;
                if (str.length > 1) {
                    var rules = str.split("").map(function(d) {
                        return {
                            literal: d
                        };
                    });

                    var newname = unique(ruleName + "$string");
                    buildProcessedRule(newname, {
                        tokens: rules,
                        postprocess: joiner
                    });
                    tokenList.push(newname);
                } else if (str.length === 1) {
                    tokenList.push({
                        literal: str
                    });
                }
            } else if (token.subexpression) {
                var data = token.subexpression;
                var name = unique(ruleName + "$subexpression");
                structure.push({"name": name, "rules": data});
                tokenList.push(name);
            } else if (token.ebnf) {
                var data = token.ebnf;
                var modifier = token.modifier;
                var name = unique(ruleName + "$ebnf");
                var arrconcat = (function(d) {
                    return [d[0]].concat(d[1]);
                }).toString();

                switch (modifier) {
                    case ":+":
                        structure.push({
                            "name": name,
                            "rules": [{
                                "tokens": [data],
                            }, {
                                "tokens": [data, name],
                                "postprocess": arrconcat
                            }]
                        });
                        tokenList.push(name);
                        break;
                    case ":*":
                        structure.push({
                            "name": name,
                            "rules": [{
                                "tokens": [],
                            }, {
                                "tokens": [data, name],
                                "postprocess": arrconcat
                            }]
                        });
                        tokenList.push(name);
                        break;
                    case ":?":
                        structure.push({
                            "name": name,
                            "rules": [{
                                "tokens": [data],
                                "postprocess": "id"
                            }, {
                                "tokens": [],
                                "postprocess": "function(d) {return null;}"
                            }]
                        });
                        tokenList.push(name);
                        break;
                }
            } else if (typeof(token) === 'string') {
                if (token !== 'null') tokenList.push(token);
            } else if (token instanceof RegExp) {
                tokenList.push(token);
            } else {
                throw new Error("Should never get here");
            }
        });

        var out = new nearley.Rule(
            ruleName,
            tokenList,
            (opts.nojs ? null : rule.postprocess)
        );

        outputRules.push(out);
    }

    var firstName;

    for (var i = 0; i < structure.length; i++) {
        var productionRule = structure[i];
        if (productionRule.body) {
            // This isn't a rule, it's an @directive.
            if (!opts.nojs) body.push(productionRule.body);
        } else {
            var rules = productionRule.rules;
            if (!firstName) firstName = productionRule.name;
            rules.forEach(function(rule) {
                buildProcessedRule(productionRule.name, rule);
            });
        }
    }

    return {
        rules: outputRules,
        body: body,
        start: firstName
    };
}

if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
    module.exports = Compile;
} else {
    window.Compile = Compile;
}
})();
<|endoftext|>


<commit_before>const _ = require('icebreaker')
const RPC = require("./rpc")
const utils = require('icebreaker-network/lib/util')
const connect = require("icebreaker-peer/lib/connect")

module.exports = function (addr, _local, opts, cb) {
  if (_.isFunction(opts)) {
    cb = opts
    opts = {}
  }

  if (!_.isPlainObject(opts)) opts = {}

  opts.authenticate = opts.authenticate || function (id, cb) { cb(null, true) }

  connect(addr, opts, (err, e) => {

    if (err) return cb(err)
    let peerID = null
    let duplex = RPC(_local, Object.assign({}, opts, { isClient: true, id: "client" }), (err, api) => {
      e.end = duplex.end;
      err = err || e.error
      if (err) return cb(err)

      if (e && api) e.peer = api

      if (e.peerID == null) {
        err = 'closing the connection peerID is undefined or null '
        return setImmediate(() => duplex.end(err, () => { cb(err) }))
      }

      opts.authenticate(e.peerID, function (err, auth) {
        if (auth == null && !err) err = new Error('client unauthorized')
        if (!auth) err = err || 'client authentication rejected'
        if (err) return setImmediate(() => duplex.end(err, () => { cb(null, err) }))
        e.auth = auth
        cb(null, e)
      })
    })
    e.end = duplex.end
    _(e, duplex, e)
  })
}<commit_msg>fix for connect<commit_after>const _ = require('icebreaker')
const RPC = require("./rpc")
const utils = require('icebreaker-network/lib/util')
const connect = require("icebreaker-peer/lib/connect")

module.exports = function (addr, _local, opts, cb) {
  if (_.isFunction(opts)) {
    cb = opts
    opts = {}
  }

  if (!_.isPlainObject(opts)) opts = {}

  opts.authenticate = opts.authenticate || function (id, cb) { cb(null, true) }

  connect(addr, opts, (err, e) => {

    if (err) return cb(err)
    let peerID = null
    let duplex = RPC(_local, Object.assign({}, opts, { isClient: true, id: "client" }), (err, api) => {
      e.end = duplex.end;
      err = err || e.error
      if (err) return cb(err)

      if (e && api) e.peer = api

      if (e.peerID == null) {
        err = 'closing the connection peerID is undefined or null '
        return setImmediate(() => duplex.end(err, () => { cb(err) }))
      }

      opts.authenticate(e.peerID, function (err, auth) {
        if (auth == null && !err) err = new Error('client unauthorized')
        if (!auth) err = err || 'client authentication rejected'
        if (err) return setImmediate(() => duplex.end(err, () => { cb( err) }))
        e.auth = auth
        cb(null, e)
      })
    })
    e.end = duplex.end
    _(e, duplex, e)
  })
}<|endoftext|>


<commit_before>// # Content
//
// Content related functions.
/*jslint node: true */

'use strict';

var cheerio = require('cheerio'), unfluff = require('unfluff'), crypto = require('crypto'), url = require('url'), _ = require('lodash');

var pubsub = require('../lib/pubsub-client');

var sites = require('./sites.js'), utils = require('./utils.js'), annotations = require('./annotations.js');

exports.indexContentItem = indexContentItem;
exports.saveAnnotations = saveAnnotations;
exports.getRecognizedLinks = getRecognizedLinks;

/**
 * Save an HTML content item, queueing content and creating annotations as required
 *
 * If it's not an HTML item, do nothing and return.
 *
 * After processing, sends updated content notification.
 *
 * @param desc:
 * @param {uri} uri
 * @param {string} content
 * @param {object} headers
 *
 * @param context:
 * @param {string} member
 * @param {uri} refererer
 * @param {array} annotators
 * @param {array} categories
 * @param {boolean} queueOnly
 *
 * @param {boolean} queueOnly don't index if it already exists (optional)
 * @param {boolean} updating don't notify content change (optional, for annotation)
 * }
**/

function indexContentItem(desc, context, callback) {
// find any existing instance
  GLOBAL.svc.indexer.retrieveByURI(desc.uri, function(err, result) {
    var cItem, hItem;
// it has been indexed
    if (result && result._source) {
      if (context.queueOnly) {
        GLOBAL.debug('already indexed', desc.uri);
        callback();
        return;
      }
      // transfer historical data
      hItem = result._source;

      // if we're receiving an incomplete item, update it from existing
      if (!desc.created) {
        desc.created = hItem.created;
        desc.content = desc.content || hItem.content;
        desc.title = context.title || desc.title || hItem.title;
      }
    }

    var validated = validateIncomingContentItem(desc, context);
    if (!validated.ok) {
      console.log('failing indexContentItem', validated);
      callback({ error: validated });
      return;
    }
    var user = validated.user;
    desc.state = validated.state;
    desc.title = validated.title || desc.title;

    cItem = annotations.createContentItem(desc);

    if (hItem) {
      cItem.timestamp = new Date();
      // merge existing properties
      ['annotations', 'visitors', 'referers'].forEach(function(p) {
      //onsole.log(p.blue, 'cItem before', cItem[p].length);
        cItem[p] = cItem[p].concat(hItem[p]);
      //console.log(p.blue, hItem[p].length, 'cItem after', cItem[p].length);
      });
    } else {
      cItem.created = cItem.timestamp;
    }

    cItem.annotations = cItem.annotations.concat(annotationsFromTags(cItem, context));

    if (!cItem.content || cItem.content.length < 1) {
      delete cItem.sha1;
      delete cItem.text;
    } else {
      cItem.sha1 = crypto.createHash('sha1').update(cItem.content, 'utf8').digest('hex');
      cItem.text = utils.getTextFromHtml(cItem.content);
      // deduplicate
      cItem.annotations = _.uniq(cItem.annotations, 'flattened');
      cItem.annotationSummary = {};
      // update annotation summary
      _.forOwn(_.groupBy(cItem.annotations, 'state'), function(vals, key) { cItem.annotationSummary[key] = vals.length; });

      if (cItem.annotationSummary.validated > 0 || cItem.annotationSummary.unvalidated > 0) {
        cItem.state = 'annotated';
      } else {
        cItem.state = 'visited';
      }
    }

    GLOBAL.debug('saving ci'.blue, user.type, user.username, cItem.uri, 'new', (hItem === null), 'visitors'.blue, cItem.visitors.length, 'annos', cItem.annotations.length);
    if (user.type === 'User' && desc.state !== utils.states.content.queued) {
      cItem.visitors.push({ member: context.member, mode: context.mode || 'browser', 'timestamp': new Date().toISOString() });
    }
    if (context.referer) {
      cItem.referers.push(context.referer);
    }

    GLOBAL.svc.indexer.saveContentItem(cItem, function(err, res, cItems) {
      cItem = cItems[0];
      if (err || !cItem) {
        GLOBAL.error('index saveContentitem failed', err);
      } else {
        if (!context.updating && cItem.state !== utils.states.content.queued) {
          var desc = _.clone(cItem);
          desc.text = utils.getTextFromHtml(cItem.content);
          desc.selector = 'body';
          var clientID = GLOBAL.svc.auth.clientIDByUsername(user.username);
          utils.indexDelay(function() {
            pubsub.init({ homepage: GLOBAL.config.HOMEPAGE, clientID: clientID }).item.annotations.update(cItem.uri);
          });
        }
        if (hItem && hItem.sha1 !== cItem.sha1) {
          GLOBAL.svc.indexer.saveItemHistory(cItem, utils.passingError);
        }
      }
      callback(err, res, cItem);
    });
  });
}

// Test an incoming desc and return a string with an error if not ok, or ok: true and desc values.
function validateIncomingContentItem(desc, context) {
  var ret = {ok: true};
  if (!context.member) {
    return 'NO MEMBER';
  }
  if (!desc.uri || desc.uri.indexOf('http') !== 0) {
    return 'indexContentItem not an http id ' + desc.uri;
  }

  ret.state = context.state || desc.state;

  if (!ret.queued && ret.state !== utils.states.content.queued) {
    if (!desc.content) {
      return 'no content for ' + desc.state;
    }

// extract recognizable content
    var extracted = extractContent(desc);
    ret.title = extracted.title || desc.title;
    if (!ret.title) {
      GLOBAL.debug('not indexable content-type', desc.uri);
      return 'not indexable';
    }
  } else {
    ret.title = desc.title;
  }

  ret.user = GLOBAL.svc.auth.getUserByUsername(context.member);
  if (!ret.user) {
    console.log(context.member, GLOBAL.config.users);
    return 'User not found';
  }
  return ret;
}

// add contextual category annotations
//FIXME annotation state
// FIXME rename categories to tags
function annotationsFromTags(cItem, context) {
  var ret = [], anno;
  if (context.categories) {
    context.categories.forEach(function(tag) {
      //  complete anno
      if (tag.type) {
        anno = tag;
      } else {
        anno = {hasTarget: cItem.uri, type: 'category', category: tag};
      }
      anno.hasTarget = cItem.uri;
      anno.state = utils.states.annotations.validated;
      anno.annotatedBy = context.member;
      ret.push(annotations.createAnnotation(anno));

    });
  }
  return ret;
}

// save an individual content item's annotations. accepts an item or array.
// FIXME: use versioning to detect collisions.
function saveAnnotations(target, context, newAnnos, callback) {
  if (!annotations || annotations.length < 1) {
    GLOBAL.error('trying to save 0 annotations');
    callback();
    return;
  }
  GLOBAL.svc.indexer.retrieveByURI(target, function(err, res) {
    if (err) {
     callback(err);
      return;
    }

    if (!res._source) {
      callback({error: 'target doesn\'t exist'});
      return;
    }
    var cItem = res._source;
    var desc = { uri: target, annotations: newAnnos, title: cItem.title, state: cItem.state };
    context.updating = true;
    indexContentItem(desc, context, function(err, res, rItem) {
      if (err) {
        console.log('saveAnnotations err'.red, err);
      }
      callback(err, res, rItem);
    });
  });
}

// find finer content areas if available
// extract content based on site definitions
function extractContent(desc) {
  /*
  // search all possible matches, returning first find
  var founds = sites.findMatch(desc.uri);

  if (founds.length) {
    var $ = cheerio.load(desc.content);
  // use first found extractor
    founds.forEach(function(found) {
      if ($(found.selector)) {
        var content = $(found.selector).html();
        return { selector: found.selector, content: content };
      }
    });
  }
  // ok, let's try unfluff
  var uf = unfluff(desc.content);
  return { selector: 'body', content: desc.content, text: uf.text, title: uf.title };
  */
  var title = getTitle(desc.content, '<title') || getTitle(desc.content, '<TITLE');

  return { selector: 'body', content: desc.content, text: 'NOTEXTRACTED', title: title };
}

// Get an HTML title the old-fashioned way.
function getTitle(content, tag) {
  if (!content) {
    return;
  }
  var ts = content.indexOf(tag);
  if (ts < 0) {
    return;
  }
  var te = content.indexOf('>', ts);
  var cs = content.indexOf('<', te + 1);
  var title = content.substring(te + 1, cs);
  return title.trim();
}

// find recognized links in document and add found as queued
function getRecognizedLinks(cItem) {
  var founds = sites.findMatch(cItem.uri), $, links = {};

  founds.forEach(function(found) {
    ['navLinks', 'resultLinks'].forEach(function(type) {
      if (found[type]) {
        $ = $ || cheerio.load(cItem.content);
        links[type] = [];
        found[type].forEach(function(s) {
          $(s + ' a').map(function(i, link) {
            var href = $(link).attr('href');
            if (href) {
              // absolute-ize relative URLs
              if (href.indexOf('http://') !== 0) {
                href = url.resolve(cItem.uri, href);
              }
              links[type].push(href);
            }
          });
        });
      }
    });
  });
  return links;
}
<commit_msg>allow query and query source fields for created content items<commit_after>// # Content
//
// Content related functions.
/*jslint node: true */

'use strict';

var cheerio = require('cheerio'), unfluff = require('unfluff'), crypto = require('crypto'), url = require('url'), _ = require('lodash');

var pubsub = require('../lib/pubsub-client');

var sites = require('./sites.js'), utils = require('./utils.js'), annotations = require('./annotations.js');

exports.indexContentItem = indexContentItem;
exports.saveAnnotations = saveAnnotations;
exports.getRecognizedLinks = getRecognizedLinks;

/**
 * Save an HTML content item, queueing content and creating annotations as required
 *
 * If it's not an HTML item, do nothing and return.
 *
 * After processing, sends updated content notification.
 *
 * @param desc:
 * @param {uri} uri
 * @param {string} content
 * @param {object} headers
 *
 * @param context:
 * @param {string} member
 * @param {uri} refererer
 * @param {array} annotators
 * @param {array} categories
 * @param {boolean} queueOnly
 * @param {string} query - retrieve any existing to update by this query rather than by uri
 * NB only the first query result is processed.
 * @parama {string} preferSource - for a query, prefer any found source's field values
 *
 * @param {boolean} queueOnly don't index if it already exists (optional)
 * @param {boolean} updating don't notify content change (optional, for annotation)
 * }
**/

function indexContentItem(desc, context, callback) {
// find any existing instance
  var process = function(err, result) {
    var cItem, hItem;
// it has been indexed
    if (result && result._source) {
      if (context.queueOnly) {
        GLOBAL.debug('already indexed', desc.uri);
        callback();
        return;
      }
      // transfer historical data
      hItem = result._source;

      // if we're receiving an incomplete item, update it from existing
      if (!desc.created) {
        desc.created = hItem.created;
        desc.content = desc.content || hItem.content;
        desc.title = context.title || desc.title || hItem.title;
      }
    }

    var validated = validateIncomingContentItem(desc, context);
    if (!validated.ok) {
      console.log('failing indexContentItem', validated);
      callback({ error: validated });
      return;
    }
    var user = validated.user;
    desc.state = validated.state;
    desc.title = validated.title || desc.title;

    cItem = annotations.createContentItem(desc);

    cItem.timestamp = new Date();
    if (hItem) {
      // merge existing properties
      ['annotations', 'visitors', 'referers'].forEach(function(p) {
      //onsole.log(p.blue, 'cItem before', cItem[p].length);
        cItem[p] = cItem[p].concat(hItem[p]);
      //console.log(p.blue, hItem[p].length, 'cItem after', cItem[p].length);
      });
    } else {
      cItem.created = cItem.timestamp;
    }

    cItem.annotations = cItem.annotations.concat(annotationsFromTags(cItem, context));

    if (!cItem.content || cItem.content.length < 1) {
      delete cItem.sha1;
      delete cItem.text;
    } else {
      cItem.sha1 = crypto.createHash('sha1').update(cItem.content, 'utf8').digest('hex');
      cItem.text = utils.getTextFromHtml(cItem.content);
      // deduplicate
      cItem.annotations = _.uniq(cItem.annotations, 'flattened');
      cItem.annotationSummary = {};
      // update annotation summary
      _.forOwn(_.groupBy(cItem.annotations, 'state'), function(vals, key) { cItem.annotationSummary[key] = vals.length; });

      if (cItem.annotationSummary.validated > 0 || cItem.annotationSummary.unvalidated > 0) {
        cItem.state = 'annotated';
      } else {
        cItem.state = 'visited';
      }
    }

    GLOBAL.debug('saving ci'.blue, user.type, user.username, cItem.uri, 'new', (hItem === null), 'visitors'.blue, cItem.visitors.length, 'annos', cItem.annotations.length);
    if (user.type === 'User' && desc.state !== utils.states.content.queued) {
      cItem.visitors.push({ member: context.member, mode: context.mode || 'browser', 'timestamp': new Date().toISOString() });
    }
    if (context.referer) {
      cItem.referers.push(context.referer);
    }

    GLOBAL.svc.indexer.saveContentItem(cItem, function(err, res, cItems) {
      cItem = cItems[0];
      if (err || !cItem) {
        GLOBAL.error('index saveContentitem failed', err);
      } else {
        if (!context.updating && cItem.state !== utils.states.content.queued) {
          var desc = _.clone(cItem);
          desc.text = utils.getTextFromHtml(cItem.content);
          desc.selector = 'body';
          var clientID = GLOBAL.svc.auth.clientIDByUsername(user.username);
          utils.indexDelay(function() {
            pubsub.init({ homepage: GLOBAL.config.HOMEPAGE, clientID: clientID }).item.annotations.update(cItem.uri);
          });
        }
        if (hItem && hItem.sha1 !== cItem.sha1) {
          GLOBAL.svc.indexer.saveItemHistory(cItem, utils.passingError);
        }
      }
      callback(err, res, cItem);
    });
  }

// use query for finding existing to update
  if (context.query) {
    GLOBAL.svc.indexer.formQuery({ query: context.query }, function(err, res) {
      var result;
      if (!err && res && res.hits.total) {
        result = res.hits.hits[0];
        // prefer source fields over desc
        if (context.preferSource) {
          context.preferSource.forEach(function(field) {
            if (result._source[field]) {
              GLOBAL.debug('using result', field, result._source[field]);
              desc[field] = result._source[field];
            }
          });
        }
      }
      process(err, result);
    });
// use URI
  } else {
    GLOBAL.svc.indexer.retrieveByURI(desc.uri, process);
  }
}

// Test an incoming desc and return a string with an error if not ok, or ok: true and desc values.
function validateIncomingContentItem(desc, context) {
  var ret = {ok: true};
  if (!context.member) {
    return 'NO MEMBER';
  }
  if (!desc.uri || desc.uri.indexOf('http') !== 0) {
    return 'indexContentItem not an http id ' + desc.uri;
  }

  ret.state = context.state || desc.state;

  if (!ret.queued && ret.state !== utils.states.content.queued) {
    if (!desc.content) {
      return 'no content for ' + desc.state;
    }

// extract recognizable content
    var extracted = extractContent(desc);
    ret.title = extracted.title || desc.title;
    if (!ret.title) {
      GLOBAL.debug('not indexable content-type', desc.uri);
      return 'not indexable';
    }
  } else {
    ret.title = desc.title;
  }

  ret.user = GLOBAL.svc.auth.getUserByUsername(context.member);
  if (!ret.user) {
    console.log(context.member, GLOBAL.config.users);
    return 'User not found';
  }
  return ret;
}

// add contextual category annotations
//FIXME annotation state
// FIXME rename categories to tags
function annotationsFromTags(cItem, context) {
  var ret = [], anno;
  if (context.categories) {
    context.categories.forEach(function(tag) {
      //  complete anno
      if (tag.type) {
        anno = tag;
      } else {
        anno = {hasTarget: cItem.uri, type: 'category', category: tag};
      }
      anno.hasTarget = cItem.uri;
      anno.state = utils.states.annotations.validated;
      anno.annotatedBy = context.member;
      ret.push(annotations.createAnnotation(anno));

    });
  }
  return ret;
}

// save an individual content item's annotations. accepts an item or array.
// FIXME: use versioning to detect collisions.
function saveAnnotations(target, context, newAnnos, callback) {
  if (!annotations || annotations.length < 1) {
    GLOBAL.error('trying to save 0 annotations');
    callback();
    return;
  }
  GLOBAL.svc.indexer.retrieveByURI(target, function(err, res) {
    if (err) {
     callback(err);
      return;
    }

    if (!res._source) {
      callback({error: 'target doesn\'t exist'});
      return;
    }
    var cItem = res._source;
    var desc = { uri: target, annotations: newAnnos, title: cItem.title, state: cItem.state };
    context.updating = true;
    indexContentItem(desc, context, function(err, res, rItem) {
      if (err) {
        console.log('saveAnnotations err'.red, err);
      }
      callback(err, res, rItem);
    });
  });
}

// find finer content areas if available
// extract content based on site definitions
function extractContent(desc) {
  /*
  // search all possible matches, returning first find
  var founds = sites.findMatch(desc.uri);

  if (founds.length) {
    var $ = cheerio.load(desc.content);
  // use first found extractor
    founds.forEach(function(found) {
      if ($(found.selector)) {
        var content = $(found.selector).html();
        return { selector: found.selector, content: content };
      }
    });
  }
  // ok, let's try unfluff
  var uf = unfluff(desc.content);
  return { selector: 'body', content: desc.content, text: uf.text, title: uf.title };
  */
  var title = getTitle(desc.content, '<title') || getTitle(desc.content, '<TITLE');

  return { selector: 'body', content: desc.content, text: 'NOTEXTRACTED', title: title };
}

// Get an HTML title the old-fashioned way.
function getTitle(content, tag) {
  if (!content) {
    return;
  }
  var ts = content.indexOf(tag);
  if (ts < 0) {
    return;
  }
  var te = content.indexOf('>', ts);
  var cs = content.indexOf('<', te + 1);
  var title = content.substring(te + 1, cs);
  return title.trim();
}

// find recognized links in document and add found as queued
function getRecognizedLinks(cItem) {
  var founds = sites.findMatch(cItem.uri), $, links = {};

  founds.forEach(function(found) {
    ['navLinks', 'resultLinks'].forEach(function(type) {
      if (found[type]) {
        $ = $ || cheerio.load(cItem.content);
        links[type] = [];
        found[type].forEach(function(s) {
          $(s + ' a').map(function(i, link) {
            var href = $(link).attr('href');
            if (href) {
              // absolute-ize relative URLs
              if (href.indexOf('http://') !== 0) {
                href = url.resolve(cItem.uri, href);
              }
              links[type].push(href);
            }
          });
        });
      }
    });
  });
  return links;
}
<|endoftext|>


<commit_before>/**
 * Context is context
 *
 * @module telekit/context
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/**
 * Constants
 * @private
 */

/** Methods that available for user and chat */
const METHOD_COMMON = [
    'sendMessage',
    'forwardMessage',
    'sendPhoto',
    'sendAudio',
    'sendDocument',
    'sendSticker',
    'sendVideo',
    'sendVoice',
    'sendLocation',
    'sendVenue',
    'sendContact',
    'sendChatAction',
    'editMessageText',
    'editMessageCaption',
    'editMessageReplyMarkup',

];

/** Methods that available only for user */
const METHOD_USER = [
    ...METHOD_COMMON,
    'getUserProfilePhotos',

];

/** Methods that available only for chat */
const METHOD_CHAT = [
    ...METHOD_COMMON,
    'leaveChat',
    'getChat',
    'getChatAdministrators',
    'getChatMembersCount',
    'getChatMember',
];

/**
 * Methods
 * @private
 */
function createProxy(kit, obj, methods) {
    return new Proxy(obj, {
        get(target, name) {
            if (methods.includes(name)) {
                return (params, callback) => kit.api.method(name,
                    Object.assign({ chat_id: obj.id }, params),
                    callback
                );
            }

            return target[name];
        },

        set() {
            return;
        },
    });
}

/**
 * Implementation and Exports
 * @public
 */
module.exports = function(kit) {
    let hidden = {
        kit: kit,

        update: null,

        user: null,
        chat: null,
    };

    return class Context {
        constructor() {
            this.isEdited = false;
            this.isChosen = false;
        }

        get update() {
            return hidden.update;
        }

        set update(value) {
            hidden.chat = null;
            hidden.user = null;

            if (value.chat) {
                hidden.chat = createProxy(
                    hidden.kit,
                    value.chat,
                    METHOD_CHAT
                );
            }

            if (value.from) {
                hidden.user = createProxy(
                    hidden.kit,
                    value.from,
                    METHOD_USER
                );
            }

            hidden.update = value;
        }

        get chat() {
            return hidden.chat;
        }

        get user() {
            return hidden.user;
        }

        get api() {
            return hidden.kit.api;
        }
    }
};
<commit_msg>Changed: added throw if you want to change `context.user` or `context.chat`<commit_after>/**
 * Context is context
 *
 * @module telekit/context
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/**
 * Constants
 * @private
 */

/** Methods that available for user and chat */
const METHOD_COMMON = [
    'sendMessage',
    'forwardMessage',
    'sendPhoto',
    'sendAudio',
    'sendDocument',
    'sendSticker',
    'sendVideo',
    'sendVoice',
    'sendLocation',
    'sendVenue',
    'sendContact',
    'sendChatAction',
    'editMessageText',
    'editMessageCaption',
    'editMessageReplyMarkup',

];

/** Methods that available only for user */
const METHOD_USER = [
    ...METHOD_COMMON,
    'getUserProfilePhotos',

];

/** Methods that available only for chat */
const METHOD_CHAT = [
    ...METHOD_COMMON,
    'leaveChat',
    'getChat',
    'getChatAdministrators',
    'getChatMembersCount',
    'getChatMember',
];

/**
 * Methods
 * @private
 */
function createProxy(kit, obj, methods) {
    return new Proxy(obj, {
        get(target, name) {
            if (methods.includes(name)) {
                return (params, callback) => kit.api.method(name,
                    Object.assign({ chat_id: obj.id }, params),
                    callback
                );
            }

            return target[name];
        },

        set() {
            return throw new Error('Cannot change `user` or `chat`.');
        },
    });
}

/**
 * Implementation and Exports
 * @public
 */
module.exports = function(kit) {
    let hidden = {
        kit: kit,

        update: null,

        user: null,
        chat: null,
    };

    return class Context {
        constructor() {
            this.isEdited = false;
            this.isChosen = false;
        }

        get update() {
            return hidden.update;
        }

        set update(value) {
            hidden.chat = null;
            hidden.user = null;

            if (value.chat) {
                hidden.chat = createProxy(
                    hidden.kit,
                    value.chat,
                    METHOD_CHAT
                );
            }

            if (value.from) {
                hidden.user = createProxy(
                    hidden.kit,
                    value.from,
                    METHOD_USER
                );
            }

            hidden.update = value;
        }

        get chat() {
            return hidden.chat;
        }

        get user() {
            return hidden.user;
        }

        get api() {
            return hidden.kit.api;
        }
    }
};
<|endoftext|>


<commit_before>const { performance, PerformanceObserver } = require('perf_hooks');
const {delay} = require('./utils');

module.exports = class Context {
    constructor(task){
        this.duration = null;
        //Object.assign(this, task);
        this.task = task;
        const obs = new PerformanceObserver((items) => {
            this.duration = items.getEntries()[0].duration;
            performance.clearMarks();
        });
        obs.observe({ entryTypes: ['measure'] });
    }

    // private
    start(){
        performance.mark('job_start');
    }

    stop(){
        performance.mark('job_stop');
        performance.measure('execution_time', 'job_start', 'job_stop');
        return this.duration;
    }

    prev(){

    }

    deps(){

    }

    log(){

    }

    queue(){

    }

    rerunable(attr, current){
        const {task} = this,
            node = task[attr] || {},
            interval = node.interval,
            limit = node.limit || Infinity,
            canRerun = current < limit;

        if(node && interval && canRerun){
            return delay(task.date, interval);
        }
        return false;
    }

    retryable(){
        return this.rerunable('retry', this.task.retries);
    }

    repeatable(){
        return this.rerunable('repeat', this.task.repetitions);
    }

    next(err, res){
        const {task} = this;
        // Status definition
        let {date} = task;
        let status = err ? 'failed' : 'complete';

        const retryDate = this.retryable();
        const repeatDate = this.repeatable();

        if(status === 'failed' && retryDate){
            status = 'retry';
            date = retryDate;
        }

        if(status === 'complete' && repeatDate){
            status = 'done';
            date = repeatDate;
        }

        status = (err && this.retryable()) ? 'retry' : status;
        status = (!err && this.repeatable()) ? 'done' : status;

        return {
            ...task,
            date,
            status,
            error: err || null,
            result: res || false,
            duration: this.duration
        };
    }

}

//<commit_msg>remove old status assignment<commit_after>const { performance, PerformanceObserver } = require('perf_hooks');
const {delay} = require('./utils');

module.exports = class Context {
    constructor(task){
        this.duration = null;
        //Object.assign(this, task);
        this.task = task;
        const obs = new PerformanceObserver((items) => {
            this.duration = items.getEntries()[0].duration;
            performance.clearMarks();
        });
        obs.observe({ entryTypes: ['measure'] });
    }

    // private
    start(){
        performance.mark('job_start');
    }

    stop(){
        performance.mark('job_stop');
        performance.measure('execution_time', 'job_start', 'job_stop');
        return this.duration;
    }

    prev(){

    }

    deps(){

    }

    log(){

    }

    queue(){

    }

    rerunable(attr, current){
        const {task} = this,
            node = task[attr] || {},
            interval = node.interval,
            limit = node.limit || Infinity,
            canRerun = current < limit;

        if(node && interval && canRerun){
            return delay(task.date, interval);
        }
        return false;
    }

    retryable(){
        return this.rerunable('retry', this.task.retries);
    }

    repeatable(){
        return this.rerunable('repeat', this.task.repetitions);
    }

    next(err, res){
        const {task} = this;
        // Status definition
        let {date} = task;
        let status = err ? 'failed' : 'complete';

        const retryDate = this.retryable();
        const repeatDate = this.repeatable();

        if(status === 'failed' && retryDate){
            status = 'retry';
            date = retryDate;
        }

        if(status === 'complete' && repeatDate){
            status = 'done';
            date = repeatDate;
        }

        return {
            ...task,
            date,
            status,
            error: err || null,
            result: res || false,
            duration: this.duration
        };
    }

}

//<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * an observable data holder.
 * it's the heart of yamvish data-binding.
 */

var utils = require('./utils'),
	env = require('./env'),
	AsyncManager = require('./async');
//_______________________________________________________ DATA BIND CONTEXT

function Context(data, parent, path, env) {
	AsyncManager.call(this);
	this.__yContext__ = true;
	this.data = (data !== undefined) ? data : {};
	this.map = {};
	if (parent) {
		this.parent = parent;
		this.env = env ? new Context(env) : parent.env;
		if (path) {
			var self = this;
			this.path = path;
			this.binds = [];
			this.parent.subscribe(path, function(value) {
				self.reset(value);
			}, false, this.binds)
		}
	} else
		this.env = env ? new Context(env) : Context.env;
}

function unsub(context, path, fn, upstream) {
	return function() {
		if (!context.destroyed)
			context.unsubscribe(path, fn, upstream);
	};
}

Context.prototype = {
	destroy: function() {
		if (this.binds)
			this.binds.forEach(function(unbind) {
				unbind();
			});
		this.destroyed = true;
		this.binds = null;
		this.parent = null;
		this.data = null;
		this.map = null;
	},
	get: function(path) {
		if (!path.forEach)
			path = path.split('.');
		switch (path[0]) {
			case '$this':
				if (path.length === 1)
					return this.data;
				break;
			case '$parent':
				if (!this.parent)
					throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
				return this.parent.get(path.slice(1));
				break;
			case '$env':
				return this.env.get(path.slice(1));
		}
		var r = utils.getProp(this.data, path);
		if (r === undefined)
			return '';
		return r;
	},
	dependent: function(path, dependencies, func) {
		var argsOutput = [],
			willFire,
			self = this,
			count = 0;
		this.binds = this.binds ||  [];
		dependencies.forEach(function(dependency) {
			argsOutput.push(self.get(dependency));
			// subscribe to arguments[i]
			var index = count++; // localise var in scope for local func closure below
			self.subscribe(dependency, function(value, type, p, key) {
				argsOutput[index] = value;
				if (!willFire)
					willFire = self.delay(function() {
						if (willFire) {
							willFire = null;
							self.set(path, func.apply(self, argsOutput));
						}
					}, 0);
			}, false, this.binds);
		});
		this.set(path, func.apply(this, argsOutput));
		return this;
	},
	reset: function(data) {
		if (data === this.data || (this.data instanceof Date && data instanceof Date && this.data.valueOf() === data.valueOf()))
			return this;
		this.data = data || {};
		this.notifyAll('reset', null, this.map, data, '*');
		return this;
	},
	toggle: function(path, value) {
		this.set(path, !this.get(path));
		return this;
	},
	toggleInArray: function(path, value) {
		var arr = this.get(path);
		for (var i = 0, len = arr.length; i < len; ++i)
			if (arr[i] === value) {
				this.del(path + '.' + i)
				return this;
			}
		return this.push(path, value);
	},
	set: function(path, value) {
		if (!path.forEach)
			path = path.split('.');
		switch (path[0]) {
			case '$this':
				if (path.length === 1)
					return this.reset(value);
				break;
			case '$parent':
				if (this.parent)
					return this.parent.set(path.slice(1), value) && this;
				throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
			case '$env':
				return this.env.set(path.slice(1), value) && this;
		}
		var old = utils.setProp(this.data, path, value);
		if (old !== value) {
			if (old instanceof Date && value instanceof Date && old.valueOf() === value.valueOf())
				return this;
			this.notify('set', path, value, path[path.length - 1]);
		}
		return this;
	},
	push: function(path, value) {
		if (!path.forEach)
			path = path.split('.');

		if (path[0] == '$parent') {
			if (this.parent)
				return this.parent.push(path.slice(1), value) && this;
			throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
		} else if (path[0] === '$env')
			return this.env.push(path.slice(1), value) && this;
		var arr;
		if (path[0] === '$this')
			arr = this.data;
		else
			arr = utils.getProp(this.data, path);
		if (!arr)
			throw new Error("yamvish.Context : Missing array at " + path.join(".") + " : couldn't push object.");
		if (!arr.forEach)
			throw new Error("yamvish.Context : Object is not array at " + path.join(".") + " : couldn't push object.");
		arr.push(value);
		this.notify('push', path, value, arr.length - 1);
		return this;
	},
	del: function(path) {
		if (!path.forEach)
			path = path.split('.');
		else
			path = path.slice();
		if (path[0] == '$parent') {
			if (this.parent)
				return this.parent.del(path.slice(1)) && this;
			throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
		} else if (path[0] == '$env')
			return this.env.del(path.slice(1)) && this;
		var path2 = path.slice();
		var key = path2.pop(),
			parent = path2.length ? utils.getProp(this.data, path2) : this.data;
		if (parent)
			if (parent.forEach) {
				var index = parseInt(key, 10);
				if (index < parent.length)
					this.notify('removeAt', path2, parent.splice(index, 1), index);
			} else {
				var val = parent[key];
				delete parent[key];
				this.notify('delete', path, val, key);
			}
		return this;
	},
	subscribe: function(path, fn, upstream, binds) {
		// console.log('context subscribe : ', path, fn, upstream);
		if (!path.forEach)
			path = path.split('.');
		var space;
		if (path[0] === '$this')
			space = this.map;
		else if (path[0] === '$env')
			return this.env.subscribe(path.slice(1), fn, upstream);
		else if (path[0] === '$parent') {
			if (!this.parent)
				throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
			return this.parent.subscribe(path.slice(1), fn, upstream);
		} else
			space = utils.getProp(this.map, path);
		if (upstream) {
			if (!space)
				utils.setProp(this.map, path, {
					_upstreams: [fn]
				});
			else
				(space._upstreams = space._upstreams || []).push(fn);
		} else if (!space)
			utils.setProp(this.map, path, {
				_listeners: [fn]
			});
		else
			(space._listeners = space._listeners || []).push(fn);
		if (binds)
			binds.push(unsub(this, path, fn, upstream));
		return this;
	},
	unsubscribe: function(path, fn, upstream) {
		if (this.distroyed)
			return this;
		if (!path.forEach)
			path = path.split('.');
		var space;
		if (path[0] === '$this')
			space = this.map;
		else if (path[0] === '$parent')
			return this.env.unsubscribe(path.slice(1), fn, upstream) && this;
		else if (path[0] === '$parent') {
			if (this.parent)
				return this.parent.unsubscribe(path.slice(1), fn, upstream) && this;
			throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
		} else
			space = utils.getProp(this.map, path);
		if (!space)
			return this;
		var arr = upstream ? space._upstreams : space._listeners;
		for (var i = 0, len = arr.length; i < len; ++i)
			if (arr[i] === fn) {
				arr.splice(i, 1);
				break;
			}
		return this;
	},
	notifyAll: function(type, path, space, value, index) {
		space = space ||  this.map;
		value = (arguments.length < 2) ? this.data : value;
		if (space._listeners)
			for (var i = 0, len = space._listeners.length; i < len; ++i) {
				var listener = space._listeners[i];
				if (!listener) {
					// maybe it's because listeners length has change so update it
					len = space._listeners.length;
					continue;
				}
				var r = listener.call(this, value, type, path, index);
				if (r && r.then)
					this.waiting(r);
			}
		if (type !== 'push' && type !== 'removeAt')
			for (var j in space) {
				if (j === '_listeners' || j === '_upstreams')
					continue;
				this.notifyAll(type, path, space[j], value ? value[j] : undefined, index);
			}
		return this;
	},
	notify: function(type, path, value, index) {
		if (!path.forEach)
			path = path.split('.');
		if (path[0] === '$this')
			path = path.slice(1);
		var space = this.map,
			i = 0,
			star;
		for (var len = path.length; i < len; ++i) {
			star = space['*'];
			if (star && star._upstreams)
				notifyUpstreams.call(this, star, type, path, value, index);
			if (!(space = space[path[i]]))
				break;
			if (space._upstreams)
				notifyUpstreams.call(this, space, type, path, value, index);
		}
		if (star)
			this.notifyAll(type, path, star, value, index);
		if (space)
			this.notifyAll(type, path, space, value, index);
		return this;
	},
	setAsync: function(path, promise) {
		var self = this;
		return this.waiting(promise.then(function(s) {
			self.set(path, s);
			return s;
		}, function(e) {
			console.error('error while Context.setAsync : ', e);
			throw e;
		}));
	},
	pushAsync: function(path, promise) {
		var self = this;
		return this.waiting(promise.then(function(s) {
			self.push(path, s);
			return s;
		}, function(e) {
			console.error('error while Context.pushAsync : ', e);
			throw e;
		}));
	},
	//______________________ AGORA MANAGEMENT
	onAgora: function(messageName, handler) {
		var agora = this.env.data.agora,
			self = this;
		var func = function() {
			handler.apply(self, arguments);
		};
		agora.on(messageName, func);
		(this.binds = this.binds ||  []).push(function() {
			agora.off(messageName, func);
		});
		return this;
	},
	toAgora: function(name) {
		var args = [name].concat([].slice.call(arguments, 1))
		this.env.data.agora.emit.apply(this.env.data.agora, args);
		return this;
	}
};

Context.env = new Context(env);
delete Context.env.env;

utils.shallowMerge(AsyncManager.prototype, Context.prototype);

function notifyUpstreams(space, type, path, value, index) {
	for (var i = 0, len = space._upstreams.length; i < len; ++i) {
		var upstream = space._upstreams[i];
		if (!upstream) {
			// maybe it's because upstreams length has change so update it
			len = space._upstreams.length;
			continue;
		}
		var r = upstream.call(this, value, type, path, index);
		if (r && r.then)
			this.waiting(r);
	}
}

module.exports = Context;
<commit_msg>debug dependent vars in Context<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * an observable data holder.
 * it's the heart of yamvish data-binding.
 */

var utils = require('./utils'),
	env = require('./env'),
	AsyncManager = require('./async');
//_______________________________________________________ DATA BIND CONTEXT

function Context(data, parent, path, env) {
	AsyncManager.call(this);
	this.__yContext__ = true;
	this.data = (data !== undefined) ? data : {};
	this.map = {};
	if (parent) {
		this.parent = parent;
		this.env = env ? new Context(env) : parent.env;
		if (path) {
			var self = this;
			this.path = path;
			this.binds = [];
			this.parent.subscribe(path, function(value) {
				self.reset(value);
			}, false, this.binds)
		}
	} else
		this.env = env ? new Context(env) : Context.env;
}

function unsub(context, path, fn, upstream) {
	return function() {
		if (!context.destroyed)
			context.unsubscribe(path, fn, upstream);
	};
}

Context.prototype = {
	destroy: function() {
		if (this.binds)
			this.binds.forEach(function(unbind) {
				unbind();
			});
		this.destroyed = true;
		this.binds = null;
		this.parent = null;
		this.data = null;
		this.map = null;
	},
	get: function(path) {
		if (!path.forEach)
			path = path.split('.');
		switch (path[0]) {
			case '$this':
				if (path.length === 1)
					return this.data;
				break;
			case '$parent':
				if (!this.parent)
					throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
				return this.parent.get(path.slice(1));
				break;
			case '$env':
				return this.env.get(path.slice(1));
		}
		var r = utils.getProp(this.data, path);
		if (r === undefined)
			return '';
		return r;
	},
	dependent: function(path, dependencies, func) {
		var argsOutput = [],
			willFire,
			self = this,
			count = 0;
		this.binds = this.binds ||  [];
		dependencies.forEach(function(dependency) {
			argsOutput.push(this.get(dependency));
			// subscribe to arguments[i]
			var index = count++; // localise var in scope for local func closure below
			this.subscribe(dependency, function(value, type, p, key) {
				argsOutput[index] = value;
				if (!willFire)
					willFire = self.delay(function() {
						if (willFire) {
							willFire = null;
							self.set(path, func.apply(self, argsOutput));
						}
					}, 0);
			}, false, this.binds);
		}, this);
		this.set(path, func.apply(this, argsOutput));
		return this;
	},
	reset: function(data) {
		if (data === this.data || (this.data instanceof Date && data instanceof Date && this.data.valueOf() === data.valueOf()))
			return this;
		this.data = data || {};
		this.notifyAll('reset', null, this.map, data, '*');
		return this;
	},
	toggle: function(path, value) {
		this.set(path, !this.get(path));
		return this;
	},
	toggleInArray: function(path, value) {
		var arr = this.get(path);
		for (var i = 0, len = arr.length; i < len; ++i)
			if (arr[i] === value) {
				this.del(path + '.' + i)
				return this;
			}
		return this.push(path, value);
	},
	set: function(path, value) {
		if (!path.forEach)
			path = path.split('.');
		switch (path[0]) {
			case '$this':
				if (path.length === 1)
					return this.reset(value);
				break;
			case '$parent':
				if (this.parent)
					return this.parent.set(path.slice(1), value) && this;
				throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
			case '$env':
				return this.env.set(path.slice(1), value) && this;
		}
		var old = utils.setProp(this.data, path, value);
		if (old !== value) {
			if (old instanceof Date && value instanceof Date && old.valueOf() === value.valueOf())
				return this;
			this.notify('set', path, value, path[path.length - 1]);
		}
		return this;
	},
	push: function(path, value) {
		if (!path.forEach)
			path = path.split('.');

		if (path[0] == '$parent') {
			if (this.parent)
				return this.parent.push(path.slice(1), value) && this;
			throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
		} else if (path[0] === '$env')
			return this.env.push(path.slice(1), value) && this;
		var arr;
		if (path[0] === '$this')
			arr = this.data;
		else
			arr = utils.getProp(this.data, path);
		if (!arr)
			throw new Error("yamvish.Context : Missing array at " + path.join(".") + " : couldn't push object.");
		if (!arr.forEach)
			throw new Error("yamvish.Context : Object is not array at " + path.join(".") + " : couldn't push object.");
		arr.push(value);
		this.notify('push', path, value, arr.length - 1);
		return this;
	},
	del: function(path) {
		if (!path.forEach)
			path = path.split('.');
		else
			path = path.slice();
		if (path[0] == '$parent') {
			if (this.parent)
				return this.parent.del(path.slice(1)) && this;
			throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
		} else if (path[0] == '$env')
			return this.env.del(path.slice(1)) && this;
		var path2 = path.slice();
		var key = path2.pop(),
			parent = path2.length ? utils.getProp(this.data, path2) : this.data;
		if (parent)
			if (parent.forEach) {
				var index = parseInt(key, 10);
				if (index < parent.length)
					this.notify('removeAt', path2, parent.splice(index, 1), index);
			} else {
				var val = parent[key];
				delete parent[key];
				this.notify('delete', path, val, key);
			}
		return this;
	},
	subscribe: function(path, fn, upstream, binds) {
		// console.log('context subscribe : ', path, fn, upstream);
		if (!path.forEach)
			path = path.split('.');
		var space;
		if (path[0] === '$this')
			space = this.map;
		else if (path[0] === '$env')
			return this.env.subscribe(path.slice(1), fn, upstream);
		else if (path[0] === '$parent') {
			if (!this.parent)
				throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
			return this.parent.subscribe(path.slice(1), fn, upstream);
		} else
			space = utils.getProp(this.map, path);
		if (upstream) {
			if (!space)
				utils.setProp(this.map, path, {
					_upstreams: [fn]
				});
			else
				(space._upstreams = space._upstreams || []).push(fn);
		} else if (!space)
			utils.setProp(this.map, path, {
				_listeners: [fn]
			});
		else
			(space._listeners = space._listeners || []).push(fn);
		if (binds)
			binds.push(unsub(this, path, fn, upstream));
		return this;
	},
	unsubscribe: function(path, fn, upstream) {
		if (this.distroyed)
			return this;
		if (!path.forEach)
			path = path.split('.');
		var space;
		if (path[0] === '$this')
			space = this.map;
		else if (path[0] === '$parent')
			return this.env.unsubscribe(path.slice(1), fn, upstream) && this;
		else if (path[0] === '$parent') {
			if (this.parent)
				return this.parent.unsubscribe(path.slice(1), fn, upstream) && this;
			throw new Error('yamvish.Context : there is no parent in current context. could not find : ' + path.join('.'));
		} else
			space = utils.getProp(this.map, path);
		if (!space)
			return this;
		var arr = upstream ? space._upstreams : space._listeners;
		for (var i = 0, len = arr.length; i < len; ++i)
			if (arr[i] === fn) {
				arr.splice(i, 1);
				break;
			}
		return this;
	},
	notifyAll: function(type, path, space, value, index) {
		space = space ||  this.map;
		value = (arguments.length < 2) ? this.data : value;
		if (space._listeners)
			for (var i = 0, len = space._listeners.length; i < len; ++i) {
				var listener = space._listeners[i];
				if (!listener) {
					// maybe it's because listeners length has change so update it
					len = space._listeners.length;
					continue;
				}
				var r = listener.call(this, value, type, path, index);
				if (r && r.then)
					this.waiting(r);
			}
		if (type !== 'push' && type !== 'removeAt')
			for (var j in space) {
				if (j === '_listeners' || j === '_upstreams')
					continue;
				this.notifyAll(type, path, space[j], value ? value[j] : undefined, index);
			}
		return this;
	},
	notify: function(type, path, value, index) {
		if (!path.forEach)
			path = path.split('.');
		if (path[0] === '$this')
			path = path.slice(1);
		var space = this.map,
			i = 0,
			star;
		for (var len = path.length; i < len; ++i) {
			star = space['*'];
			if (star && star._upstreams)
				notifyUpstreams.call(this, star, type, path, value, index);
			if (!(space = space[path[i]]))
				break;
			if (space._upstreams)
				notifyUpstreams.call(this, space, type, path, value, index);
		}
		if (star)
			this.notifyAll(type, path, star, value, index);
		if (space)
			this.notifyAll(type, path, space, value, index);
		return this;
	},
	setAsync: function(path, promise) {
		var self = this;
		return this.waiting(promise.then(function(s) {
			self.set(path, s);
			return s;
		}, function(e) {
			console.error('error while Context.setAsync : ', e);
			throw e;
		}));
	},
	pushAsync: function(path, promise) {
		var self = this;
		return this.waiting(promise.then(function(s) {
			self.push(path, s);
			return s;
		}, function(e) {
			console.error('error while Context.pushAsync : ', e);
			throw e;
		}));
	},
	//______________________ AGORA MANAGEMENT
	onAgora: function(messageName, handler) {
		var agora = this.env.data.agora,
			self = this;
		var func = function() {
			handler.apply(self, arguments);
		};
		agora.on(messageName, func);
		(this.binds = this.binds ||  []).push(function() {
			agora.off(messageName, func);
		});
		return this;
	},
	toAgora: function(name) {
		var args = [name].concat([].slice.call(arguments, 1))
		this.env.data.agora.emit.apply(this.env.data.agora, args);
		return this;
	}
};

Context.env = new Context(env);
delete Context.env.env;

utils.shallowMerge(AsyncManager.prototype, Context.prototype);

function notifyUpstreams(space, type, path, value, index) {
	for (var i = 0, len = space._upstreams.length; i < len; ++i) {
		var upstream = space._upstreams[i];
		if (!upstream) {
			// maybe it's because upstreams length has change so update it
			len = space._upstreams.length;
			continue;
		}
		var r = upstream.call(this, value, type, path, index);
		if (r && r.then)
			this.waiting(r);
	}
}

module.exports = Context;
<|endoftext|>


<commit_before>/**
 * A context tracks the context of a particular execution queue.
 *
 * As the queue is processed, the context will gain information
 * about the results of each command executed.
 */
var Logger = require('./logging').Logger;

module.exports = Context;

function Context(initialValues) {
  this.resultMap = {};
  this.datasourceMap = {};

  // Debug flag.
  this.debug = false;

  // The logging event emitter.
  this.logger = new Logger();

  // This was initially done for safety.
  // Could this just be turned into
  // this.resultMap = intialvalues || {}
  if (typeof initialValues == 'object') {
    for (var name in initialValues) {
      this.add(name, initialValues[name]);
    }
  }
}

Context.prototype.add = function(name, value) {
  if (value == undefined)
    return;

  this.resultMap[name] = value;

}
Context.prototype.get = function(name) {
  return this.resultMap[name];
}

// Property 'length'.
Context.prototype.__defineGetter__('length', function() {
  return this.size();
});

Context.prototype.size = function() {
  // Since size is called rarely, we
  // calculate on the fly.
  var i = 0;
  for (var o in this.resultMap) {
    ++i;
  }
  return i;
}
Context.prototype.getAll = function() {
  return this.resultMap;
}

/**
 * Log a message to the logging facility.
 *
 * Attach an event listen to cxt.logger.
 * Then handle the following events (at your option):
 *
 * - warning
 * - fatal
 * - error
 * - info
 * - debug
 * - custom
 *
 * Note that the parameters are in reverse order for historical reasons.
 *
 * @param {String} msg
 *   The message.
 * @param {String} level
 *   THe log level.
 */
Context.prototype.log = function(msg, level) {
  this.logger.log(level || "info", msg);
}

Context.prototype.setLogger = function(logger) {
  this.logger = logger;
}

// XXX: I don't like having one object serve as the compartment for both
// general objects and datasources. This should get refactored. But for
// the first go-around, I feel like I should favor simplicity.

Context.prototype.addDatasource = function(name, ds) {
  this.datasourceMap[name] = ds;
}

Context.prototype.getDatasource = function(name) {
  return this.datasourceMap[name];
}

Context.prototype.removeDatasource = function(name) {
  this.datasourceMap[name] = null;
}

/**
 * A partial clone of a context.
 *
 * This returns a new context with the same data
 * and datasources as the base. Note that the
 * values in this context are not cloned. So modifying them
 * will modify the base copy as well.
 */
Context.prototype.copy = function() {
  var cxt = new Context();
  var map = this.getAll();
  for (var key in map) {
    cxt.add(key, map[key]);
  }
  for (var key in this.datasourceMap) {
    cxt.addDatasource(key, this.datasourceMap[key]);
  }
  return cxt;
}
<commit_msg>Context.log now supports varags and objects.<commit_after>/**
 * A context tracks the context of a particular execution queue.
 *
 * As the queue is processed, the context will gain information
 * about the results of each command executed.
 */
var util = require('util');
var Logger = require('./logging').Logger;

module.exports = Context;

function Context(initialValues) {
  this.resultMap = {};
  this.datasourceMap = {};

  // Debug flag.
  this.debug = false;

  // The logging event emitter.
  this.logger = new Logger();

  // This was initially done for safety.
  // Could this just be turned into
  // this.resultMap = intialvalues || {}
  if (typeof initialValues == 'object') {
    for (var name in initialValues) {
      this.add(name, initialValues[name]);
    }
  }
}

Context.prototype.add = function(name, value) {
  if (value == undefined)
    return;

  this.resultMap[name] = value;

}
Context.prototype.get = function(name) {
  return this.resultMap[name];
}

// Property 'length'.
Context.prototype.__defineGetter__('length', function() {
  return this.size();
});

Context.prototype.size = function() {
  // Since size is called rarely, we
  // calculate on the fly.
  var i = 0;
  for (var o in this.resultMap) {
    ++i;
  }
  return i;
}
Context.prototype.getAll = function() {
  return this.resultMap;
}

/**
 * Log a message to the logging facility.
 *
 * Attach an event listen to cxt.logger.
 * Then handle the following events (at your option):
 *
 * - warning
 * - fatal
 * - error
 * - info
 * - debug
 * - custom
 *
 * Note that the parameters are in reverse order for historical reasons.
 *
 * @param {String|Object} msg
 *   The message. If this is an object, it will be run through util.inspect().
 * @param {String|Number} ...
 *   Zero or more primatives that will be interpolated into `msg` using util.format().
 * @param {String} level
 *   THe log level.
 */
Context.prototype.log = function(msg, level) {
  if (arguments.length > 2) {
    var interp = Array.prototype.slice.call(arguments, 0, -1);
    msg = util.format.apply(this, interp);
  }
  else if (typeof msg != 'string') {
    msg = util.inspect(msg);
  }
  var logLevel = arguments.length > 2 ? arguments[arguments.length - 1] : level;
  this.logger.log(logLevel || "info", msg);
}

Context.prototype.setLogger = function(logger) {
  this.logger = logger;
}

// XXX: I don't like having one object serve as the compartment for both
// general objects and datasources. This should get refactored. But for
// the first go-around, I feel like I should favor simplicity.

Context.prototype.addDatasource = function(name, ds) {
  this.datasourceMap[name] = ds;
}

Context.prototype.getDatasource = function(name) {
  return this.datasourceMap[name];
}

Context.prototype.removeDatasource = function(name) {
  this.datasourceMap[name] = null;
}

/**
 * A partial clone of a context.
 *
 * This returns a new context with the same data
 * and datasources as the base. Note that the
 * values in this context are not cloned. So modifying them
 * will modify the base copy as well.
 */
Context.prototype.copy = function() {
  var cxt = new Context();
  var map = this.getAll();
  for (var key in map) {
    cxt.add(key, map[key]);
  }
  for (var key in this.datasourceMap) {
    cxt.addDatasource(key, this.datasourceMap[key]);
  }
  return cxt;
}
<|endoftext|>


<commit_before>'use strict';

var cheerio = require('cheerio');
var snakeCase = require('change-case').snakeCase;
var flatten = require('annofp').flatten;
var is = require('annois');
var unidecode = require('unidecode');

var convertTag = require('./convert_tag');
var toMarkdown = require('./to_markdown');

module.exports = function(json, extend) {
    extend = extend || function(data) {
        return data;
    };

    if(!json.feed) {
        return {};
    }

    var slugs = [], images = [];

    var posts = json.feed.entry ? json.feed.entry.map(function(post, i) {
        var title = post.title['$t'].trim(),
            slug = snakeCase(unidecode(title)),
            html = post.content['$t'],
            markdown = tomd(html),
            published = Date.parse(post.published['$t']);

        // prevent duplicate slugs (suffix post index if slug exists)
        slug = slugs.indexOf(slug) === -1 ? slug : slug + i;
        slugs.push(slug);

        // grab a post's images and add to global images array (for download later)
        var postImages = markdown.match(/\[!\[]\((.*?)\)/);
        if (postImages !== null) {
            postImages.forEach(function(image){
                images.push(image.replace('[![](', '').replace(/.(jpg|JPG|jpeg|JPEG|gif|GIF|png|PNG)\)/, '.$1'));
            });
        }

        return extend({
            id: i,
            title: title,
            slug: slug,
            markdown: markdown,
            html: html,
            image: null,
            featured: 0,
            page: 0,
            status: 'published',
            language: 'en_US',
            'meta_title': null,
            'meta_description': null,
            'author_id': 1,
            'created_at': published,
            'created_by': 1,
            'updated_at': Date.parse(post.updated['$t']),
            'updated_by': 1,
            'published_at': published,
            'published_by': 1
        }, post);
    }): [];

    var tagIds = {};
    var tags = json.feed.category ? json.feed.category.map(function(category, i) {
        var name = convertTag(category.term);

        tagIds[name] = i;

        return {
            id: i,
            name: name,
            slug: snakeCase(unidecode(name)),
            description: ''
        };
    }): [];

    var postsTags = json.feed.entry ? flatten(json.feed.entry.map(function(post, i) {
        if(!is.array(post.category)) {
            return [];
        }

        return post.category.map(function(category) {
            var term = convertTag(category.term);
            var tagId = tagIds[term];

            if(!is.defined(tagId)) {
                console.error(term + ' doesn\'t have a tag associated to it!');

                return {};
            }

            return {
                'tag_id': tagId,
                'post_id': i
            };
        });
    })): [];

    return {
        meta: {
            'exported_on': Date.now(),
            version: '000'
        },
        images: images,
        data: {
            posts: posts,
            tags: tags,
            'posts_tags': postsTags
        }
    };
};

function tomd(html) {
    var $ = cheerio.load(html);

    // remove links from img's that link to themselves
    $('a').replaceWith(function(i, e) {
        if ($(e).find('img').length) {
            if ($(e).attr('href') === $(e).find('img').first().attr('src')) {
                return $(e).find('img').first();
            }
        }

        return $(e);
    });

    html = $.html();

    // remove div's
    html = html.replace(/<div(.*?)>|<\/div>/gi, '');

    // remove span's
    html = html.replace(/<span(.*?)>|<\/span>/gi, '');

    // remove tables
    html = html.replace(/<table(.*?)>|<thead(.*?)>|<tbody(.*?)>|<tr(.*?)>|<td(.*?)>|<\/td>|<\/tr>|<\/tbody>|<\/thead>|<\/table>/gi, '');

    var markdown = toMarkdown(html);

    markdown = markdown
        .replace(/ /gi, ' ') // remove nbsp's
        .replace(/&/g, '&') // replace ampersands
        .replace(/  +/g, ' ') // remove double spaces
        .replace(/\!\[]\((.*?)\)/g, '![]($1)\n\n') // add double line break after images
        .replace(/(\n\s+)/g, '\n\n') // remove space at beginning of a line
        .trim(); // remove trailing whitespace

    // replace image paths
    markdown = markdown.replace(/\!\[\]\((\bhttps?:\/\/[^\s()<>]+(?:\([\w\d]+\)|[^[:punct:]\s]|\/))/ig, '![](/content/images/blogger/');

    return markdown;
}
<commit_msg>replace authors<commit_after>'use strict';

var cheerio = require('cheerio');
var snakeCase = require('change-case').snakeCase;
var flatten = require('annofp').flatten;
var is = require('annois');
var unidecode = require('unidecode');

var convertTag = require('./convert_tag');
var toMarkdown = require('./to_markdown');

module.exports = function(json, extend) {
    extend = extend || function(data) {
        return data;
    };

    if(!json.feed) {
        return {};
    }

    var slugs = [], images = [];

    var posts = json.feed.entry ? json.feed.entry.map(function(post, i) {
        var title = post.title['$t'].trim(),
            slug = snakeCase(unidecode(title)),
            html = post.content['$t'],
            markdown = tomd(html),
            published = Date.parse(post.published['$t']);

        // prevent duplicate slugs (suffix post index if slug exists)
        slug = slugs.indexOf(slug) === -1 ? slug : slug + i;
        slugs.push(slug);

        // grab a post's images and add to global images array (for download later)
        var postImages = markdown.match(/\[!\[]\((.*?)\)/);
        if (postImages !== null) {
            postImages.forEach(function(image){
                images.push(image.replace('[![](', '').replace(/.(jpg|JPG|jpeg|JPEG|gif|GIF|png|PNG)\)/, '.$1'));
            });
        }

        var publishedBy = post.author[0].name['$t'],
            authors = {
                'Kai Price': 2,
                'Amanda Nelson': 3
            };

        return extend({
            id: i,
            title: title,
            slug: slug,
            markdown: markdown,
            html: html,
            image: null,
            featured: 0,
            page: 0,
            status: 'published',
            language: 'en_US',
            'meta_title': null,
            'meta_description': null,
            'author_id': 1,
            'created_at': published,
            'created_by': 1,
            'updated_at': Date.parse(post.updated['$t']),
            'updated_by': 1,
            'published_at': published,
            'published_by': authors[publishedBy] ? authors[publishedBy] : 1
        }, post);
    }): [];

    var tagIds = {};
    var tags = json.feed.category ? json.feed.category.map(function(category, i) {
        var name = convertTag(category.term);

        tagIds[name] = i;

        return {
            id: i,
            name: name,
            slug: snakeCase(unidecode(name)),
            description: ''
        };
    }): [];

    var postsTags = json.feed.entry ? flatten(json.feed.entry.map(function(post, i) {
        if(!is.array(post.category)) {
            return [];
        }

        return post.category.map(function(category) {
            var term = convertTag(category.term);
            var tagId = tagIds[term];

            if(!is.defined(tagId)) {
                console.error(term + ' doesn\'t have a tag associated to it!');

                return {};
            }

            return {
                'tag_id': tagId,
                'post_id': i
            };
        });
    })): [];

    return {
        meta: {
            'exported_on': Date.now(),
            version: '000'
        },
        images: images,
        data: {
            posts: posts,
            tags: tags,
            'posts_tags': postsTags
        }
    };
};

function tomd(html) {
    var $ = cheerio.load(html);

    // remove links from img's that link to themselves
    $('a').replaceWith(function(i, e) {
        if ($(e).find('img').length) {
            if ($(e).attr('href') === $(e).find('img').first().attr('src')) {
                return $(e).find('img').first();
            }
        }

        return $(e);
    });

    html = $.html();

    // remove div's
    html = html.replace(/<div(.*?)>|<\/div>/gi, '');

    // remove span's
    html = html.replace(/<span(.*?)>|<\/span>/gi, '');

    // remove tables
    html = html.replace(/<table(.*?)>|<thead(.*?)>|<tbody(.*?)>|<tr(.*?)>|<td(.*?)>|<\/td>|<\/tr>|<\/tbody>|<\/thead>|<\/table>/gi, '');

    var markdown = toMarkdown(html);

    markdown = markdown
        .replace(/ /gi, ' ') // remove nbsp's
        .replace(/&/g, '&') // replace ampersands
        .replace(/  +/g, ' ') // remove double spaces
        .replace(/\!\[]\((.*?)\)/g, '![]($1)\n\n') // add double line break after images
        .replace(/(\n\s+)/g, '\n\n') // remove space at beginning of a line
        .trim(); // remove trailing whitespace

    // replace image paths
    markdown = markdown.replace(/\!\[\]\((\bhttps?:\/\/[^\s()<>]+(?:\([\w\d]+\)|[^[:punct:]\s]|\/))/ig, '![](/content/images/blogger/');

    return markdown;
}
<|endoftext|>