<commit_before>var acornToEsprima = require("acorn-to-esprima");
var assign         = require("lodash.assign");
var pick           = require("lodash.pick");
var Module         = require("module");
var path           = require("path");
var parse          = require("babel-core").parse;
var t              = require("babel-core").types;
var tt             = require("babel-core").acorn.tokTypes;
var traverse       = require("babel-core").traverse;

var estraverse;
var hasPatched = false;

function createModule(filename) {
  var mod = new Module(filename);
  mod.filename = filename;
  mod.paths = Module._nodeModulePaths(path.dirname(filename));
  return mod;
}

function monkeypatch() {
  if (hasPatched) return;
  hasPatched = true;

  var eslintLoc;
  try {
    // avoid importing a local copy of eslint, try to find a peer dependency
    eslintLoc = Module._resolveFilename("eslint", module.parent);
  } catch (err) {
    try {
      // avoids breaking in jest where module.parent is undefined
      eslintLoc = require.resolve("eslint");
    } catch (err) {
      throw new ReferenceError("couldn't resolve eslint");
    }
  }

  // get modules relative to what eslint will load
  var eslintMod = createModule(eslintLoc);
  var escopeLoc = Module._resolveFilename("escope", eslintMod);
  var escopeMod = createModule(escopeLoc);

  // npm 3: monkeypatch estraverse if it's in escope
  var estraverseRelative = escopeMod;
  try {
    var esrecurseLoc = Module._resolveFilename("esrecurse", eslintMod);
    estraverseRelative = createModule(esrecurseLoc);
  } catch (err) {}

  // monkeypatch estraverse
  estraverse = estraverseRelative.require("estraverse");
  assign(estraverse.VisitorKeys, t.VISITOR_KEYS);

  // monkeypatch estraverse-fb
  var estraverseFb = eslintMod.require("estraverse-fb");
  assign(estraverseFb.VisitorKeys, t.VISITOR_KEYS);

  // ESLint v1.9.0 uses estraverse directly to work around https://github.com/npm/npm/issues/9663
  var estraverseOfEslint = eslintMod.require("estraverse");
  if (estraverseOfEslint !== estraverseFb) {
    assign(estraverseOfEslint.VisitorKeys, t.VISITOR_KEYS);
  }

  // monkeypatch escope
  var escope  = require(escopeLoc);
  var analyze = escope.analyze;
  escope.analyze = function (ast, opts) {
    opts.ecmaVersion = 6;
    opts.sourceType = "module";
    var results = analyze.call(this, ast, opts);
    return results;
  };

  // monkeypatch escope/referencer
  var referencerLoc;
  try {
    referencerLoc = Module._resolveFilename("./referencer", escopeMod);
  } catch (err) {
    throw new ReferenceError("couldn't resolve escope/referencer");
  }
  var referencerMod = createModule(referencerLoc);
  var referencer = require(referencerLoc);

  // monkeypatch escope/pattern-visitor
  var patternVisitorLoc;
  var patternVisitorMod;
  var patternVisitor;
  try {
    patternVisitorLoc = Module._resolveFilename("./pattern-visitor", escopeMod);
    patternVisitorMod = createModule(patternVisitorLoc);
    patternVisitor = require(patternVisitorLoc);
  } catch (err) {
    // When eslint uses old escope, we cannot find pattern visitor.
    // Fallback to the old way.
  }

  // reference Definition
  var definitionLoc;
  try {
    definitionLoc = Module._resolveFilename("./definition", referencerMod);
  } catch (err) {
    throw new ReferenceError("couldn't resolve escope/definition");
  }
  var Definition = require(definitionLoc).Definition;

  // if there are decorators, then visit each
  function visitDecorators(node) {
    if (!node.decorators) {
      return;
    }
    for (var i = 0; i < node.decorators.length; i++) {
      if (node.decorators[i].expression) {
        this.visit(node.decorators[i]);
      }
    }
  }

  // iterate through part of t.VISITOR_KEYS
  var visitorKeysMap = pick(t.VISITOR_KEYS, function(k) {
    return t.FLIPPED_ALIAS_KEYS.Flow.concat([
      "ArrayPattern",
      "ClassDeclaration",
      "ClassExpression",
      "FunctionDeclaration",
      "FunctionExpression",
      "Identifier",
      "ObjectPattern",
      "RestElement"
    ]).indexOf(k) === -1;
  });

  var propertyTypes = {
    // loops
    callProperties: { type: "loop", values: ["value"] },
    indexers: { type: "loop", values: ["key", "value"] },
    properties: { type: "loop", values: ["value"] },
    types: { type: "loop" },
    params: { type: "loop" },
    // single property
    argument: { type: "single" },
    elementType: { type: "single" },
    qualification: { type: "single" },
    rest: { type: "single" },
    returnType: { type: "single" },
    // others
    typeAnnotation: { type: "typeAnnotation" },
    typeParameters: { type: "typeParameters" },
    id: { type: "id" }
  };

  function visitTypeAnnotation(node) {
    // get property to check (params, id, etc...)
    var visitorValues = visitorKeysMap[node.type];
    if (!visitorValues) {
      return;
    }

    // can have multiple properties
    for (var i = 0; i < visitorValues.length; i++) {
      var visitorValue = visitorValues[i];
      var propertyType = propertyTypes[visitorValue];
      var nodeProperty = node[visitorValue];
      // check if property or type is defined
      if (propertyType == null || nodeProperty == null) {
        continue;
      }
      if (propertyType.type === "loop") {
        for (var j = 0; j < nodeProperty.length; j++) {
          if (Array.isArray(propertyType.values)) {
            for (var k = 0; k < propertyType.values.length; k++) {
              checkIdentifierOrVisit.call(this, nodeProperty[j][propertyType.values[k]]);
            }
          } else {
            checkIdentifierOrVisit.call(this, nodeProperty[j]);
          }
        }
      } else if (propertyType.type === "single") {
        checkIdentifierOrVisit.call(this, nodeProperty);
      } else if (propertyType.type === "typeAnnotation") {
        visitTypeAnnotation.call(this, node.typeAnnotation);
      } else if (propertyType.type === "typeParameters") {
        for (var l = 0; l < node.typeParameters.params.length; l++) {
          checkIdentifierOrVisit.call(this, node.typeParameters.params[l]);
        }
      } else if (propertyType.type === "id") {
        if (node.id.type === "Identifier") {
          checkIdentifierOrVisit.call(this, node.id);
        } else {
          visitTypeAnnotation.call(this, node.id);
        }
      }
    }
  }

  function checkIdentifierOrVisit(node) {
    if (node.typeAnnotation) {
      visitTypeAnnotation.call(this, node.typeAnnotation);
    } else if (node.type === "Identifier") {
      this.visit(node);
    } else {
      visitTypeAnnotation.call(this, node);
    }
  }

  function nestTypeParamScope(manager, node) {
    var parentScope = manager.__currentScope;
    var scope = new escope.Scope(manager, "type-parameters", parentScope, node, false);
    manager.__nestScope(scope);
    for (var j = 0; j < node.typeParameters.params.length; j++) {
      var name = node.typeParameters.params[j];
      scope.__define(name, new Definition("TypeParameter", name, name));
    }
    scope.__define = function() {
      return parentScope.__define.apply(parentScope, arguments);
    };
    return scope;
  }

  // visit decorators that are in: ClassDeclaration / ClassExpression
  var visitClass = referencer.prototype.visitClass;
  referencer.prototype.visitClass = function(node) {
    visitDecorators.call(this, node);
    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    // visit flow type: ClassImplements
    if (node.implements) {
      for (var i = 0; i < node.implements.length; i++) {
        checkIdentifierOrVisit.call(this, node.implements[i]);
      }
    }
    if (node.superTypeParameters) {
      for (var k = 0; k < node.superTypeParameters.params.length; k++) {
        checkIdentifierOrVisit.call(this, node.superTypeParameters.params[k]);
      }
    }
    visitClass.call(this, node);
    if (typeParamScope) {
      this.close(node);
    }
  };
    // visit decorators that are in: Property / MethodDefinition
  var visitProperty = referencer.prototype.visitProperty;
  referencer.prototype.visitProperty = function(node) {
    if (node.value.type === "TypeCastExpression") {
      visitTypeAnnotation.call(this, node.value);
    }
    visitDecorators.call(this, node);
    visitProperty.call(this, node);
  };

  // visit flow type in FunctionDeclaration, FunctionExpression, ArrowFunctionExpression
  var visitFunction = referencer.prototype.visitFunction;
  referencer.prototype.visitFunction = function(node) {
    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    if (node.returnType) {
      checkIdentifierOrVisit.call(this, node.returnType);
    }
    // only visit if function parameters have types
    if (node.params) {
      for (var i = 0; i < node.params.length; i++) {
        var param = node.params[i];
        if (param.typeAnnotation) {
          checkIdentifierOrVisit.call(this, param);
        } else if (t.isAssignmentPattern(param)) {
          if (param.left.typeAnnotation) {
            checkIdentifierOrVisit.call(this, param.left);
          }
        }
      }
    }
    visitFunction.call(this, node);
    if (typeParamScope) {
      this.close(node);
    }
  };

  if (patternVisitor) {
    patternVisitor.prototype.SpreadProperty = function (node) {
      this.visit(node.argument);
    };
  }

  // visit flow type in VariableDeclaration
  var variableDeclaration = referencer.prototype.VariableDeclaration;
  referencer.prototype.VariableDeclaration = function(node) {
    if (node.declarations) {
      for (var i = 0; i < node.declarations.length; i++) {
        var id = node.declarations[i].id;
        var typeAnnotation = id.typeAnnotation;
        if (typeAnnotation) {
          checkIdentifierOrVisit.call(this, typeAnnotation);
        }
        if (!patternVisitor) {
          // Old method. Once escope in eslint is updated, this code is not necessary.
          if (id.type === "ObjectPattern") {
            // check if object destructuring has a spread
            var hasSpread = id.properties.filter(function(p) {
              return p._babelType === "SpreadProperty";
            });
            // visit properties if so
            if (hasSpread.length > 0) {
              for (var j = 0; j < id.properties.length; j++) {
                this.visit(id.properties[j]);
              }
            }
          }
        }
      }
    }
    variableDeclaration.call(this, node);
  };

  function createScopeVariable (node, name) {
    this.currentScope().variableScope.__define(name,
      new Definition(
        "Variable",
        name,
        node,
        null,
        null,
        null
      )
    );
  }

  referencer.prototype.TypeAlias = function(node) {
    createScopeVariable.call(this, node, node.id);
    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    if (node.right) {
      visitTypeAnnotation.call(this, node.right);
    }
    if (typeParamScope) {
      this.close(node);
    }
  };

  referencer.prototype.ComprehensionExpression = function(node) {
    for (var i = 0; i < node.blocks.length; i++) {
      var block = node.blocks[i];
      if (block.left) {
        var scope = new escope.Scope(this.scopeManager, "comprehensions", this.currentScope(), node, false);
        this.scopeManager.__nestScope(scope);

        var left = block.left;
        if (left.type === "Identifier") {
          scope.__define(left, new Definition("ComprehensionElement", left, left));
        } else if (left.type === "ArrayPattern") {
          for (var i = 0; i < left.elements.length; i++) {
            var name = left.elements[i];
            if (name) {
              scope.__define(name, new Definition("ComprehensionElement", name, name));
            }
          }
        } else if (left.type === "ObjectPattern") {
          for (var i = 0; i < left.properties.length; i++) {
            var name = left.properties[i];
            if (name && name.key && name.key.type === "Identifier") {
              scope.__define(name.key, new Definition("ComprehensionElement", name.key, name.key));
            }
          }
        }
      }
      if (block.right) {
        this.visit(block.right);
      }
    }
    if (node.filter) {
      this.visit(node.filter);
    }
    this.visit(node.body);
    this.close(node);
  };

  referencer.prototype.DeclareModule =
  referencer.prototype.DeclareFunction =
  referencer.prototype.DeclareVariable =
  referencer.prototype.DeclareClass = function(node) {
    if (node.id) {
      createScopeVariable.call(this, node, node.id);
    }

    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    if (typeParamScope) {
      this.close(node);
    }
  };
}

exports.parse = function (code) {
  try {
    monkeypatch();
  } catch (err) {
    console.error(err.stack);
    process.exit(1);
  }

  return exports.parseNoPatch(code);
}

exports.parseNoPatch = function (code) {
  var opts = {
    locations: true,
    ranges: true
  };

  var comments = opts.onComment = [];
  var tokens = opts.onToken = [];

  var ast;
  try {
    ast = parse(code, opts);
  } catch (err) {
    if (err instanceof SyntaxError) {
      err.lineNumber = err.loc.line;
      err.column = err.loc.column;

      // remove trailing "(LINE:COLUMN)" acorn message and add in esprima syntax error message start
      err.message = "Line " + err.lineNumber + ": " + err.message.replace(/ \((\d+):(\d+)\)$/, "");
    }

    throw err;
  }

  // remove EOF token, eslint doesn't use this for anything and it interferes with some rules
  // see https://github.com/babel/babel-eslint/issues/2 for more info
  // todo: find a more elegant way to do this
  tokens.pop();

  // convert tokens
  ast.tokens = acornToEsprima.toTokens(tokens, tt);

  // add comments
  acornToEsprima.convertComments(comments);
  ast.comments = comments;
  acornToEsprima.attachComments(ast, comments, ast.tokens);

  // transform esprima and acorn divergent nodes
  acornToEsprima.toAST(ast, traverse);

  return ast;
}
<commit_msg>Avoid errors in eslint 1.10.x when excluding destructured properties.<commit_after>var acornToEsprima = require("acorn-to-esprima");
var assign         = require("lodash.assign");
var pick           = require("lodash.pick");
var Module         = require("module");
var path           = require("path");
var parse          = require("babel-core").parse;
var t              = require("babel-core").types;
var tt             = require("babel-core").acorn.tokTypes;
var traverse       = require("babel-core").traverse;

var estraverse;
var hasPatched = false;

function createModule(filename) {
  var mod = new Module(filename);
  mod.filename = filename;
  mod.paths = Module._nodeModulePaths(path.dirname(filename));
  return mod;
}

function monkeypatch() {
  if (hasPatched) return;
  hasPatched = true;

  var eslintLoc;
  try {
    // avoid importing a local copy of eslint, try to find a peer dependency
    eslintLoc = Module._resolveFilename("eslint", module.parent);
  } catch (err) {
    try {
      // avoids breaking in jest where module.parent is undefined
      eslintLoc = require.resolve("eslint");
    } catch (err) {
      throw new ReferenceError("couldn't resolve eslint");
    }
  }

  // get modules relative to what eslint will load
  var eslintMod = createModule(eslintLoc);
  var escopeLoc = Module._resolveFilename("escope", eslintMod);
  var escopeMod = createModule(escopeLoc);

  // npm 3: monkeypatch estraverse if it's in escope
  var estraverseRelative = escopeMod;
  try {
    var esrecurseLoc = Module._resolveFilename("esrecurse", eslintMod);
    estraverseRelative = createModule(esrecurseLoc);
  } catch (err) {}

  // monkeypatch estraverse
  estraverse = estraverseRelative.require("estraverse");
  assign(estraverse.VisitorKeys, t.VISITOR_KEYS);

  // monkeypatch estraverse-fb
  var estraverseFb = eslintMod.require("estraverse-fb");
  assign(estraverseFb.VisitorKeys, t.VISITOR_KEYS);

  // ESLint v1.9.0 uses estraverse directly to work around https://github.com/npm/npm/issues/9663
  var estraverseOfEslint = eslintMod.require("estraverse");
  if (estraverseOfEslint !== estraverseFb) {
    assign(estraverseOfEslint.VisitorKeys, t.VISITOR_KEYS);
  }

  // monkeypatch escope
  var escope  = require(escopeLoc);
  var analyze = escope.analyze;
  escope.analyze = function (ast, opts) {
    opts.ecmaVersion = 6;
    opts.sourceType = "module";
    var results = analyze.call(this, ast, opts);
    return results;
  };

  // monkeypatch escope/referencer
  var referencerLoc;
  try {
    referencerLoc = Module._resolveFilename("./referencer", escopeMod);
  } catch (err) {
    throw new ReferenceError("couldn't resolve escope/referencer");
  }
  var referencerMod = createModule(referencerLoc);
  var referencer = require(referencerLoc);

  // monkeypatch escope/pattern-visitor
  var patternVisitorLoc;
  var patternVisitorMod;
  var patternVisitor;
  try {
    patternVisitorLoc = Module._resolveFilename("./pattern-visitor", escopeMod);
    patternVisitorMod = createModule(patternVisitorLoc);
    patternVisitor = require(patternVisitorLoc);
  } catch (err) {
    // When eslint uses old escope, we cannot find pattern visitor.
    // Fallback to the old way.
  }

  // reference Definition
  var definitionLoc;
  try {
    definitionLoc = Module._resolveFilename("./definition", referencerMod);
  } catch (err) {
    throw new ReferenceError("couldn't resolve escope/definition");
  }
  var Definition = require(definitionLoc).Definition;

  // if there are decorators, then visit each
  function visitDecorators(node) {
    if (!node.decorators) {
      return;
    }
    for (var i = 0; i < node.decorators.length; i++) {
      if (node.decorators[i].expression) {
        this.visit(node.decorators[i]);
      }
    }
  }

  // iterate through part of t.VISITOR_KEYS
  var visitorKeysMap = pick(t.VISITOR_KEYS, function(k) {
    return t.FLIPPED_ALIAS_KEYS.Flow.concat([
      "ArrayPattern",
      "ClassDeclaration",
      "ClassExpression",
      "FunctionDeclaration",
      "FunctionExpression",
      "Identifier",
      "ObjectPattern",
      "RestElement"
    ]).indexOf(k) === -1;
  });

  var propertyTypes = {
    // loops
    callProperties: { type: "loop", values: ["value"] },
    indexers: { type: "loop", values: ["key", "value"] },
    properties: { type: "loop", values: ["value"] },
    types: { type: "loop" },
    params: { type: "loop" },
    // single property
    argument: { type: "single" },
    elementType: { type: "single" },
    qualification: { type: "single" },
    rest: { type: "single" },
    returnType: { type: "single" },
    // others
    typeAnnotation: { type: "typeAnnotation" },
    typeParameters: { type: "typeParameters" },
    id: { type: "id" }
  };

  function visitTypeAnnotation(node) {
    // get property to check (params, id, etc...)
    var visitorValues = visitorKeysMap[node.type];
    if (!visitorValues) {
      return;
    }

    // can have multiple properties
    for (var i = 0; i < visitorValues.length; i++) {
      var visitorValue = visitorValues[i];
      var propertyType = propertyTypes[visitorValue];
      var nodeProperty = node[visitorValue];
      // check if property or type is defined
      if (propertyType == null || nodeProperty == null) {
        continue;
      }
      if (propertyType.type === "loop") {
        for (var j = 0; j < nodeProperty.length; j++) {
          if (Array.isArray(propertyType.values)) {
            for (var k = 0; k < propertyType.values.length; k++) {
              checkIdentifierOrVisit.call(this, nodeProperty[j][propertyType.values[k]]);
            }
          } else {
            checkIdentifierOrVisit.call(this, nodeProperty[j]);
          }
        }
      } else if (propertyType.type === "single") {
        checkIdentifierOrVisit.call(this, nodeProperty);
      } else if (propertyType.type === "typeAnnotation") {
        visitTypeAnnotation.call(this, node.typeAnnotation);
      } else if (propertyType.type === "typeParameters") {
        for (var l = 0; l < node.typeParameters.params.length; l++) {
          checkIdentifierOrVisit.call(this, node.typeParameters.params[l]);
        }
      } else if (propertyType.type === "id") {
        if (node.id.type === "Identifier") {
          checkIdentifierOrVisit.call(this, node.id);
        } else {
          visitTypeAnnotation.call(this, node.id);
        }
      }
    }
  }

  function checkIdentifierOrVisit(node) {
    if (node.typeAnnotation) {
      visitTypeAnnotation.call(this, node.typeAnnotation);
    } else if (node.type === "Identifier") {
      this.visit(node);
    } else {
      visitTypeAnnotation.call(this, node);
    }
  }

  function nestTypeParamScope(manager, node) {
    var parentScope = manager.__currentScope;
    var scope = new escope.Scope(manager, "type-parameters", parentScope, node, false);
    manager.__nestScope(scope);
    for (var j = 0; j < node.typeParameters.params.length; j++) {
      var name = node.typeParameters.params[j];
      scope.__define(name, new Definition("TypeParameter", name, name));
    }
    scope.__define = function() {
      return parentScope.__define.apply(parentScope, arguments);
    };
    return scope;
  }

  // visit decorators that are in: ClassDeclaration / ClassExpression
  var visitClass = referencer.prototype.visitClass;
  referencer.prototype.visitClass = function(node) {
    visitDecorators.call(this, node);
    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    // visit flow type: ClassImplements
    if (node.implements) {
      for (var i = 0; i < node.implements.length; i++) {
        checkIdentifierOrVisit.call(this, node.implements[i]);
      }
    }
    if (node.superTypeParameters) {
      for (var k = 0; k < node.superTypeParameters.params.length; k++) {
        checkIdentifierOrVisit.call(this, node.superTypeParameters.params[k]);
      }
    }
    visitClass.call(this, node);
    if (typeParamScope) {
      this.close(node);
    }
  };
    // visit decorators that are in: Property / MethodDefinition
  var visitProperty = referencer.prototype.visitProperty;
  referencer.prototype.visitProperty = function(node) {
    if (node.value.type === "TypeCastExpression") {
      visitTypeAnnotation.call(this, node.value);
    }
    visitDecorators.call(this, node);
    visitProperty.call(this, node);
  };

  // visit flow type in FunctionDeclaration, FunctionExpression, ArrowFunctionExpression
  var visitFunction = referencer.prototype.visitFunction;
  referencer.prototype.visitFunction = function(node) {
    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    if (node.returnType) {
      checkIdentifierOrVisit.call(this, node.returnType);
    }
    // only visit if function parameters have types
    if (node.params) {
      for (var i = 0; i < node.params.length; i++) {
        var param = node.params[i];
        if (param.typeAnnotation) {
          checkIdentifierOrVisit.call(this, param);
        } else if (t.isAssignmentPattern(param)) {
          if (param.left.typeAnnotation) {
            checkIdentifierOrVisit.call(this, param.left);
          }
        }
      }
    }
    visitFunction.call(this, node);
    if (typeParamScope) {
      this.close(node);
    }
  };

  if (patternVisitor) {
    patternVisitor.prototype.SpreadProperty = function (node) {
      this.visit(node.argument);
    };
  }

  // visit flow type in VariableDeclaration
  var variableDeclaration = referencer.prototype.VariableDeclaration;
  referencer.prototype.VariableDeclaration = function(node) {
    if (node.declarations) {
      for (var i = 0; i < node.declarations.length; i++) {
        var id = node.declarations[i].id;
        var typeAnnotation = id.typeAnnotation;
        if (typeAnnotation) {
          checkIdentifierOrVisit.call(this, typeAnnotation);
        }
        if (id.type === "ObjectPattern") {
          // check if object destructuring has a spread
          var hasSpread = id.properties.filter(function(p) {
            return p._babelType === "SpreadProperty";
          });
          // visit properties if so
          if (hasSpread.length > 0) {
            for (var j = 0; j < id.properties.length; j++) {
              this.visit(id.properties[j]);
            }
          }
        }
      }
    }
    variableDeclaration.call(this, node);
  };

  function createScopeVariable (node, name) {
    this.currentScope().variableScope.__define(name,
      new Definition(
        "Variable",
        name,
        node,
        null,
        null,
        null
      )
    );
  }

  referencer.prototype.TypeAlias = function(node) {
    createScopeVariable.call(this, node, node.id);
    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    if (node.right) {
      visitTypeAnnotation.call(this, node.right);
    }
    if (typeParamScope) {
      this.close(node);
    }
  };

  referencer.prototype.ComprehensionExpression = function(node) {
    for (var i = 0; i < node.blocks.length; i++) {
      var block = node.blocks[i];
      if (block.left) {
        var scope = new escope.Scope(this.scopeManager, "comprehensions", this.currentScope(), node, false);
        this.scopeManager.__nestScope(scope);

        var left = block.left;
        if (left.type === "Identifier") {
          scope.__define(left, new Definition("ComprehensionElement", left, left));
        } else if (left.type === "ArrayPattern") {
          for (var i = 0; i < left.elements.length; i++) {
            var name = left.elements[i];
            if (name) {
              scope.__define(name, new Definition("ComprehensionElement", name, name));
            }
          }
        } else if (left.type === "ObjectPattern") {
          for (var i = 0; i < left.properties.length; i++) {
            var name = left.properties[i];
            if (name && name.key && name.key.type === "Identifier") {
              scope.__define(name.key, new Definition("ComprehensionElement", name.key, name.key));
            }
          }
        }
      }
      if (block.right) {
        this.visit(block.right);
      }
    }
    if (node.filter) {
      this.visit(node.filter);
    }
    this.visit(node.body);
    this.close(node);
  };

  referencer.prototype.DeclareModule =
  referencer.prototype.DeclareFunction =
  referencer.prototype.DeclareVariable =
  referencer.prototype.DeclareClass = function(node) {
    if (node.id) {
      createScopeVariable.call(this, node, node.id);
    }

    var typeParamScope;
    if (node.typeParameters) {
      typeParamScope = nestTypeParamScope(this.scopeManager, node);
    }
    if (typeParamScope) {
      this.close(node);
    }
  };
}

exports.parse = function (code) {
  try {
    monkeypatch();
  } catch (err) {
    console.error(err.stack);
    process.exit(1);
  }

  return exports.parseNoPatch(code);
}

exports.parseNoPatch = function (code) {
  var opts = {
    locations: true,
    ranges: true
  };

  var comments = opts.onComment = [];
  var tokens = opts.onToken = [];

  var ast;
  try {
    ast = parse(code, opts);
  } catch (err) {
    if (err instanceof SyntaxError) {
      err.lineNumber = err.loc.line;
      err.column = err.loc.column;

      // remove trailing "(LINE:COLUMN)" acorn message and add in esprima syntax error message start
      err.message = "Line " + err.lineNumber + ": " + err.message.replace(/ \((\d+):(\d+)\)$/, "");
    }

    throw err;
  }

  // remove EOF token, eslint doesn't use this for anything and it interferes with some rules
  // see https://github.com/babel/babel-eslint/issues/2 for more info
  // todo: find a more elegant way to do this
  tokens.pop();

  // convert tokens
  ast.tokens = acornToEsprima.toTokens(tokens, tt);

  // add comments
  acornToEsprima.convertComments(comments);
  ast.comments = comments;
  acornToEsprima.attachComments(ast, comments, ast.tokens);

  // transform esprima and acorn divergent nodes
  acornToEsprima.toAST(ast, traverse);

  return ast;
}
<|endoftext|>


<commit_before>module.exports = {
  builders: {
    routes: require('./builders/routes'),
    shapes: require('./builders/shapes'),
    stops: require('./builders/stops')
  }
};
<commit_msg>refactored cache method<commit_after>var fs = require('fs');
var _ = require('lodash');
var request = require('superagent');
var Promise = require('es6-promise').Promise;

// XXX refactor, duplicate code also present in Gruntfile.js
function cache(){
  var OSM3S_API = 'http://api.openstreetmap.fr/oapi/interpreter';

  var mastersQuery = fs.readFileSync('queries/get-master-routes.osm3s').toString();
  var stopsQuery = fs.readFileSync('queries/get-stops-nodes.osm3s').toString();
  var routesQuery = fs.readFileSync('queries/get-routes-rel.osm3s').toString();
  var waysQuery = fs.readFileSync('queries/get-routes-ways.osm3s').toString();
  var nodesQuery = fs.readFileSync('queries/get-routes-nodes.osm3s').toString();

  var queries = [mastersQuery, stopsQuery, routesQuery, waysQuery, nodesQuery];

  /*
   * gets data from OSM Overpass API
   */
  function queryOSM(query){
    return new Promise(function(resolve, reject){
      request.get(OSM3S_API)
        .query({data: query})
        .end(function(err, res){
          if(err){
            reject(err);
          } else {
            resolve(res.body);
          }
        });
    });
  }

  /*
   * array of arrays with [routes, ways, nodes]
   */
  function saveData(data){
    var types = ['masters', 'stops', 'routes', 'ways', 'nodes'];
    _.each(data, function(arr, index){
      fs.writeFileSync('./cache/' + types[index] + '.json', JSON.stringify(arr));
    });
    console.log('data saved to ./cache');
  }

  /*
   * get all data and save to disk
   */
  return Promise.all(queries.map(queryOSM))
    .then(saveData);

};

module.exports = {
  builders: {
    routes: require('./builders/routes'),
    shapes: require('./builders/shapes'),
    stops: require('./builders/stops')
  },
  cache:cache
};
<|endoftext|>


<commit_before>"use strict";

var _ = require("lodash"),
    Sequelize = require("sequelize"),
    guard = require("when/guard"),
    when = require("when");

module.exports = function G(sequelizeModelOrInstance, options) {
    options = _.merge({
        attributes: {},
        number: 1
    }, options);

    function valueBasedOnAttribute(attribute) {
        var typeString;

        if (attribute.type) {
            typeString = attribute.type.toString();
        } else {
            typeString = attribute;
        }

        if (typeString === "ENUM") {
            return _.sample(attribute.values);
        } else if (_.contains(["INTEGER", "SMALLINT UNSIGNED"], typeString)) {
            return _.parseInt(_.uniqueId(), 10);
            // starts with VARCHAR( or CHAR(, or is TEXT
        } else if (typeString.indexOf("VARCHAR(") === 0 || typeString.indexOf("CHAR") === 0 || typeString === "TEXT") {
            if (attribute.validate && attribute.validate.isUrl) {
                return "http://example.com/" + _.uniqueId();
            } else {
                return _.uniqueId();
            }
        }

        return null;
    }

    function setDefaultAttributesValue(rawAttributes, customValues, associationIdentifiers) {
        var attributes = _.clone(customValues);

        _(rawAttributes)
        // Removes from rawAttributes any attributes from customValues. We want user-passed values to take precedence
        .omit(_.keys(customValues))
        // Loop the remaining rawAttributes to set values according to its Sequelize data type
        .forEach(function (value, key) {
            if (!_.has(value, "autoIncrement") && value.autoIncrement !== true) {
                if (_.has(value, "references") || _.contains(associationIdentifiers, key)) {
                    attributes[key] = null;
                } else {
                    var valueToPopulate = valueBasedOnAttribute(value);
                    if (!_.isNull(valueToPopulate)) {
                        attributes[key] = valueToPopulate;
                    }
                }
            }
        }).value();

        return attributes;
    }

    function instancesIfNeeded(sequelizeModelOrInstance) {
        // It is a model, create the instance
        if (sequelizeModelOrInstance.tableName) {
            var associationIdentifiers = _.pluck(sequelizeModelOrInstance.associations, "identifier"),
                bulkCreateArgument = [];

            for (var i = 0; i < options.number; i++) {
                var attributes = setDefaultAttributesValue(sequelizeModelOrInstance.rawAttributes, options.attributes, associationIdentifiers);

                _.forEach(options.attributes, function (value, key) {
                    if (_.isArray(value)) { // If value is an array, we consume the first element
                        attributes[key] = value[i];
                    } else if (_.isFunction(value)) { // If value is a function, execute it
                        attributes[key] = value();
                    }
                });

                bulkCreateArgument.push(attributes);
            }

            // Sadly .bulkCreate does not return the newly created instances. We need to .findAll, but since calling G() multiple times
            // could potentially run .findAll and return previously created records, we need to .slice with just the last options.number
            // elements
            return sequelizeModelOrInstance.bulkCreate(bulkCreateArgument).then(function () {
                return sequelizeModelOrInstance.findAll();
            }).then(function (instances) {
                return instances.slice(-options.number);
            });
        } else {
            // It is already an instance, not a model, so wrap it as a promise
            return when([sequelizeModelOrInstance]);
        }
    }

    return instancesIfNeeded(sequelizeModelOrInstance).then(function (instances) {
        var instance;

        if (options.number > 1) {
            var originalNumber = options.number;

            options.number = options.number - instances.length;

            return when.map(instances, function (instance) {
                // This part should be refactored with bulkCreateArgument.push's from instancesIfNeeded()
                var attributes = {};

                _.forEach(options.attributes, function (value, key) {
                    if (_.isArray(value)) { // If value is an array, we consume the first element
                        attributes[key] = value.shift();
                    } else if (_.isFunction(value)) { // If value is a function, execute it
                        attributes[key] = value();
                    } else {
                        attributes[key] = value;
                    }
                });

                var optionsCopy = _.clone(options);
                optionsCopy.attributes = attributes;

                return new G(instance, optionsCopy);
            });
        } else {
            instance = instances[0];
        }

        // Since G is recursive, options.rootInstance keeps track of what should be ultimately returned
        if (!options.rootInstance) {
            options.rootInstance = instance;
        }

        instance.generator = {};

        var associations = _.where(instance.daoFactory.associations, {
            associationType: "BelongsTo"
        });

        if (_.isEmpty(associations)) {
            return instance;
        } else {
            return when.map(associations, function (association) {
                var target = association.target,
                    targetAttributes = options[target.name] && options[target.name].attributes || {},
                    targetInstancePromise;

                var associationIdentifiers = _.pluck(target.associations, "identifier");

                targetAttributes = setDefaultAttributesValue(target.rawAttributes, targetAttributes, associationIdentifiers);

                if (options[target.name] && options[target.name] === "shared") {
                    targetInstancePromise = target.findAll().then(function (targetInstances) {
                        if (targetInstances.length === 0) {
                            return target.create(targetAttributes);
                        } else {
                            return _.first(targetInstances);
                        }
                    });
                } else if (options[target.name] === null) {
                    return;
                } else {
                    // If the target identifier was passed as an atribute of instance, try to get the
                    // existing record from the database. In other words, the foreign key value is set.
                    // Otherwise, create the instance.
                    targetInstancePromise = target.findOrCreate({
                        id: options.attributes[association.identifier] || null
                    }, targetAttributes);
                }

                return targetInstancePromise.then(function (targetInstance) {
                    var setterName = Sequelize.Utils._.camelize("set_" + (association.options.as || Sequelize.Utils.singularize(association.target.tableName, association.options.language)));

                    instance.generator[target.name] = targetInstance;

                    return instance[setterName].call(instance, targetInstance).then(function () {
                        return targetInstance;
                    });
                });
            }).then(function (targetInstances) {
                var guardedAsyncOperation = guard(guard.n(1), function (targetInstance) {
                    if (targetInstance && !_.isEmpty(targetInstance.daoFactory.associations)) {
                        return new G(targetInstance, options);
                    } else {
                        return targetInstance;
                    }
                });

                return when.map(targetInstances, guardedAsyncOperation);
            }).then(function () {
                return options.rootInstance;
            });
        }
    });
};
<commit_msg>Re-added helpful comment<commit_after>"use strict";

var _ = require("lodash"),
    Sequelize = require("sequelize"),
    guard = require("when/guard"),
    when = require("when");

module.exports = function G(sequelizeModelOrInstance, options) {
    options = _.merge({
        attributes: {},
        number: 1
    }, options);

    function valueBasedOnAttribute(attribute) {
        var typeString;

        if (attribute.type) {
            typeString = attribute.type.toString();
        } else {
            typeString = attribute;
        }

        if (typeString === "ENUM") {
            return _.sample(attribute.values);
        } else if (_.contains(["INTEGER", "SMALLINT UNSIGNED"], typeString)) {
            return _.parseInt(_.uniqueId(), 10);
            // starts with VARCHAR( or CHAR(, or is TEXT
        } else if (typeString.indexOf("VARCHAR(") === 0 || typeString.indexOf("CHAR") === 0 || typeString === "TEXT") {
            if (attribute.validate && attribute.validate.isUrl) {
                return "http://example.com/" + _.uniqueId();
            } else {
                return _.uniqueId();
            }
        }

        return null;
    }

    function setDefaultAttributesValue(rawAttributes, customValues, associationIdentifiers) {
        var attributes = _.clone(customValues);

        _(rawAttributes)
        // Removes from rawAttributes any attributes from customValues. We want user-passed values to take precedence
        .omit(_.keys(customValues))
        // Loop the remaining rawAttributes to set values according to its Sequelize data type
        .forEach(function (value, key) {
            if (!_.has(value, "autoIncrement") && value.autoIncrement !== true) {
                if (_.has(value, "references") || _.contains(associationIdentifiers, key)) {
                    attributes[key] = null;
                } else {
                    var valueToPopulate = valueBasedOnAttribute(value);
                    if (!_.isNull(valueToPopulate)) {
                        attributes[key] = valueToPopulate;
                    }
                }
            }
        }).value();

        return attributes;
    }

    function instancesIfNeeded(sequelizeModelOrInstance) {
        // It is a model, create the instance
        if (sequelizeModelOrInstance.tableName) {
            var associationIdentifiers = _.pluck(sequelizeModelOrInstance.associations, "identifier"),
                bulkCreateArgument = [];

            for (var i = 0; i < options.number; i++) {
                var attributes = setDefaultAttributesValue(sequelizeModelOrInstance.rawAttributes, options.attributes, associationIdentifiers);

                _.forEach(options.attributes, function (value, key) {
                    if (_.isArray(value)) { // If value is an array, we consume the first element
                        attributes[key] = value[i];
                    } else if (_.isFunction(value)) { // If value is a function, execute it
                        attributes[key] = value();
                    }
                });

                bulkCreateArgument.push(attributes);
            }

            // Sadly .bulkCreate does not return the newly created instances. We need to .findAll, but since calling G() multiple times
            // could potentially run .findAll and return previously created records, we need to .slice with just the last options.number
            // elements
            return sequelizeModelOrInstance.bulkCreate(bulkCreateArgument).then(function () {
                return sequelizeModelOrInstance.findAll();
            }).then(function (instances) {
                return instances.slice(-options.number);
            });
        } else {
            // It is already an instance, not a model, so wrap it as a promise
            return when([sequelizeModelOrInstance]);
        }
    }

    return instancesIfNeeded(sequelizeModelOrInstance).then(function (instances) {
        var instance;

        if (options.number > 1) {
            var originalNumber = options.number;

            options.number = options.number - instances.length;

            return when.map(instances, function (instance) {
                // This part should be refactored with bulkCreateArgument.push's from instancesIfNeeded()
                var attributes = {};

                _.forEach(options.attributes, function (value, key) {
                    if (_.isArray(value)) { // If value is an array, we consume the first element
                        attributes[key] = value.shift();
                    } else if (_.isFunction(value)) { // If value is a function, execute it
                        attributes[key] = value();
                    } else {
                        attributes[key] = value;
                    }
                });

                var optionsCopy = _.clone(options);
                optionsCopy.attributes = attributes;

                return new G(instance, optionsCopy);
            });
        } else {
            instance = instances[0];
        }

        // Since G is recursive, options.rootInstance keeps track of what should be ultimately returned
        if (!options.rootInstance) {
            options.rootInstance = instance;
        }

        instance.generator = {};

        var associations = _.where(instance.daoFactory.associations, {
            associationType: "BelongsTo"
        });

        if (_.isEmpty(associations)) {
            return instance;
        } else {
            return when.map(associations, function (association) {
                var target = association.target,
                    targetAttributes = options[target.name] && options[target.name].attributes || {},
                    targetInstancePromise;

                var associationIdentifiers = _.pluck(target.associations, "identifier");

                targetAttributes = setDefaultAttributesValue(target.rawAttributes, targetAttributes, associationIdentifiers);

                if (options[target.name] && options[target.name] === "shared") {
                    targetInstancePromise = target.findAll().then(function (targetInstances) {
                        if (targetInstances.length === 0) {
                            return target.create(targetAttributes);
                        } else {
                            return _.first(targetInstances);
                        }
                    });
                } else if (options[target.name] === null) {
                    return;
                } else {
                    // If the target identifier was passed as an atribute of instance, try to get the
                    // existing record from the database. In other words, the foreign key value is set.
                    // Otherwise, create the instance.
                    targetInstancePromise = target.findOrCreate({
                        id: options.attributes[association.identifier] || null
                    }, targetAttributes);
                }

                return targetInstancePromise.then(function (targetInstance) {
                    // setterName code copied straight from Sequelize
                    // https://github.com/sequelize/sequelize/blob/0299ce638fc13ad79a50cd0714f274143babaf29/lib/associations/belongs-to.js#L71
                    var setterName = Sequelize.Utils._.camelize("set_" + (association.options.as || Sequelize.Utils.singularize(association.target.tableName, association.options.language)));

                    instance.generator[target.name] = targetInstance;

                    return instance[setterName].call(instance, targetInstance).then(function () {
                        return targetInstance;
                    });
                });
            }).then(function (targetInstances) {
                var guardedAsyncOperation = guard(guard.n(1), function (targetInstance) {
                    if (targetInstance && !_.isEmpty(targetInstance.daoFactory.associations)) {
                        return new G(targetInstance, options);
                    } else {
                        return targetInstance;
                    }
                });

                return when.map(targetInstances, guardedAsyncOperation);
            }).then(function () {
                return options.rootInstance;
            });
        }
    });
};
<|endoftext|>


<commit_before>module.exports = serial

function serial(list, iterator, callback) {
    (function loop(err) {
        if (err) {
            return callback && callback(err)
        }

        var item = list.shift()

        if (!item) {
            return
        }

        iterator(item, loop)
    }())
}
<commit_msg>lol callbacks<commit_after>module.exports = serial

function serial(list, iterator, callback) {
    (function loop(err) {
        if (err) {
            return callback && callback(err)
        }

        var item = list.shift()

        if (!item) {
            return callback(null)
        }

        iterator(item, loop)
    }())
}
<|endoftext|>


<commit_before>var path = require("path");
var to5  = require("6to5-core");
var fs   = require("fs");
var _    = require("lodash");

module.exports = function (opts) {
  opts = _.defaults(opts || {}, {
    options: {},
    dest:    "cache",
    src:     "assets"
  });

  var cache = Object.create(null);

  return function (req, res, next) {
    var url = req.url;
    if (!to5.canCompile(url)) return next();

    var dest = path.join(opts.dest, url);
    var src  = path.join(opts.src, url);

    var write = function (transformed) {
      fs.writeFile(dest, transformed, function (err) {
        if (err) {
          next(err);
        } else {
          cache[url] = Date.now();
          next();
        }
      });
    };

    var compile = function () {
      var transformOpts = _.clone(opts.options);

      to5.transformFile(src, transformOpts, function (err, result) {
        if (err) return next(err);
        write(result.code);
      });
    };

    var destExists = function () {
      fs.stat(dest, function (err, stat) {
        if (err) return next(err);

        if (cache[url] < +stat.mtime) {
          compile();
        } else {
          next();
        }
      });
    };

    fs.exists(src, function (exists) {
      if (!exists) return next();

      fs.exists(dest, function (exists) {
        if (exists && cache[dest]) {
          destExists();
        } else {
          compile();
        }
      });
    });
  };
};
<commit_msg>Don't uses `fs.exists`, but stat and check error.<commit_after>var path = require("path");
var to5  = require("6to5-core");
var fs   = require("fs");
var _    = require("lodash");

module.exports = function (opts) {
  opts = _.defaults(opts || {}, {
    options: {},
    dest:    "cache",
    src:     "assets"
  });

  var cache = Object.create(null);

  return function (req, res, next) {
    var url = req.url;
    if (!to5.canCompile(url)) return next();

    var dest = path.join(opts.dest, url);
    var src  = path.join(opts.src, url);
    var destStat;

    var write = function (transformed) {
      fs.writeFile(dest, transformed, function (err) {
        if (err) {
          next(err);
        } else {
          cache[url] = Date.now();
          next();
        }
      });
    };

    var compile = function () {
      var transformOpts = _.clone(opts.options);

      to5.transformFile(src, transformOpts, function (err, result) {
        if (err) return next(err);
        write(result.code);
      });
    };

    var destExists = function () {
      if (cache[url] < +destStat.mtime) {
        compile();
      } else {
        next();
      }
    };

    fs.stat(src, function (err, stat) {
      if (err && err.code === 'ENOENT') return next();
      else if (err) return next(err);

      fs.stat(dest, function (err, stat) {
        if (err && err.code !== 'ENOENT') return next(err);
        destStat = stat;

        if (!err && cache[dest]) {
          destExists();
        } else {
          compile();
        }
      });
    });
  };
};
<|endoftext|>


<commit_before>/*global __dirname*/
var fsExtra = require('fs-extra');
var Evaldown = require('evaldown');
var metalSmith = require('metalsmith');
var path = require('path');
var _ = require('lodash');

var createExpect = require('./lib/createExpect');

function idToName(id) {
  return id.replace(/-/g, ' ');
}

function getTypeHierarchy(typeIndex, typeName) {
  var tree = {};
  Object.keys(typeIndex[typeName] || {}).forEach(function(childTypeName) {
    tree[childTypeName] = getTypeHierarchy(typeIndex, childTypeName);
  });

  return tree;
}

function flattenTypeHierarchy(typeHierarchy, assertionsByType) {
  var result = [];
  Object.keys(typeHierarchy)
    .sort(function(a, b) {
      var aChildren = Object.keys(typeHierarchy[a]);
      var bChildren = Object.keys(typeHierarchy[b]);
      if (aChildren.length === 0 && bChildren.length > 0) {
        return -1;
      }
      if (aChildren.length > 0 && bChildren.length === 0) {
        return 1;
      }
      var aLength = assertionsByType[a] ? assertionsByType[a].length : 0;
      var bLength = assertionsByType[b] ? assertionsByType[b].length : 0;
      if (aLength > bLength) {
        return -1;
      }
      if (aLength < bLength) {
        return 1;
      }

      a = a.toLowerCase();
      b = b.toLowerCase();
      if (a < b) {
        return -1;
      }
      if (a > b) {
        return 1;
      }
      return 0;
    })
    .forEach(function(typeName) {
      result.push(typeName);
      Array.prototype.push.apply(
        result,
        flattenTypeHierarchy(typeHierarchy[typeName], assertionsByType)
      );
    });
  return result;
}

function addTypeToIndex(typeIndex, type) {
  if (type.baseType) {
    typeIndex[type.baseType.name] = typeIndex[type.baseType.name] || {};
    typeIndex[type.baseType.name][type.name] = type.name;
    addTypeToIndex(typeIndex, type.baseType);
  }
}

module.exports = async function generate(options) {
  if (options.require) {
    var moduleNames = options.require;
    if (!Array.isArray(moduleNames)) {
      moduleNames = [moduleNames];
    }
    moduleNames.forEach(function(moduleName) {
      if (/^[./]/.test(moduleName)) {
        moduleName = path.resolve(process.cwd(), moduleName);
      }
      require(moduleName);
    });
  }

  var expect = createExpect(options);

  function sortTypesByHierarchy(assertionsByType) {
    var typeIndex = {};
    var unknownTypes = [];
    Object.keys(assertionsByType).forEach(function(typeName) {
      var type = expect.getType(typeName);
      if (type) {
        addTypeToIndex(typeIndex, type);
      } else {
        unknownTypes.push(typeName);
      }
    });

    var typeHierarchy = { any: getTypeHierarchy(typeIndex, 'any') };

    var result = {};

    flattenTypeHierarchy(typeHierarchy, assertionsByType)
      .concat(unknownTypes)
      .forEach(function(typeName) {
        if (assertionsByType[typeName]) {
          result[typeName] = assertionsByType[typeName];
        }
      });

    return result;
  }

  var cwd = process.cwd();
  var assertionsPattern = options.assertions || [
    'assertions/*/*.md',
    'assertions.md'
  ];
  var output = options.output || 'site-build';
  var tmpOutput = `${output}-tmp`;

  const stats = await new Evaldown({
    commentMarker: 'unexpected-markdown',
    outputCapture: 'nowrap',
    outputFormat: 'inlined',
    sourcePath: path.join(cwd, 'documentation'),
    targetPath: path.join(cwd, tmpOutput),
    fileGlobals: {
      expect: options => createExpect(options.metadata)
    },
    update: !!options['update-examples']
  }).processFiles();

  console.log(`evaldown completed with ${JSON.stringify(stats)}`);

  await new Promise((resolve, reject) => {
    metalSmith('.')
      .destination(output)
      .source(tmpOutput)
      .use(
        require('metalsmith-collections')({
          assertions: {
            pattern: assertionsPattern
          },
          apiPages: {
            pattern: ['api/*.md', 'api.md']
          },
          pages: {
            pattern: ['*.md', '!assertions.md', '!api.md']
          }
        })
      )
      .use(
        require('./lib/include-static-assets')({
          path: path.resolve(__dirname, 'static')
        })
      )
      // Dynamicly generate metadata for assertion files
      .use(function(files, metalsmith, next) {
        Object.keys(files)
          .filter(function(file) {
            return /\.md$/.test(file);
          })
          .forEach(function(file) {
            const id = file.match(/([^/]+)\.md$/)[1];
            const name = idToName(id);

            if (files[file].collection.indexOf('apiPages') !== -1) {
              files[file].template = 'api.ejs';

              if (file === 'api.md') {
                files[file].title = 'API';
              }
            } else if (files[file].collection.indexOf('assertions') !== -1) {
              files[file].template = 'assertion.ejs';
              files[file].declarations = [];

              if (file === 'assertions.md') {
                files[file].title = 'Assertions';
              } else {
                const type = file.match(/^assertions\/([^/]+)/)[1];

                files[file].declarations = _.uniq(
                  (expect.assertions[name] || [])
                    .filter(function(assertionRule) {
                      return assertionRule.subject.type.name === type;
                    })
                    .map(function(assertionRule) {
                      return assertionRule.declaration.replace(
                        /<.*?>/,
                        '<' + assertionRule.subject.type.name + '>'
                      );
                    })
                );

                files[file].windowTitle = name + ' (' + type + ')';
                files[file].type = type;
              }
            }

            if (!files[file].title) {
              files[file].title = name;
            }

            if (!files[file].windowTitle) {
              files[file].windowTitle = files[file].title;
            }

            files[file].url =
              '/' + file.replace(/(\/?)index.md$/, '$1').replace(/\.md$/, '/');
          });
        next();
      })
      .use(function(files, metalsmith, next) {
        var metadata = metalsmith.metadata();

        metadata.collections.menuPages = metadata.collections.pages.filter(
          function(page) {
            return page.url !== '/' && page.menuPage !== false;
          }
        );

        metadata.collections.menuPages.forEach(function(page) {
          page.collection.push('menuPages');
        });

        metadata.collections.apiPages.sort(function(a, b) {
          var aTitle = a.title.toLowerCase();
          var bTitle = b.title.toLowerCase();
          if (aTitle < bTitle) {
            return -1;
          }
          if (aTitle > bTitle) {
            return 1;
          }
          return 0;
        });

        // Make sure that the most important types are listed first and in this order:
        var assertionsByType = {};
        metadata.collections.assertions.forEach(function(assertion) {
          if (assertion.type) {
            assertionsByType[assertion.type] =
              assertionsByType[assertion.type] || [];
            assertionsByType[assertion.type].push(assertion);
          }
        });

        assertionsByType = sortTypesByHierarchy(assertionsByType);
        Object.keys(assertionsByType).forEach(function(type) {
          assertionsByType[type].sort(function(a, b) {
            var aName = a.title.toLowerCase();
            var bName = b.title.toLowerCase();
            if (aName < bName) {
              return -1;
            }
            if (aName > bName) {
              return 1;
            }
            return 0;
          });
        });
        metadata.assertionsByType = assertionsByType;

        metadata.assertionsUrl = null;
        if (Object.keys(assertionsByType).length > 0) {
          metadata.assertionsUrl = metadata.collections.assertions.some(
            page => page.url === '/assertions/'
          )
            ? '/assertions/'
            : assertionsByType[Object.keys(assertionsByType)[0]][0].url;
        }

        metadata.apiPagesUrl = null;
        if (metadata.collections.apiPages.length > 0) {
          metadata.apiPagesUrl = metadata.collections.apiPages.some(
            page => page.url === '/api/'
          )
            ? '/api/'
            : metadata.collections.apiPages[0].url;
        }

        next();
      })
      .use(function(files, metalsmith, next) {
        var metadata = metalsmith.metadata();
        Object.keys(metadata.assertionsByType).forEach(function(type) {
          var declarations = [];
          metadata.assertionsByType[type].forEach(function(assertion) {
            Array.prototype.push.apply(declarations, assertion.declarations);
          });

          var path = 'assertions/' + type + '/';
          var file = 'assertions/' + type + '.html';
          files[file] = {
            windowTitle: type,
            title: type,
            declarations: _.uniq(declarations),
            template: 'type.ejs',
            url: path,
            contents: ''
          };
        });
        next();
      })
      .use(function(files, metalsmith, next) {
        var metadata = metalsmith.metadata();
        var indexData = [];

        metadata.collections.apiPages.forEach(function(assertion) {
          indexData.push({
            label: assertion.title + ' (api)',
            url: assertion.url
          });
        });

        metadata.collections.assertions.forEach(function(assertion) {
          indexData.push({
            label: assertion.windowTitle,
            url: assertion.url
          });
        });
        files['searchIndex.json'] = {
          contents: JSON.stringify(indexData, null, 2)
        };
        next();
      })
      .use(require('metalsmith-markdown')())
      // permalinks with no options will just make pretty urls...
      .use(require('metalsmith-permalinks')({ relative: false }))
      .use(function(files, metalsmith, next) {
        // Useful for debugging ;-)
        // require('uninspected').log(files);
        next();
      })
      .use(require('metalsmith-less')())
      .use(require('metalsmith-relative')())
      .use(
        require('metalsmith-templates')({
          engine: 'ejs',
          directory: path.resolve(__dirname, 'templates')
        })
      )
      .use(
        require('metalsmith-autoprefixer')({
          browsers: 'last 2 versions',
          cascade: false
        })
      )
      .use(require('./lib/delete-less-files')())
      .build(function(err) {
        if (err) {
          reject(err);
        } else {
          console.log('wrote site to ' + output);
          resolve();
        }
      });
  });

  await fsExtra.remove(tmpOutput);
};
<commit_msg>No longer switch into nowrap mode.<commit_after>/*global __dirname*/
var fsExtra = require('fs-extra');
var Evaldown = require('evaldown');
var metalSmith = require('metalsmith');
var path = require('path');
var _ = require('lodash');

var createExpect = require('./lib/createExpect');

function idToName(id) {
  return id.replace(/-/g, ' ');
}

function getTypeHierarchy(typeIndex, typeName) {
  var tree = {};
  Object.keys(typeIndex[typeName] || {}).forEach(function(childTypeName) {
    tree[childTypeName] = getTypeHierarchy(typeIndex, childTypeName);
  });

  return tree;
}

function flattenTypeHierarchy(typeHierarchy, assertionsByType) {
  var result = [];
  Object.keys(typeHierarchy)
    .sort(function(a, b) {
      var aChildren = Object.keys(typeHierarchy[a]);
      var bChildren = Object.keys(typeHierarchy[b]);
      if (aChildren.length === 0 && bChildren.length > 0) {
        return -1;
      }
      if (aChildren.length > 0 && bChildren.length === 0) {
        return 1;
      }
      var aLength = assertionsByType[a] ? assertionsByType[a].length : 0;
      var bLength = assertionsByType[b] ? assertionsByType[b].length : 0;
      if (aLength > bLength) {
        return -1;
      }
      if (aLength < bLength) {
        return 1;
      }

      a = a.toLowerCase();
      b = b.toLowerCase();
      if (a < b) {
        return -1;
      }
      if (a > b) {
        return 1;
      }
      return 0;
    })
    .forEach(function(typeName) {
      result.push(typeName);
      Array.prototype.push.apply(
        result,
        flattenTypeHierarchy(typeHierarchy[typeName], assertionsByType)
      );
    });
  return result;
}

function addTypeToIndex(typeIndex, type) {
  if (type.baseType) {
    typeIndex[type.baseType.name] = typeIndex[type.baseType.name] || {};
    typeIndex[type.baseType.name][type.name] = type.name;
    addTypeToIndex(typeIndex, type.baseType);
  }
}

module.exports = async function generate(options) {
  if (options.require) {
    var moduleNames = options.require;
    if (!Array.isArray(moduleNames)) {
      moduleNames = [moduleNames];
    }
    moduleNames.forEach(function(moduleName) {
      if (/^[./]/.test(moduleName)) {
        moduleName = path.resolve(process.cwd(), moduleName);
      }
      require(moduleName);
    });
  }

  var expect = createExpect(options);

  function sortTypesByHierarchy(assertionsByType) {
    var typeIndex = {};
    var unknownTypes = [];
    Object.keys(assertionsByType).forEach(function(typeName) {
      var type = expect.getType(typeName);
      if (type) {
        addTypeToIndex(typeIndex, type);
      } else {
        unknownTypes.push(typeName);
      }
    });

    var typeHierarchy = { any: getTypeHierarchy(typeIndex, 'any') };

    var result = {};

    flattenTypeHierarchy(typeHierarchy, assertionsByType)
      .concat(unknownTypes)
      .forEach(function(typeName) {
        if (assertionsByType[typeName]) {
          result[typeName] = assertionsByType[typeName];
        }
      });

    return result;
  }

  var cwd = process.cwd();
  var assertionsPattern = options.assertions || [
    'assertions/*/*.md',
    'assertions.md'
  ];
  var output = options.output || 'site-build';
  var tmpOutput = `${output}-tmp`;

  const stats = await new Evaldown({
    commentMarker: 'unexpected-markdown',
    outputFormat: 'inlined',
    sourcePath: path.join(cwd, 'documentation'),
    targetPath: path.join(cwd, tmpOutput),
    fileGlobals: {
      expect: options => createExpect(options.metadata)
    },
    update: !!options['update-examples']
  }).processFiles();

  console.log(`evaldown completed with ${JSON.stringify(stats)}`);

  await new Promise((resolve, reject) => {
    metalSmith('.')
      .destination(output)
      .source(tmpOutput)
      .use(
        require('metalsmith-collections')({
          assertions: {
            pattern: assertionsPattern
          },
          apiPages: {
            pattern: ['api/*.md', 'api.md']
          },
          pages: {
            pattern: ['*.md', '!assertions.md', '!api.md']
          }
        })
      )
      .use(
        require('./lib/include-static-assets')({
          path: path.resolve(__dirname, 'static')
        })
      )
      // Dynamicly generate metadata for assertion files
      .use(function(files, metalsmith, next) {
        Object.keys(files)
          .filter(function(file) {
            return /\.md$/.test(file);
          })
          .forEach(function(file) {
            const id = file.match(/([^/]+)\.md$/)[1];
            const name = idToName(id);

            if (files[file].collection.indexOf('apiPages') !== -1) {
              files[file].template = 'api.ejs';

              if (file === 'api.md') {
                files[file].title = 'API';
              }
            } else if (files[file].collection.indexOf('assertions') !== -1) {
              files[file].template = 'assertion.ejs';
              files[file].declarations = [];

              if (file === 'assertions.md') {
                files[file].title = 'Assertions';
              } else {
                const type = file.match(/^assertions\/([^/]+)/)[1];

                files[file].declarations = _.uniq(
                  (expect.assertions[name] || [])
                    .filter(function(assertionRule) {
                      return assertionRule.subject.type.name === type;
                    })
                    .map(function(assertionRule) {
                      return assertionRule.declaration.replace(
                        /<.*?>/,
                        '<' + assertionRule.subject.type.name + '>'
                      );
                    })
                );

                files[file].windowTitle = name + ' (' + type + ')';
                files[file].type = type;
              }
            }

            if (!files[file].title) {
              files[file].title = name;
            }

            if (!files[file].windowTitle) {
              files[file].windowTitle = files[file].title;
            }

            files[file].url =
              '/' + file.replace(/(\/?)index.md$/, '$1').replace(/\.md$/, '/');
          });
        next();
      })
      .use(function(files, metalsmith, next) {
        var metadata = metalsmith.metadata();

        metadata.collections.menuPages = metadata.collections.pages.filter(
          function(page) {
            return page.url !== '/' && page.menuPage !== false;
          }
        );

        metadata.collections.menuPages.forEach(function(page) {
          page.collection.push('menuPages');
        });

        metadata.collections.apiPages.sort(function(a, b) {
          var aTitle = a.title.toLowerCase();
          var bTitle = b.title.toLowerCase();
          if (aTitle < bTitle) {
            return -1;
          }
          if (aTitle > bTitle) {
            return 1;
          }
          return 0;
        });

        // Make sure that the most important types are listed first and in this order:
        var assertionsByType = {};
        metadata.collections.assertions.forEach(function(assertion) {
          if (assertion.type) {
            assertionsByType[assertion.type] =
              assertionsByType[assertion.type] || [];
            assertionsByType[assertion.type].push(assertion);
          }
        });

        assertionsByType = sortTypesByHierarchy(assertionsByType);
        Object.keys(assertionsByType).forEach(function(type) {
          assertionsByType[type].sort(function(a, b) {
            var aName = a.title.toLowerCase();
            var bName = b.title.toLowerCase();
            if (aName < bName) {
              return -1;
            }
            if (aName > bName) {
              return 1;
            }
            return 0;
          });
        });
        metadata.assertionsByType = assertionsByType;

        metadata.assertionsUrl = null;
        if (Object.keys(assertionsByType).length > 0) {
          metadata.assertionsUrl = metadata.collections.assertions.some(
            page => page.url === '/assertions/'
          )
            ? '/assertions/'
            : assertionsByType[Object.keys(assertionsByType)[0]][0].url;
        }

        metadata.apiPagesUrl = null;
        if (metadata.collections.apiPages.length > 0) {
          metadata.apiPagesUrl = metadata.collections.apiPages.some(
            page => page.url === '/api/'
          )
            ? '/api/'
            : metadata.collections.apiPages[0].url;
        }

        next();
      })
      .use(function(files, metalsmith, next) {
        var metadata = metalsmith.metadata();
        Object.keys(metadata.assertionsByType).forEach(function(type) {
          var declarations = [];
          metadata.assertionsByType[type].forEach(function(assertion) {
            Array.prototype.push.apply(declarations, assertion.declarations);
          });

          var path = 'assertions/' + type + '/';
          var file = 'assertions/' + type + '.html';
          files[file] = {
            windowTitle: type,
            title: type,
            declarations: _.uniq(declarations),
            template: 'type.ejs',
            url: path,
            contents: ''
          };
        });
        next();
      })
      .use(function(files, metalsmith, next) {
        var metadata = metalsmith.metadata();
        var indexData = [];

        metadata.collections.apiPages.forEach(function(assertion) {
          indexData.push({
            label: assertion.title + ' (api)',
            url: assertion.url
          });
        });

        metadata.collections.assertions.forEach(function(assertion) {
          indexData.push({
            label: assertion.windowTitle,
            url: assertion.url
          });
        });
        files['searchIndex.json'] = {
          contents: JSON.stringify(indexData, null, 2)
        };
        next();
      })
      .use(require('metalsmith-markdown')())
      // permalinks with no options will just make pretty urls...
      .use(require('metalsmith-permalinks')({ relative: false }))
      .use(function(files, metalsmith, next) {
        // Useful for debugging ;-)
        // require('uninspected').log(files);
        next();
      })
      .use(require('metalsmith-less')())
      .use(require('metalsmith-relative')())
      .use(
        require('metalsmith-templates')({
          engine: 'ejs',
          directory: path.resolve(__dirname, 'templates')
        })
      )
      .use(
        require('metalsmith-autoprefixer')({
          browsers: 'last 2 versions',
          cascade: false
        })
      )
      .use(require('./lib/delete-less-files')())
      .build(function(err) {
        if (err) {
          reject(err);
        } else {
          console.log('wrote site to ' + output);
          resolve();
        }
      });
  });

  await fsExtra.remove(tmpOutput);
};
<|endoftext|>


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

const MAX_TIMEOUT_VALUE = 2147483647;

module.exports = function(underlying, interval = 0, {
    leading = false,
    trailing = true,
    maxWait = null,
    waitForNextExecution = true,
    allowConcurrentExecutions = false,
    waitBetweenConsecutiveExecutions = false
}) {
    leading = !!leading;
    trailing = !!trailing;

    if (!leading && !trailing) {
        trailing = true;
    }

    waitForNextExecution = !!waitForNextExecution;
    allowConcurrentExecutions = !!allowConcurrentExecutions;
    waitBetweenConsecutiveExecutions = !!waitBetweenConsecutiveExecutions;

    if (allowConcurrentExecutions && waitBetweenConsecutiveExecutions) {
        allowConcurrentExecutions = false;
    }

    interval = _.clamp(interval, 0, MAX_TIMEOUT_VALUE);

    let applyMaxWait = _.isNil(maxWait);
    maxWait = _.clamp(maxWait, interval, MAX_TIMEOUT_VALUE);

    let currentlyExecuting = false;

    let callWaitBegin = null;
    let lastCall = null;

    let nextRunTimer = null;
    let nextRunIsImmediate = false;

    let currentPromise = null;

    let nextPromise = null;
    let nextResolver = null;
    let nextRejecter = null;

    function cancelWaitingRun() {
        if (nextRunTimer) {
            if (nextRunIsImmediate) {
                clearImmediate(nextRunTimer);
            }
            else {
                clearTimeout(nextRunTimer);
            }
        }

        nextRunTimer = null;
    }

    function scheduleRun(func, time) {
        cancelWaitingRun();

        time = _.clamp(time, 0, MAX_TIMEOUT_VALUE);

        if (time === 0) {
            nextRunTimer = setImmediate(func);
            nextRunIsImmediate = true;
        }
        else {
            nextRunTimer = setTimeout(func, time);
            nextRunIsImmediate = false;
        }
    }

    function setNextPromise() {
        nextPromise = new Promise(function(resolve, reject) {
            nextResolver = resolve;
            nextRejecter = reject;
        });
    }

    function scheduleNextRun() {
        if (callWaitBegin) {
            // calls are waiting, schedule a run
            let currentTime = Date.now();
            let nextRunWait = applyMaxWait ? Math.min(interval, callWaitBegin + maxWait - currentTime) : interval;
            scheduleRun(executeUnderlying, nextRunWait);
        }
    }

    function executeUnderlying() {
        let promise = nextPromise;
        let resolve = nextResolver;
        let reject = nextRejecter;

        return co(function*() {
            currentlyExecuting = true;
            callWaitBegin = null;
            currentPromise = promise;
            cancelWaitingRun();
            setNextPromise();

            try {
                let result = yield underlying();

                resolve(result);
            }
            catch (err) {
                reject(err);
            }

            let finishTime = Date.now();

            // clean up if appropriate
            if (currentPromise === promise) {
                currentlyExecuting = false;

                if (waitBetweenConsecutiveExecutions) {
                    // reset wait timers
                    if (callWaitBegin) {
                        callWaitBegin = finishTime;
                    }

                    lastCall = finishTime;
                }

                scheduleNextRun();
            }
        });
    }

    let debounced = function debouncer() {
        let currentTime = Date.now();
        let withinDebounceInterval = lastCall && lastCall + interval > currentTime;
        lastCall = currentTime;

        if (currentlyExecuting) {
            if (!waitForNextExecution) {
                // no need to schedule a run
                return currentPromise;
            }

            if (!allowConcurrentExecutions) {
                // don't attempt to schedule the next run while an execution is ongoing
                if (!callWaitBegin) {
                    callWaitBegin = currentTime;
                }
                return nextPromise;
            }
        }

        if (leading && !withinDebounceInterval) {
            // just run now
            executeUnderlying();
            return currentPromise;
        }

        if (trailing) {
            // schedule the next execution
            if (!callWaitBegin) {
                callWaitBegin = currentTime;
            }
        }

        scheduleNextRun();
        return nextPromise;
    }

    debounced.flush = function flush() {
        executeUnderlying();
    }

    debounced.cancel = function cancel() {
        nextRejecter(new Error('call canceled'));
        callWaitBegin = null;
        lastCall = null;
        cancelWaitingRun();
        setNextPromise();
    }

    setNextPromise();

    return debounced;
}
<commit_msg>Make overhauls to fix debounce code.<commit_after>const _ = require('lodash');
const co = require('co');

const MAX_TIMEOUT_VALUE = 2147483647;

module.exports = function(underlying, interval = 0, {
    leading = false,
    trailing = true,
    maxWait = null,
    delayBetweenExecutions = null,
    waitForNextExecution = true,
    allowConcurrentExecutions = false
}) {
    leading = !!leading;
    trailing = !!trailing;

    // function must either execute on leading side or on trailing side, not neither
    if (!leading && !trailing) {
        trailing = true;
    }

    waitForNextExecution = !!waitForNextExecution;

    // if function executes on leading side only, waiting for next execution makes no sense
    // same applies for trailing side only and previous execution
    if (!leading || !trailing) {
        waitForNextExecution = trailing;
    }

    allowConcurrentExecutions = !!allowConcurrentExecutions;

    interval = _.clamp(interval, 0, MAX_TIMEOUT_VALUE);

    let applyMaxWait = _.isNil(maxWait);
    maxWait = _.clamp(maxWait, interval, MAX_TIMEOUT_VALUE);

    let applyDelayBetweenExecutions = _.isNil(delayBetweenExecutions);
    delayBetweenExecutions = _.clamp(delayBetweenExecutions, 0, MAX_TIMEOUT_VALUE);

    // if a delay between executions is set, no consecutive executions can occur
    if (allowConcurrentExecutions && applyDelayBetweenExecutions) {
        allowConcurrentExecutions = false;
    }

    let currentlyExecuting = false;

    let callsWaiting = false;
    let firstWaitingCall = null;
    let lastProcessedCall = null;
    let lastCall = null;
    let lastCallArgs = null;
    let lastCallThis = null;
    let lastExecution = null;

    let nextRunTimer = null;
    let nextRunIsImmediate = false;

    let currentPromise = null;

    let nextPromise = null;
    let nextResolver = null;
    let nextRejecter = null;

    function cancelWaitingRun() {
        // properly cancel either immediate or timeout
        if (nextRunTimer) {
            if (nextRunIsImmediate) {
                clearImmediate(nextRunTimer);
            }
            else {
                clearTimeout(nextRunTimer);
            }
        }

        nextRunTimer = null;
    }

    function scheduleRun(func, time) {
        cancelWaitingRun();

        // clamp to acceptable timeout values
        time = _.clamp(time, 0, MAX_TIMEOUT_VALUE);

        // use either immediates or timeouts
        if (time === 0) {
            nextRunTimer = setImmediate(func);
            nextRunIsImmediate = true;
        }
        else {
            nextRunTimer = setTimeout(func, time);
            nextRunIsImmediate = false;
        }
    }

    function setNextPromise() {
        nextPromise = new Promise(function(resolve, reject) {
            // make sure to keep the resolver and rejecter
            nextResolver = resolve;
            nextRejecter = reject;
        });
    }

    function scheduleNextRun() {
        let currentTime = Date.now();

        if (callsWaiting) {
            // calls are waiting, schedule a run

            let times = [lastCall + interval];

            // apply max wait(s)
            if (applyMaxWait) {
                if (leading && lastProcessedCall) {
                    times.push(lastProcessedCall + maxWait);
                }

                if (trailing && firstWaitingCall) {
                    times.push(firstWaitingCall + maxWait);
                }
            }

            let nextTime = _.min(times);

            // apply delay between executions
            if (applyDelayBetweenExecutions && lastExecution) {
                let nextAllowedTime = lastExecution + delayBetweenExecutions;

                if (nextAllowedTime > nextTime) {
                    nextTime = nextAllowedTime;
                }
            }

            // schedule actual run
            let wait = nextTime - currentTime;
            scheduleRun(executeUnderlying, wait);
        }
    }

    function executeUnderlying() {
        let promise = nextPromise;
        let resolve = nextResolver;
        let reject = nextRejecter;

        let funcArgs = lastCallArgs;
        let funcThis = lastCallThis;

        return co(function*() {
            currentlyExecuting = true;
            callsWaiting = false;
            firstWaitingCall = null;
            lastProcessedCall = lastCall;
            currentPromise = promise;
            cancelWaitingRun();
            setNextPromise();

            try {
                let result = yield underlying.apply(funcThis, funcArgs);

                resolve(result);
            }
            catch (err) {
                reject(err);
            }

            let finishTime = Date.now();

            // clean up if appropriate
            if (currentPromise === promise) {
                currentlyExecuting = false;
                lastExecution = finishTime;

                // schedule any delayed calls
                if (callsWaiting) {
                    scheduleNextRun();
                }
            }
        });
    }

    let debounced = function debouncer() {
        let currentTime = Date.now();
        let withinDebounceInterval = lastCall && lastCall + interval > currentTime;
        lastCall = currentTime;
        lastCallArgs = arguments;
        lastCallThis = this;

        if (leading) {
            if (!withinDebounceInterval) {
                // just run now
                executeUnderlying();
                return currentPromise;
            }
            else {
                // even if not the leading call, max wait may apply forcing a run
                if (applyMaxWait) {
                    let waitTime = currentTime - lastProcessedCall;

                    if (waitTime >= maxWait) {
                        callsWaiting = true;
                    }
                }
            }
        }

        if (trailing) {
            // calls are always waiting on the trailing edge
            callsWaiting = true;

            if (!firstWaitingCall) {
                firstWaitingCall = currentTime;
            }
        }

        if (callsWaiting) {
            // don't schedule runs during an execution unless allowed to
            if (!currentlyExecuting || allowConcurrentExecutions) {
                scheduleNextRun();
            }
        }

        // provide proper promise
        return waitForNextExecution ? nextPromise : currentPromise;
    }

    debounced.flush = function flush() {
        executeUnderlying();
    }

    debounced.cancel = function cancel() {
        nextRejecter(new Error('call canceled'));
        callsWaiting = false;
        firstWaitingCall = null;
        lastCall = null;
        cancelWaitingRun();
        setNextPromise();
    }

    setNextPromise();

    return debounced;
}
<|endoftext|>


<commit_before>/**
 * Created by Ralph Varjabedian.
 * nodetastic is licensed under the [BSD-3 License] https://raw.githubusercontent.com/ralphv/nodetastic/master/LICENSE.
 * do not remove this notice.
 */

var fs = require("fs");

require("./SetupErrorCodes.js");
var config = require("./config.js");
var setOptions = require("./cmd_to_config");
module.exports = require("./lib/");
module.exports.setOptions = setOptions;
//set options via command lines or via setOptions

// setup crash log
process.on('uncaughtException', function(err) {
  console.log('Un-Caught exception:', err);
  var log = function(filename) {
    var details = "";
    try { details = JSON.stringify(err); } catch(e) {}
    fs.appendFileSync(filename, "uncaught exception: " + (new Date()).toString() + " " + err + " " + details + "\r\n");
  };
  try {
    log(config.crashLog);
  }
  catch(e) {
    if(e && e.code == 'EACCES') {
      try { log("./nodetastic-crash.log")} catch(e) {}
    }
  }
  process.exit(1);
});<commit_msg>add stack trace to crash log<commit_after>/**
 * Created by Ralph Varjabedian.
 * nodetastic is licensed under the [BSD-3 License] https://raw.githubusercontent.com/ralphv/nodetastic/master/LICENSE.
 * do not remove this notice.
 */

var fs = require("fs");

require("./SetupErrorCodes.js");
var config = require("./config.js");
var setOptions = require("./cmd_to_config");
module.exports = require("./lib/");
module.exports.setOptions = setOptions;
//set options via command lines or via setOptions

// setup crash log
process.on('uncaughtException', function(err) {
  console.log('Un-Caught exception:', err);
  var log = function(filename) {
    var details = "";
    try { details = JSON.stringify(err); } catch(e) {}
    fs.appendFileSync(filename, "uncaught exception: " + (new Date()).toString() + " " + err + " " + details + "\r\n" + "stack: " + err.stack);
  };
  try {
    log(config.crashLog);
  }
  catch(e) {
    if(e && e.code == 'EACCES') {
      try { log("./nodetastic-crash.log")} catch(e) {}
    }
  }
  process.exit(1);
});<|endoftext|>


<commit_before>var events = require('events');
var util = require('util');

var LRU = module.exports = function (max) {
    events.EventEmitter.call(this);
    this.cache = {}
    this.head = this.tail = null;
    this.length = 0;
    this.max = max || 1000;
};
util.inherits(LRU, events.EventEmitter);

LRU.prototype.remove = function (key) {
    var element = this.cache[key];

    if(element) {
        delete this.cache[key];

        --this.length;

        if(element.prev) this.cache[element.prev].next = element.next;
        if(element.next) this.cache[element.next].prev = element.prev;

        if(this.head == key) {
            this.head = element.prev;
        }

        if(this.tail == key) {
            this.tail = element.next;
        }
    }
    return element;
}

LRU.prototype.set = function (key, value) {
    if( this.cache.hasOwnProperty(key) ) {
        element = this.cache[key]
        element.value = value

        // If it's already the head, there's nothing more to do:
        if( key === this.head ) {
            return value;
        }
    } else {
        element = { value:value };

        this.cache[key] = element;

        // Eviction is only possible if the key didn't already exist:
        if (++this.length > this.max) {
            this.evict();
        }
    }

    element.next = null;
    element.prev = this.head;

    if (this.head) {
        this.cache[this.head].next = key;
    }
    this.head = key;

    if(!this.tail) {
      this.tail = key;
    }

    return value
};

LRU.prototype.get = function (key) {
    var element = this.cache[key];
    if (!element) { return; }

    if( this.length > 1 ) {
        // Tail only changes if this was the tail:
        if( key === this.tail ) this.tail = element.next

        if( this.head !== key ) {
            // Set prev -> next:
            if( element.prev ) this.cache[element.prev].next = element.next

            // Set prevhead->next:
            if( this.head ) this.cache[this.head].next = key
        }

        // Set next -> prev:
        if( element.next ) this.cache[element.next].prev = element.prev

        // Set new head:
        this.head = key
    }

    return element.value;
};

LRU.prototype.evict = function () {
    if(!this.tail) { return; }
    var key = this.tail;
    var element = this.remove(this.tail);
    this.emit('evict', {key:key, value:element.value});
};

<commit_msg>make new optional<commit_after>var events = require('events');
var util = require('util');

var LRU = module.exports = function (max) {
    if (!(this instanceof LRU)) return new LRU(max);
    events.EventEmitter.call(this);
    this.cache = {}
    this.head = this.tail = null;
    this.length = 0;
    this.max = max || 1000;
};
util.inherits(LRU, events.EventEmitter);

LRU.prototype.remove = function (key) {
    var element = this.cache[key];

    if(element) {
        delete this.cache[key];

        --this.length;

        if(element.prev) this.cache[element.prev].next = element.next;
        if(element.next) this.cache[element.next].prev = element.prev;

        if(this.head == key) {
            this.head = element.prev;
        }

        if(this.tail == key) {
            this.tail = element.next;
        }
    }
    return element;
}

LRU.prototype.set = function (key, value) {
    if( this.cache.hasOwnProperty(key) ) {
        element = this.cache[key]
        element.value = value

        // If it's already the head, there's nothing more to do:
        if( key === this.head ) {
            return value;
        }
    } else {
        element = { value:value };

        this.cache[key] = element;

        // Eviction is only possible if the key didn't already exist:
        if (++this.length > this.max) {
            this.evict();
        }
    }

    element.next = null;
    element.prev = this.head;

    if (this.head) {
        this.cache[this.head].next = key;
    }
    this.head = key;

    if(!this.tail) {
      this.tail = key;
    }

    return value
};

LRU.prototype.get = function (key) {
    var element = this.cache[key];
    if (!element) { return; }

    if( this.length > 1 ) {
        // Tail only changes if this was the tail:
        if( key === this.tail ) this.tail = element.next

        if( this.head !== key ) {
            // Set prev -> next:
            if( element.prev ) this.cache[element.prev].next = element.next

            // Set prevhead->next:
            if( this.head ) this.cache[this.head].next = key
        }

        // Set next -> prev:
        if( element.next ) this.cache[element.next].prev = element.prev

        // Set new head:
        this.head = key
    }

    return element.value;
};

LRU.prototype.evict = function () {
    if(!this.tail) { return; }
    var key = this.tail;
    var element = this.remove(this.tail);
    this.emit('evict', {key:key, value:element.value});
};

<|endoftext|>