<commit_before>// the tagRangeFinder function is
//   Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
// released under the MIT license (../../LICENSE) like the rest of CodeMirror
CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
  var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
  var nameChar = nameStartChar + "\-\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
  var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");

  var lineText = cm.getLine(line);
  var found = false;
  var tag = null;
  var pos = 0;
  while (!found) {
    pos = lineText.indexOf("<", pos);
    if (-1 == pos) // no tag on line
      return;
    if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
      pos++;
      continue;
    }
    // ok we weem to have a start tag
    if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
      pos++;
      continue;
    }
    var gtPos = lineText.indexOf(">", pos + 1);
    if (-1 == gtPos) { // end of start tag not in line
      var l = line + 1;
      var foundGt = false;
      var lastLine = cm.lineCount();
      while (l < lastLine && !foundGt) {
        var lt = cm.getLine(l);
        var gt = lt.indexOf(">");
        if (-1 != gt) { // found a >
          foundGt = true;
          var slash = lt.lastIndexOf("/", gt);
          if (-1 != slash && slash < gt) {
            var str = lineText.substr(slash, gt - slash + 1);
            if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
              if (hideEnd === true) l++;
              return l;
            }
          }
        }
        l++;
      }
      found = true;
    }
    else {
      var slashPos = lineText.lastIndexOf("/", gtPos);
      if (-1 == slashPos) { // cannot be empty tag
        found = true;
        // don't continue
      }
      else { // empty tag?
        // check if really empty tag
        var str = lineText.substr(slashPos, gtPos - slashPos + 1);
        if (!str.match( /\/\s*\>/ )) { // finally not empty
          found = true;
          // don't continue
        }
      }
    }
    if (found) {
      var subLine = lineText.substr(pos + 1);
      tag = subLine.match(xmlNAMERegExp);
      if (tag) {
        // we have an element name, wooohooo !
        tag = tag[0];
        // do we have the close tag on same line ???
        if (-1 != lineText.indexOf("</" + tag + ">", pos)) // yep
        {
          found = false;
        }
        // we don't, so we have a candidate...
      }
      else
        found = false;
    }
    if (!found)
      pos++;
  }

  if (found) {
    var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
    var startTagRegExp = new RegExp(startTag, "g");
    var endTag = "</" + tag + ">";
    var depth = 1;
    var l = line + 1;
    var lastLine = cm.lineCount();
    while (l < lastLine) {
      lineText = cm.getLine(l);
      var match = lineText.match(startTagRegExp);
      if (match) {
        for (var i = 0; i < match.length; i++) {
          if (match[i] == endTag)
            depth--;
          else
            depth++;
          if (!depth) {
            if (hideEnd === true) l++;
            return l;
          }
        }
      }
      l++;
    }
    return;
  }
};

CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
  var lineText = cm.getLine(line);
  var startChar = lineText.lastIndexOf("{");
  if (startChar < 0 || lineText.lastIndexOf("}") > startChar) return;
  var tokenType = cm.getTokenAt({line: line, ch: startChar}).className;
  var count = 1, lastLine = cm.lineCount(), end;
  outer: for (var i = line + 1; i < lastLine; ++i) {
    var text = cm.getLine(i), pos = 0;
    for (;;) {
      var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
      if (nextOpen < 0) nextOpen = text.length;
      if (nextClose < 0) nextClose = text.length;
      pos = Math.min(nextOpen, nextClose);
      if (pos == text.length) break;
      if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) {
        if (pos == nextOpen) ++count;
        else if (!--count) { end = i; break outer; }
      }
      ++pos;
    }
  }
  if (end == null || end == line + 1) return;
  if (hideEnd === true) end++;
  return end;
};

CodeMirror.indentRangeFinder = function(cm, line) {
  var tabSize = cm.getOption("tabSize");
  var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
  for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
    var handle = cm.getLineHandle(i);
    if (!/^\s*$/.test(handle.text)) {
      if (handle.indentation(tabSize) <= myIndent) break;
      last = i;
    }
  }
  if (!last) return null;
  return last + 1;
};

CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
  var folded = [];
  if (markText == null) markText = '
▼
%N%';

  function isFolded(cm, n) {
    for (var i = 0; i < folded.length; ++i) {
      var start = cm.lineInfo(folded[i].start);
      if (!start) folded.splice(i--, 1);
      else if (start.line == n) return {pos: i, region: folded[i]};
    }
  }

  function expand(cm, region) {
    cm.clearMarker(region.start);
    for (var i = 0; i < region.hidden.length; ++i)
      cm.showLine(region.hidden[i]);
  }

  return function(cm, line) {
    cm.operation(function() {
      var known = isFolded(cm, line);
      if (known) {
        folded.splice(known.pos, 1);
        expand(cm, known.region);
      } else {
        var end = rangeFinder(cm, line, hideEnd);
        if (end == null) return;
        var hidden = [];
        for (var i = line + 1; i < end; ++i) {
          var handle = cm.hideLine(i);
          if (handle) hidden.push(handle);
        }
        var first = cm.setMarker(line, markText);
        var region = {start: first, hidden: hidden};
        cm.onDeleteLine(first, function() { expand(cm, region); });
        folded.push(region);
      }
    });
  };
};
<commit_msg>Ignore string/comment tokens as fold points in braceFolder<commit_after>// the tagRangeFinder function is
//   Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
// released under the MIT license (../../LICENSE) like the rest of CodeMirror
CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
  var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
  var nameChar = nameStartChar + "\-\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
  var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");

  var lineText = cm.getLine(line);
  var found = false;
  var tag = null;
  var pos = 0;
  while (!found) {
    pos = lineText.indexOf("<", pos);
    if (-1 == pos) // no tag on line
      return;
    if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
      pos++;
      continue;
    }
    // ok we weem to have a start tag
    if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
      pos++;
      continue;
    }
    var gtPos = lineText.indexOf(">", pos + 1);
    if (-1 == gtPos) { // end of start tag not in line
      var l = line + 1;
      var foundGt = false;
      var lastLine = cm.lineCount();
      while (l < lastLine && !foundGt) {
        var lt = cm.getLine(l);
        var gt = lt.indexOf(">");
        if (-1 != gt) { // found a >
          foundGt = true;
          var slash = lt.lastIndexOf("/", gt);
          if (-1 != slash && slash < gt) {
            var str = lineText.substr(slash, gt - slash + 1);
            if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
              if (hideEnd === true) l++;
              return l;
            }
          }
        }
        l++;
      }
      found = true;
    }
    else {
      var slashPos = lineText.lastIndexOf("/", gtPos);
      if (-1 == slashPos) { // cannot be empty tag
        found = true;
        // don't continue
      }
      else { // empty tag?
        // check if really empty tag
        var str = lineText.substr(slashPos, gtPos - slashPos + 1);
        if (!str.match( /\/\s*\>/ )) { // finally not empty
          found = true;
          // don't continue
        }
      }
    }
    if (found) {
      var subLine = lineText.substr(pos + 1);
      tag = subLine.match(xmlNAMERegExp);
      if (tag) {
        // we have an element name, wooohooo !
        tag = tag[0];
        // do we have the close tag on same line ???
        if (-1 != lineText.indexOf("</" + tag + ">", pos)) // yep
        {
          found = false;
        }
        // we don't, so we have a candidate...
      }
      else
        found = false;
    }
    if (!found)
      pos++;
  }

  if (found) {
    var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
    var startTagRegExp = new RegExp(startTag, "g");
    var endTag = "</" + tag + ">";
    var depth = 1;
    var l = line + 1;
    var lastLine = cm.lineCount();
    while (l < lastLine) {
      lineText = cm.getLine(l);
      var match = lineText.match(startTagRegExp);
      if (match) {
        for (var i = 0; i < match.length; i++) {
          if (match[i] == endTag)
            depth--;
          else
            depth++;
          if (!depth) {
            if (hideEnd === true) l++;
            return l;
          }
        }
      }
      l++;
    }
    return;
  }
};

CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
  var lineText = cm.getLine(line), at = lineText.length, startChar, tokenType;
  for (;;) {
    var found = lineText.lastIndexOf("{", at);
    if (found < 0) break;
    tokenType = cm.getTokenAt({line: line, ch: found}).className;
    if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
    at = found - 1;
  }
  if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
  var count = 1, lastLine = cm.lineCount(), end;
  outer: for (var i = line + 1; i < lastLine; ++i) {
    var text = cm.getLine(i), pos = 0;
    for (;;) {
      var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
      if (nextOpen < 0) nextOpen = text.length;
      if (nextClose < 0) nextClose = text.length;
      pos = Math.min(nextOpen, nextClose);
      if (pos == text.length) break;
      if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) {
        if (pos == nextOpen) ++count;
        else if (!--count) { end = i; break outer; }
      }
      ++pos;
    }
  }
  if (end == null || end == line + 1) return;
  if (hideEnd === true) end++;
  return end;
};

CodeMirror.indentRangeFinder = function(cm, line) {
  var tabSize = cm.getOption("tabSize");
  var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
  for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
    var handle = cm.getLineHandle(i);
    if (!/^\s*$/.test(handle.text)) {
      if (handle.indentation(tabSize) <= myIndent) break;
      last = i;
    }
  }
  if (!last) return null;
  return last + 1;
};

CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
  var folded = [];
  if (markText == null) markText = '
▼
%N%';

  function isFolded(cm, n) {
    for (var i = 0; i < folded.length; ++i) {
      var start = cm.lineInfo(folded[i].start);
      if (!start) folded.splice(i--, 1);
      else if (start.line == n) return {pos: i, region: folded[i]};
    }
  }

  function expand(cm, region) {
    cm.clearMarker(region.start);
    for (var i = 0; i < region.hidden.length; ++i)
      cm.showLine(region.hidden[i]);
  }

  return function(cm, line) {
    cm.operation(function() {
      var known = isFolded(cm, line);
      if (known) {
        folded.splice(known.pos, 1);
        expand(cm, known.region);
      } else {
        var end = rangeFinder(cm, line, hideEnd);
        if (end == null) return;
        var hidden = [];
        for (var i = line + 1; i < end; ++i) {
          var handle = cm.hideLine(i);
          if (handle) hidden.push(handle);
        }
        var first = cm.setMarker(line, markText);
        var region = {start: first, hidden: hidden};
        cm.onDeleteLine(first, function() { expand(cm, region); });
        folded.push(region);
      }
    });
  };
};
<|endoftext|>


<commit_before>'use strict';

var random = require('./random'),
    combine = require('./combine');

function reduce(obj) {
  var mix = obj.allOf || obj.anyOf || obj.oneOf;

  if (!(mix && mix.length)) {
    return;
  }

  if ((obj.oneOf || obj.anyOf) && mix.length) {
    var offset = random(0, mix.length),
        length = 1;

    mix.splice(offset, length);
  }

  delete obj.allOf;
  delete obj.anyOf;
  delete obj.oneOf;

  var fixed = {};

  mix.forEach(function(value) {
    combine(fixed, value);
  });

  combine(obj, fixed);
}

function traverse(obj) {
  var primitives = require('./primitives');

  var copy = {};

  if (Array.isArray(obj)) {
    copy = [];
  }

  while (obj.allOf || obj.anyOf || obj.oneOf) {
    reduce(obj);
  }

  if (obj.enum) {
    return obj.enum[obj.enum.length > 1 ? random(0, obj.enum.length - 1) : 0];
  }

  if (obj.type) {
    if (Array.isArray(obj.type)) {
      obj.type = obj.type[random(0, obj.type.length - 1)];
    }

    if (!primitives[obj.type]) {
      throw new Error('Unknown primitive "' + obj.type + '"');
    }

    return primitives[obj.type](obj);
  }

  for (var key in obj) {
    var value = obj[key];

    if (typeof value === 'object') {
      copy[key] = traverse(value);
    } else {
      copy[key] = value;
    }
  }

  return copy;
}

module.exports = traverse;
<commit_msg>Do not modify type value; fix<commit_after>'use strict';

var random = require('./random'),
    combine = require('./combine');

function reduce(obj) {
  var mix = obj.allOf || obj.anyOf || obj.oneOf;

  if (!(mix && mix.length)) {
    return;
  }

  if ((obj.oneOf || obj.anyOf) && mix.length) {
    var offset = random(0, mix.length),
        length = 1;

    mix.splice(offset, length);
  }

  delete obj.allOf;
  delete obj.anyOf;
  delete obj.oneOf;

  var fixed = {};

  mix.forEach(function(value) {
    combine(fixed, value);
  });

  combine(obj, fixed);
}

function traverse(obj) {
  var primitives = require('./primitives');

  var copy = {};

  if (Array.isArray(obj)) {
    copy = [];
  }

  while (obj.allOf || obj.anyOf || obj.oneOf) {
    reduce(obj);
  }

  if (obj.enum) {
    return obj.enum[obj.enum.length > 1 ? random(0, obj.enum.length - 1) : 0];
  }

  if (obj.type) {
    var type = obj.type;

    if (Array.isArray(type)) {
      type = type[random(0, type.length - 1)];
    }

    if (!primitives[type]) {
      throw new Error('Unknown primitive "' + type + '"');
    }

    return primitives[type](obj);
  }

  for (var key in obj) {
    var value = obj[key];

    if (typeof value === 'object') {
      copy[key] = traverse(value);
    } else {
      copy[key] = value;
    }
  }

  return copy;
}

module.exports = traverse;
<|endoftext|>


<commit_before>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Registry = require('../registry');
var Lib = require('../lib');

var baseAttributes = require('../plots/attributes');
var baseLayoutAttributes = require('../plots/layout_attributes');
var frameAttributes = require('../plots/frame_attributes');
var animationAttributes = require('../plots/animation_attributes');

// polar attributes are not part of the Registry yet
var polarAreaAttrs = require('../plots/polar/area_attributes');
var polarAxisAttrs = require('../plots/polar/axis_attributes');

var extendFlat = Lib.extendFlat;
var extendDeep = Lib.extendDeep;

var IS_SUBPLOT_OBJ = '_isSubplotObj';
var IS_LINKED_TO_ARRAY = '_isLinkedToArray';
var DEPRECATED = '_deprecated';
var UNDERSCORE_ATTRS = [IS_SUBPLOT_OBJ, IS_LINKED_TO_ARRAY, DEPRECATED];

exports.IS_SUBPLOT_OBJ = '_isSubplotObj';
exports.IS_LINKED_TO_ARRAY = '_isLinkedToArray';
exports.DEPRECATED = DEPRECATED;
exports.UNDERSCORE_ATTRS = UNDERSCORE_ATTRS;

/** Outputs the full plotly.js plot schema
 *
 * @return {object}
 *  - defs
 *  - traces
 *  - layout
 *  - transforms
 *  - frames
 *  - animations
 *  - config (coming soon ...)
 */
exports.get = function() {
    var traces = {};

    Registry.allTypes.concat('area').forEach(function(type) {
        traces[type] = getTraceAttributes(type);
    });

    var transforms = {};

    Object.keys(Registry.transformsRegistry).forEach(function(type) {
        transforms[type] = getTransformAttributes(type);
    });

    return {
        defs: {
            valObjects: Lib.valObjects,
            metaKeys: UNDERSCORE_ATTRS.concat['description', 'role']
        },

        traces: traces,
        layout: getLayoutAttributes(),

        transforms: transforms,

        frames: formatAttributes(frameAttributes),
        animation: formatAttributes(animationAttributes)
    };
};

/**
 * Crawl the attribute tree, recursively calling a callback function
 *
 * @param {object} attrs
 *  The node of the attribute tree (e.g. the root) from which recursion originates
 * @param {Function} callback
 *  A callback function with the signature:
 *          @callback callback
 *          @param {object} attr an attribute
 *          @param {String} attrName name string
 *          @param {object[]} attrs all the attributes
 *          @param {Number} level the recursion level, 0 at the root
 * @param {Number} [specifiedLevel]
 *  The level in the tree, in order to let the callback function detect descend or backtrack,
 *  typically unsupplied (implied 0), just used by the self-recursive call.
 *  The necessity arises because the tree traversal is not controlled by callback return values.
 *  The decision to not use callback return values for controlling tree pruning arose from
 *  the goal of keeping the crawler backwards compatible. Observe that one of the pruning conditions
 *  precedes the callback call.
 *
 * @return {object} transformOut
 *  copy of transformIn that contains attribute defaults
 */
exports.crawl = function(attrs, callback, specifiedLevel) {
    var level = specifiedLevel || 0;

    Object.keys(attrs).forEach(function(attrName) {
        var attr = attrs[attrName];

        if(UNDERSCORE_ATTRS.indexOf(attrName) !== -1) return;

        callback(attr, attrName, attrs, level);

        if(exports.isValObject(attr)) return;

        if(Lib.isPlainObject(attr)) exports.crawl(attr, callback, level + 1);
    });
};

/** Is object a value object (or a container object)?
 *
 * @param {object} obj
 * @return {boolean}
 *  returns true for a valid value object and
 *  false for tree nodes in the attribute hierarchy
 */
exports.isValObject = function(obj) {
    return obj && obj.valType !== undefined;
};

/**
 * Find all data array attributes in a given trace object - including
 * `arrayOk` attributes.
 *
 * @param {object} trace
 *  full trace object that contains a reference to `_module.attributes`
 *
 * @return {array} arrayAttributes
 *  list of array attributes for the given trace
 */
exports.findArrayAttributes = function(trace) {
    var arrayAttributes = [],
        stack = [];

    function callback(attr, attrName, attrs, level) {
        stack = stack.slice(0, level).concat([attrName]);

        var splittableAttr = attr.valType === 'data_array' || attr.arrayOk === true;
        if(!splittableAttr) return;

        var astr = toAttrString(stack);
        var val = Lib.nestedProperty(trace, astr).get();
        if(!Array.isArray(val)) return;

        arrayAttributes.push(astr);
    }

    function toAttrString(stack) {
        return stack.join('.');
    }

    exports.crawl(trace._module.attributes, callback);

    if(trace.transforms) {
        var transforms = trace.transforms;

        for(var i = 0; i < transforms.length; i++) {
            var transform = transforms[i];

            stack = ['transforms[' + i + ']'];
            exports.crawl(transform._module.attributes, callback, 1);
        }
    }

    // Look into the fullInput module attributes for array attributes
    // to make sure that 'custom' array attributes are detected.
    //
    // At the moment, we need this block to make sure that
    // ohlc and candlestick 'open', 'high', 'low', 'close' can be
    // used with filter ang groupby transforms.
    if(trace._fullInput) {
        exports.crawl(trace._fullInput._module.attributes, callback);

        arrayAttributes = Lib.filterUnique(arrayAttributes);
    }

    return arrayAttributes;
};

function getTraceAttributes(type) {
    var _module, basePlotModule;

    if(type === 'area') {
        _module = { attributes: polarAreaAttrs };
        basePlotModule = {};
    }
    else {
        _module = Registry.modules[type]._module,
        basePlotModule = _module.basePlotModule;
    }

    var attributes = {};

    // make 'type' the first attribute in the object
    attributes.type = null;

    // base attributes (same for all trace types)
    extendDeep(attributes, baseAttributes);

    // module attributes
    extendDeep(attributes, _module.attributes);

    // subplot attributes
    if(basePlotModule.attributes) {
        extendDeep(attributes, basePlotModule.attributes);
    }

    // 'type' gets overwritten by baseAttributes; reset it here
    attributes.type = type;

    var out = {
        meta: _module.meta || {},
        attributes: formatAttributes(attributes),
    };

    // trace-specific layout attributes
    if(_module.layoutAttributes) {
        var layoutAttributes = {};

        extendDeep(layoutAttributes, _module.layoutAttributes);
        out.layoutAttributes = formatAttributes(layoutAttributes);
    }

    return out;
}

function getLayoutAttributes() {
    var layoutAttributes = {};

    // global layout attributes
    extendDeep(layoutAttributes, baseLayoutAttributes);

    // add base plot module layout attributes
    Object.keys(Registry.subplotsRegistry).forEach(function(k) {
        var _module = Registry.subplotsRegistry[k];

        if(!_module.layoutAttributes) return;

        if(_module.name === 'cartesian') {
            handleBasePlotModule(layoutAttributes, _module, 'xaxis');
            handleBasePlotModule(layoutAttributes, _module, 'yaxis');
        }
        else {
            var astr = _module.attr === 'subplot' ? _module.name : _module.attr;

            handleBasePlotModule(layoutAttributes, _module, astr);
        }
    });

    // polar layout attributes
    layoutAttributes = assignPolarLayoutAttrs(layoutAttributes);

    // add registered components layout attribute
    Object.keys(Registry.componentsRegistry).forEach(function(k) {
        var _module = Registry.componentsRegistry[k];

        if(!_module.layoutAttributes) return;

        if(Array.isArray(_module.layoutNodes)) {
            _module.layoutNodes.forEach(function(v) {
                handleRegisteredComponent(layoutAttributes, _module, v + _module.name);
            });
        }
        else {
            handleRegisteredComponent(layoutAttributes, _module, _module.name);
        }
    });

    return {
        layoutAttributes: formatAttributes(layoutAttributes)
    };
}

function getTransformAttributes(type) {
    var _module = Registry.transformsRegistry[type];

    return {
        attributes: formatAttributes(_module.attributes)
    };
}

function formatAttributes(attrs) {
    mergeValTypeAndRole(attrs);
    formatArrayContainers(attrs);

    return attrs;
}

function mergeValTypeAndRole(attrs) {

    function makeSrcAttr(attrName) {
        return {
            valType: 'string',
            role: 'info',
            description: [
                'Sets the source reference on plot.ly for ',
                attrName, '.'
            ].join(' ')
        };
    }

    function callback(attr, attrName, attrs) {
        if(exports.isValObject(attr)) {
            if(attr.valType === 'data_array') {
                // all 'data_array' attrs have role 'data'
                attr.role = 'data';
                // all 'data_array' attrs have a corresponding 'src' attr
                attrs[attrName + 'src'] = makeSrcAttr(attrName);
            }
            else if(attr.arrayOk === true) {
                // all 'arrayOk' attrs have a corresponding 'src' attr
                attrs[attrName + 'src'] = makeSrcAttr(attrName);
            }
        }
        else if(Lib.isPlainObject(attr)) {
            // all attrs container objects get role 'object'
            attr.role = 'object';
        }
    }

    exports.crawl(attrs, callback);
}

function formatArrayContainers(attrs) {

    function callback(attr, attrName, attrs) {
        if(!attr) return;

        var itemName = attr[IS_LINKED_TO_ARRAY];

        if(!itemName) return;

        delete attr[IS_LINKED_TO_ARRAY];

        attrs[attrName] = { items: {} };
        attrs[attrName].items[itemName] = attr;
        attrs[attrName].role = 'object';
    }

    exports.crawl(attrs, callback);
}

function assignPolarLayoutAttrs(layoutAttributes) {
    extendFlat(layoutAttributes, {
        radialaxis: polarAxisAttrs.radialaxis,
        angularaxis: polarAxisAttrs.angularaxis
    });

    extendFlat(layoutAttributes, polarAxisAttrs.layout);

    return layoutAttributes;
}

function handleBasePlotModule(layoutAttributes, _module, astr) {
    var np = Lib.nestedProperty(layoutAttributes, astr),
        attrs = extendDeep({}, _module.layoutAttributes);

    attrs[IS_SUBPLOT_OBJ] = true;
    np.set(attrs);
}

function handleRegisteredComponent(layoutAttributes, _module, astr) {
    var np = Lib.nestedProperty(layoutAttributes, astr),
        attrs = extendDeep(np.get() || {}, _module.layoutAttributes);

    np.set(attrs);
}
<commit_msg>lint (use variable instead of duplicating hard-coded strings)<commit_after>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Registry = require('../registry');
var Lib = require('../lib');

var baseAttributes = require('../plots/attributes');
var baseLayoutAttributes = require('../plots/layout_attributes');
var frameAttributes = require('../plots/frame_attributes');
var animationAttributes = require('../plots/animation_attributes');

// polar attributes are not part of the Registry yet
var polarAreaAttrs = require('../plots/polar/area_attributes');
var polarAxisAttrs = require('../plots/polar/axis_attributes');

var extendFlat = Lib.extendFlat;
var extendDeep = Lib.extendDeep;

var IS_SUBPLOT_OBJ = '_isSubplotObj';
var IS_LINKED_TO_ARRAY = '_isLinkedToArray';
var DEPRECATED = '_deprecated';
var UNDERSCORE_ATTRS = [IS_SUBPLOT_OBJ, IS_LINKED_TO_ARRAY, DEPRECATED];

exports.IS_SUBPLOT_OBJ = IS_SUBPLOT_OBJ;
exports.IS_LINKED_TO_ARRAY = IS_LINKED_TO_ARRAY;
exports.DEPRECATED = DEPRECATED;
exports.UNDERSCORE_ATTRS = UNDERSCORE_ATTRS;

/** Outputs the full plotly.js plot schema
 *
 * @return {object}
 *  - defs
 *  - traces
 *  - layout
 *  - transforms
 *  - frames
 *  - animations
 *  - config (coming soon ...)
 */
exports.get = function() {
    var traces = {};

    Registry.allTypes.concat('area').forEach(function(type) {
        traces[type] = getTraceAttributes(type);
    });

    var transforms = {};

    Object.keys(Registry.transformsRegistry).forEach(function(type) {
        transforms[type] = getTransformAttributes(type);
    });

    return {
        defs: {
            valObjects: Lib.valObjects,
            metaKeys: UNDERSCORE_ATTRS.concat['description', 'role']
        },

        traces: traces,
        layout: getLayoutAttributes(),

        transforms: transforms,

        frames: formatAttributes(frameAttributes),
        animation: formatAttributes(animationAttributes)
    };
};

/**
 * Crawl the attribute tree, recursively calling a callback function
 *
 * @param {object} attrs
 *  The node of the attribute tree (e.g. the root) from which recursion originates
 * @param {Function} callback
 *  A callback function with the signature:
 *          @callback callback
 *          @param {object} attr an attribute
 *          @param {String} attrName name string
 *          @param {object[]} attrs all the attributes
 *          @param {Number} level the recursion level, 0 at the root
 * @param {Number} [specifiedLevel]
 *  The level in the tree, in order to let the callback function detect descend or backtrack,
 *  typically unsupplied (implied 0), just used by the self-recursive call.
 *  The necessity arises because the tree traversal is not controlled by callback return values.
 *  The decision to not use callback return values for controlling tree pruning arose from
 *  the goal of keeping the crawler backwards compatible. Observe that one of the pruning conditions
 *  precedes the callback call.
 *
 * @return {object} transformOut
 *  copy of transformIn that contains attribute defaults
 */
exports.crawl = function(attrs, callback, specifiedLevel) {
    var level = specifiedLevel || 0;

    Object.keys(attrs).forEach(function(attrName) {
        var attr = attrs[attrName];

        if(UNDERSCORE_ATTRS.indexOf(attrName) !== -1) return;

        callback(attr, attrName, attrs, level);

        if(exports.isValObject(attr)) return;

        if(Lib.isPlainObject(attr)) exports.crawl(attr, callback, level + 1);
    });
};

/** Is object a value object (or a container object)?
 *
 * @param {object} obj
 * @return {boolean}
 *  returns true for a valid value object and
 *  false for tree nodes in the attribute hierarchy
 */
exports.isValObject = function(obj) {
    return obj && obj.valType !== undefined;
};

/**
 * Find all data array attributes in a given trace object - including
 * `arrayOk` attributes.
 *
 * @param {object} trace
 *  full trace object that contains a reference to `_module.attributes`
 *
 * @return {array} arrayAttributes
 *  list of array attributes for the given trace
 */
exports.findArrayAttributes = function(trace) {
    var arrayAttributes = [],
        stack = [];

    function callback(attr, attrName, attrs, level) {
        stack = stack.slice(0, level).concat([attrName]);

        var splittableAttr = attr.valType === 'data_array' || attr.arrayOk === true;
        if(!splittableAttr) return;

        var astr = toAttrString(stack);
        var val = Lib.nestedProperty(trace, astr).get();
        if(!Array.isArray(val)) return;

        arrayAttributes.push(astr);
    }

    function toAttrString(stack) {
        return stack.join('.');
    }

    exports.crawl(trace._module.attributes, callback);

    if(trace.transforms) {
        var transforms = trace.transforms;

        for(var i = 0; i < transforms.length; i++) {
            var transform = transforms[i];

            stack = ['transforms[' + i + ']'];
            exports.crawl(transform._module.attributes, callback, 1);
        }
    }

    // Look into the fullInput module attributes for array attributes
    // to make sure that 'custom' array attributes are detected.
    //
    // At the moment, we need this block to make sure that
    // ohlc and candlestick 'open', 'high', 'low', 'close' can be
    // used with filter ang groupby transforms.
    if(trace._fullInput) {
        exports.crawl(trace._fullInput._module.attributes, callback);

        arrayAttributes = Lib.filterUnique(arrayAttributes);
    }

    return arrayAttributes;
};

function getTraceAttributes(type) {
    var _module, basePlotModule;

    if(type === 'area') {
        _module = { attributes: polarAreaAttrs };
        basePlotModule = {};
    }
    else {
        _module = Registry.modules[type]._module,
        basePlotModule = _module.basePlotModule;
    }

    var attributes = {};

    // make 'type' the first attribute in the object
    attributes.type = null;

    // base attributes (same for all trace types)
    extendDeep(attributes, baseAttributes);

    // module attributes
    extendDeep(attributes, _module.attributes);

    // subplot attributes
    if(basePlotModule.attributes) {
        extendDeep(attributes, basePlotModule.attributes);
    }

    // 'type' gets overwritten by baseAttributes; reset it here
    attributes.type = type;

    var out = {
        meta: _module.meta || {},
        attributes: formatAttributes(attributes),
    };

    // trace-specific layout attributes
    if(_module.layoutAttributes) {
        var layoutAttributes = {};

        extendDeep(layoutAttributes, _module.layoutAttributes);
        out.layoutAttributes = formatAttributes(layoutAttributes);
    }

    return out;
}

function getLayoutAttributes() {
    var layoutAttributes = {};

    // global layout attributes
    extendDeep(layoutAttributes, baseLayoutAttributes);

    // add base plot module layout attributes
    Object.keys(Registry.subplotsRegistry).forEach(function(k) {
        var _module = Registry.subplotsRegistry[k];

        if(!_module.layoutAttributes) return;

        if(_module.name === 'cartesian') {
            handleBasePlotModule(layoutAttributes, _module, 'xaxis');
            handleBasePlotModule(layoutAttributes, _module, 'yaxis');
        }
        else {
            var astr = _module.attr === 'subplot' ? _module.name : _module.attr;

            handleBasePlotModule(layoutAttributes, _module, astr);
        }
    });

    // polar layout attributes
    layoutAttributes = assignPolarLayoutAttrs(layoutAttributes);

    // add registered components layout attribute
    Object.keys(Registry.componentsRegistry).forEach(function(k) {
        var _module = Registry.componentsRegistry[k];

        if(!_module.layoutAttributes) return;

        if(Array.isArray(_module.layoutNodes)) {
            _module.layoutNodes.forEach(function(v) {
                handleRegisteredComponent(layoutAttributes, _module, v + _module.name);
            });
        }
        else {
            handleRegisteredComponent(layoutAttributes, _module, _module.name);
        }
    });

    return {
        layoutAttributes: formatAttributes(layoutAttributes)
    };
}

function getTransformAttributes(type) {
    var _module = Registry.transformsRegistry[type];

    return {
        attributes: formatAttributes(_module.attributes)
    };
}

function formatAttributes(attrs) {
    mergeValTypeAndRole(attrs);
    formatArrayContainers(attrs);

    return attrs;
}

function mergeValTypeAndRole(attrs) {

    function makeSrcAttr(attrName) {
        return {
            valType: 'string',
            role: 'info',
            description: [
                'Sets the source reference on plot.ly for ',
                attrName, '.'
            ].join(' ')
        };
    }

    function callback(attr, attrName, attrs) {
        if(exports.isValObject(attr)) {
            if(attr.valType === 'data_array') {
                // all 'data_array' attrs have role 'data'
                attr.role = 'data';
                // all 'data_array' attrs have a corresponding 'src' attr
                attrs[attrName + 'src'] = makeSrcAttr(attrName);
            }
            else if(attr.arrayOk === true) {
                // all 'arrayOk' attrs have a corresponding 'src' attr
                attrs[attrName + 'src'] = makeSrcAttr(attrName);
            }
        }
        else if(Lib.isPlainObject(attr)) {
            // all attrs container objects get role 'object'
            attr.role = 'object';
        }
    }

    exports.crawl(attrs, callback);
}

function formatArrayContainers(attrs) {

    function callback(attr, attrName, attrs) {
        if(!attr) return;

        var itemName = attr[IS_LINKED_TO_ARRAY];

        if(!itemName) return;

        delete attr[IS_LINKED_TO_ARRAY];

        attrs[attrName] = { items: {} };
        attrs[attrName].items[itemName] = attr;
        attrs[attrName].role = 'object';
    }

    exports.crawl(attrs, callback);
}

function assignPolarLayoutAttrs(layoutAttributes) {
    extendFlat(layoutAttributes, {
        radialaxis: polarAxisAttrs.radialaxis,
        angularaxis: polarAxisAttrs.angularaxis
    });

    extendFlat(layoutAttributes, polarAxisAttrs.layout);

    return layoutAttributes;
}

function handleBasePlotModule(layoutAttributes, _module, astr) {
    var np = Lib.nestedProperty(layoutAttributes, astr),
        attrs = extendDeep({}, _module.layoutAttributes);

    attrs[IS_SUBPLOT_OBJ] = true;
    np.set(attrs);
}

function handleRegisteredComponent(layoutAttributes, _module, astr) {
    var np = Lib.nestedProperty(layoutAttributes, astr),
        attrs = extendDeep(np.get() || {}, _module.layoutAttributes);

    np.set(attrs);
}
<|endoftext|>


<commit_before>'use strict'

function log (message) {
  console.log(message)
}

function exit (code) {
  process.exit(code)
}

function success (message) {
  log(message)
  exit(0)
}

function failure (message) {
  log(message)
  exit(1)
}

function message (message, code) {
  log(message)
  exit(code)
}

module.exports = { message, success, failure }
<commit_msg>Add a logger.<commit_after>'use strict'

function log (message) {
  console.log(message)
}

function exit (code) {
  return process.exit(code)
}

function success (message) {
  log(message)
  return exit(0)
}

function failure (message) {
  log(message)
  return exit(1)
}

function message (message, code = 0) {
  log(message)
  return exit(code)
}

module.exports = { message, success, failure }
<|endoftext|>


<commit_before>/**
 * @for p5
 * @requires core
 */

'use strict';

var p5 = require('./core');
var doFriendlyWelcome = false; // TEMP until we get it all working LM

// -- Borrowed from jQuery 1.11.3 --
var class2type = {};
var toString = class2type.toString;
var names = ['Boolean', 'Number', 'String', 'Function',
             'Array', 'Date', 'RegExp', 'Object', 'Error'];
for (var n=0; n<names.length; n++) {
  class2type[ '[object ' + names[n] + ']' ] = names[n].toLowerCase();
}
var getType = function( obj ) {
  if ( obj == null ) {
    return obj + '';
  }
  return typeof obj === 'object' || typeof obj === 'function' ?
    class2type[ toString.call(obj) ] || 'object' :
    typeof obj;
};
var isArray = Array.isArray || function( obj ) {
  return getType(obj) === 'array';
};
var isNumeric =function( obj ) {
  // parseFloat NaNs numeric-cast false positives (null|true|false|"")
  // ...but misinterprets leading-number strings, particularly hex literals
  // subtraction forces infinities to NaN
  // adding 1 corrects loss of precision from parseFloat (#15100)
  return !isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
};
// -- End borrow --

/**
 * Checks the definition type against the argument type
 * If any of these passes (in order), it matches:
 *
 * - p5.* definitions are checked with instanceof
 * - Booleans are let through (everything is truthy or falsey)
 * - Lowercase of the definition is checked against the js type
 * - Number types are checked to see if they are numerically castable
 */
var numberTypes = ['Number', 'Integer', 'Number/Constant'];
function typeMatches(defType, argType, arg) {
  if(defType.match(/^p5\./)) {
    var parts = defType.split('.');
    return arg instanceof p5[parts[1]];
  }
  return defType === 'Boolean' || // Anything is truthy, cover in Debug Guide
    (defType.toLowerCase() === argType) ||
    (numberTypes.indexOf(defType) > -1 && isNumeric(arg));
}

/**
 * Prints out a fancy, colorful message to the console log
 *
 * @param  {String}               message the words to be said
 * @param  {String}               func    the name of the function to link
 * @param  {Integer/Color String} color   CSS color string or error type
 *
 * @return console logs
 */
// Wrong number of params, undefined param, wrong type
var PARAM_COUNT = 0;
var EMPTY_VAR = 1;
var WRONG_TYPE = 2;
var FILE_LOAD = 3;
// p5.js blue, p5.js orange, auto dark green; fallback p5.js darkened magenta
// See testColors below for all the color codes and names
var typeColors = ['#2D7BB6', '#EE9900', '#4DB200', '#C83C00'];
function report(message, func, color) {
  if(doFriendlyWelcome){
    friendlyWelcome();
    doFriendlyWelcome =false;
  }
  if ('undefined' === getType(color)) {
    color   = '#B40033'; // dark magenta
  } else if (getType(color) === 'number') { // Type to color
    color = typeColors[color];
  }
  // LM TEMP commenting this out until we get the whole system working
  // if (func.substring(0,4) === 'load'){
  //   console.log(
  //     '%c> p5.js says: '+message+'%c'+
  //     '[https://github.com/processing/p5.js/wiki/Local-server]',
  //     'background-color:' + color + ';color:#FFF;',
  //     'background-color:transparent;color:' + color +';',
  //     'background-color:' + color + ';color:#FFF;',
  //     'background-color:transparent;color:' + color +';'
  //   );
  // }
  // else{
  //   console.log(
  //     '%c> p5.js says: '+message+'%c [http://p5js.org/reference/#p5/'+func+
  //     ']', 'background-color:' + color + ';color:#FFF;',
  //     'background-color:transparent;color:' + color +';'
  //   );
  // }
}

/**
 * Validate all the parameters of a function for number and type
 * NOTE THIS FUNCTION IS TEMPORARILY DISABLED UNTIL FURTHER WORK
 * AND UPDATES ARE IMPLEMENTED. -LMCCART
 *
 * @param  {String} func  name of function we're checking
 * @param  {Array}  args  pass of the JS default arguments array
 * @param  {Array}  types List of types accepted ['Number', 'String, ...] OR
 *                        a list of lists for each format: [
 *                          ['String', 'Number', 'Number'],
 *                          ['String', 'Number', 'Number', 'Number', 'Number'
 *                        ]
 *
 * @return console logs
 */
p5.prototype._validateParameters = function(func, args, types) {
  if (!isArray(types[0])) {
    types = [types];
  }
  // Check number of parameters
  // Example: "You wrote ellipse(X,X,X). ellipse was expecting 4
  //          parameters. Try ellipse(X,X,X,X)."
  var diff = Math.abs(args.length-types[0].length);
  var message, tindex = 0;
  for (var i=1, len=types.length; i<len; i++) {
    var d = Math.abs(args.length-types[i].length);
    if (d <= diff) {
      tindex = i;
      diff = d;
    }
  }
  var symbol = 'X'; // Parameter placeholder
  if(diff > 0) {
    message = 'You wrote ' + func + '(';
    // Concat an appropriate number of placeholders for call
    if (args.length > 0) {
      message += symbol + Array(args.length).join(',' + symbol);
    }
    message += '). ' + func + ' was expecting ' + types[tindex].length +
      ' parameters. Try ' + func + '(';
    // Concat an appropriate number of placeholders for definition
    if (types[tindex].length > 0) {
      message += symbol + Array(types[tindex].length).join(',' + symbol);
    }
    message += ').';
    // If multiple definitions
    if (types.length > 1) {
      message += ' ' + func + ' takes different numbers of parameters ' +
        'depending on what you want to do. Click this link to learn more: ';
    }
    report(message, func, PARAM_COUNT);
  }
  // Type checking
  // Example: "It looks like ellipse received an empty variable in spot #2."
  // Example: "ellipse was expecting a number for parameter #1,
  //           received "foo" instead."
  for (var format=0; format<types.length; format++) {
    for (var p=0; p < types[format].length && p < args.length; p++) {
      var defType = types[format][p];
      var argType = getType(args[p]);
      if ('undefined' === argType || null === argType) {
        report('It looks like ' + func +
          ' received an empty variable in spot #' + (p+1) +
          '. If not intentional, this is often a problem with scope: ' +
          '[link to scope].', func, EMPTY_VAR);
      } else if (defType !== '*' && !typeMatches(defType, argType, args[p])) {
        message = func + ' was expecting a ' + defType.toLowerCase() +
          ' for parameter #' + (p+1) + ', received ';
        // Wrap strings in quotes
        message += 'string' === argType ? '"' + args[p] + '"' : args[p];
        message += ' instead.';
        // If multiple definitions
        if (types.length > 1) {
          message += ' ' + func + ' takes different numbers of parameters ' +
            'depending on what you want to do. ' +
            'Click this link to learn more:';
        }
        report(message, func, WRONG_TYPE);
      }
    }
  }
};
/*
 * NOTE THIS FUNCTION IS TEMPORARILY DISABLED UNTIL FURTHER WORK
 * AND UPDATES ARE IMPLEMENTED. -LMCCART
 */
p5.prototype._validateParameters = function() {
  return true;
};

var errorCases = {
  '0': {
    fileType: 'image',
    method: 'loadImage',
    message: ' hosting the image online,'
  },
  '1': {
    fileType: 'XML file',
    method: 'loadXML'
  },
  '2': {
    fileType: 'table file',
    method: 'loadTable'
  },
  '3': {
    fileType: 'text file',
    method: 'loadStrings'
  },
  '4': {
    fileType: 'font',
    method: 'loadFont',
    message: ' hosting the font online,'
  },
};
p5._friendlyFileLoadError = function (errorType, filePath) {
  var errorInfo = errorCases[ errorType ];
  var message = 'It looks like there was a problem' +
  ' loading your ' + errorInfo.fileType + '.' +
  ' Try checking if the file path%c [' + filePath + '] %cis correct,' +
  (errorInfo.message || '') + ' or running a local server.';
  report(message, errorInfo.method, FILE_LOAD);
};

function friendlyWelcome() {
  // p5.js brand - magenta: #ED225D
  var astrixBgColor = 'transparent';
  var astrixTxtColor = '#ED225D';
  var welcomeBgColor = '#ED225D';
  var welcomeTextColor = 'white';
  console.log(
  '%c    _ \n'+
  ' /\\| |/\\ \n'+
  ' \\ ` \' /  \n'+
  ' / , . \\  \n'+
  ' \\/|_|\\/ '+
  '\n\n%c> p5.js says: Welcome! '+
  'This is your friendly debugger. ' +
  'To turn me off switch to using “p5.min.js”.',
  'background-color:'+astrixBgColor+';color:' + astrixTxtColor +';',
  'background-color:'+welcomeBgColor+';color:' + welcomeTextColor +';'
  );
}

/**
 * Prints out all the colors in the color pallete with white text.
 * For color blindness testing.
 */
/* function testColors() {
  var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer';
  report(str, 'print', '#ED225D'); // p5.js magenta
  report(str, 'print', '#2D7BB6'); // p5.js blue
  report(str, 'print', '#EE9900'); // p5.js orange
  report(str, 'print', '#A67F59'); // p5.js light brown
  report(str, 'print', '#704F21'); // p5.js gold
  report(str, 'print', '#1CC581'); // auto cyan
  report(str, 'print', '#FF6625'); // auto orange
  report(str, 'print', '#79EB22'); // auto green
  report(str, 'print', '#B40033'); // p5.js darkened magenta
  report(str, 'print', '#084B7F'); // p5.js darkened blue
  report(str, 'print', '#945F00'); // p5.js darkened orange
  report(str, 'print', '#6B441D'); // p5.js darkened brown
  report(str, 'print', '#2E1B00'); // p5.js darkened gold
  report(str, 'print', '#008851'); // auto dark cyan
  report(str, 'print', '#C83C00'); // auto dark orange
  report(str, 'print', '#4DB200'); // auto dark green
} */

// This is a lazily-defined list of p5 symbols that may be
// misused by beginners at top-level code, outside of setup/draw. We'd like
// to detect these errors and help the user by suggesting they move them
// into setup/draw.
//
// For more details, see https://github.com/processing/p5.js/issues/1121.
var misusedAtTopLevelCode = null;
var FAQ_URL = 'https://github.com/processing/p5.js/wiki/' +
              'Frequently-Asked-Questions' +
              '#why-cant-i-assign-variables-using-p5-functions-and-' +
              'variables-before-setup';

function defineMisusedAtTopLevelCode() {
  var uniqueNamesFound = {};

  var getSymbols = function(obj) {
    return Object.getOwnPropertyNames(obj).filter(function(name) {
      if (name[0] === '_') {
        return false;
      }
      if (name in uniqueNamesFound) {
        return false;
      }

      uniqueNamesFound[name] = true;

      return true;
    }).map(function(name) {
      var type;

      if (typeof(obj[name]) === 'function') {
        type = 'function';
      } else if (name === name.toUpperCase()) {
        type = 'constant';
      } else {
        type = 'variable';
      }

      return {name: name, type: type};
    });
  };

  misusedAtTopLevelCode = [].concat(
    getSymbols(p5.prototype),
    // At present, p5 only adds its constants to p5.prototype during
    // construction, which may not have happened at the time a
    // ReferenceError is thrown, so we'll manually add them to our list.
    getSymbols(require('./constants'))
  );

  // This will ultimately ensure that we report the most specific error
  // possible to the user, e.g. advising them about HALF_PI instead of PI
  // when their code misuses the former.
  misusedAtTopLevelCode.sort(function(a, b) {
    return b.name.length - a.name.length;
  });
}

function helpForMisusedAtTopLevelCode(e, log) {
  if (!log) {
    log = console.log.bind(console);
  }

  if (!misusedAtTopLevelCode) {
    defineMisusedAtTopLevelCode();
  }

  // If we find that we're logging lots of false positives, we can
  // uncomment the following code to avoid displaying anything if the
  // user's code isn't likely to be using p5's global mode. (Note that
  // setup/draw are more likely to be defined due to JS function hoisting.)
  //
  //if (!('setup' in window || 'draw' in window)) {
  //  return;
  //}

  misusedAtTopLevelCode.some(function(symbol) {
    // Note that while just checking for the occurrence of the
    // symbol name in the error message could result in false positives,
    // a more rigorous test is difficult because different browsers
    // log different messages, and the format of those messages may
    // change over time.
    //
    // For example, if the user uses 'PI' in their code, it may result
    // in any one of the following messages:
    //
    //   * 'PI' is undefined                           (Microsoft Edge)
    //   * ReferenceError: PI is undefined             (Firefox)
    //   * Uncaught ReferenceError: PI is not defined  (Chrome)

    if (e.message && e.message.indexOf(symbol.name) !== -1) {
      log('%cDid you just try to use p5.js\'s ' + symbol.name +
          (symbol.type === 'function' ? '() ' : ' ') + symbol.type +
          '? If so, you may want to ' +
          'move it into your sketch\'s setup() function.\n\n' +
          'For more details, see: ' + FAQ_URL,
          'color: #B40033' /* Dark magenta */);
      return true;
    }
  });
}

// Exposing this primarily for unit testing.
p5.prototype._helpForMisusedAtTopLevelCode = helpForMisusedAtTopLevelCode;

if (document.readyState !== 'complete') {
  window.addEventListener('error', helpForMisusedAtTopLevelCode, false);

  // Our job is only to catch ReferenceErrors that are thrown when
  // global (non-instance mode) p5 APIs are used at the top-level
  // scope of a file, so we'll unbind our error listener now to make
  // sure we don't log false positives later.
  window.addEventListener('load', function() {
    window.removeEventListener('error', helpForMisusedAtTopLevelCode, false);
  });
}

module.exports = p5;
<commit_msg>fixing over friendly error closes #1633<commit_after>/**
 * @for p5
 * @requires core
 */

'use strict';

var p5 = require('./core');
var doFriendlyWelcome = false; // TEMP until we get it all working LM

// -- Borrowed from jQuery 1.11.3 --
var class2type = {};
var toString = class2type.toString;
var names = ['Boolean', 'Number', 'String', 'Function',
             'Array', 'Date', 'RegExp', 'Object', 'Error'];
for (var n=0; n<names.length; n++) {
  class2type[ '[object ' + names[n] + ']' ] = names[n].toLowerCase();
}
var getType = function( obj ) {
  if ( obj == null ) {
    return obj + '';
  }
  return typeof obj === 'object' || typeof obj === 'function' ?
    class2type[ toString.call(obj) ] || 'object' :
    typeof obj;
};
var isArray = Array.isArray || function( obj ) {
  return getType(obj) === 'array';
};
var isNumeric =function( obj ) {
  // parseFloat NaNs numeric-cast false positives (null|true|false|"")
  // ...but misinterprets leading-number strings, particularly hex literals
  // subtraction forces infinities to NaN
  // adding 1 corrects loss of precision from parseFloat (#15100)
  return !isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
};
// -- End borrow --

/**
 * Checks the definition type against the argument type
 * If any of these passes (in order), it matches:
 *
 * - p5.* definitions are checked with instanceof
 * - Booleans are let through (everything is truthy or falsey)
 * - Lowercase of the definition is checked against the js type
 * - Number types are checked to see if they are numerically castable
 */
var numberTypes = ['Number', 'Integer', 'Number/Constant'];
function typeMatches(defType, argType, arg) {
  if(defType.match(/^p5\./)) {
    var parts = defType.split('.');
    return arg instanceof p5[parts[1]];
  }
  return defType === 'Boolean' || // Anything is truthy, cover in Debug Guide
    (defType.toLowerCase() === argType) ||
    (numberTypes.indexOf(defType) > -1 && isNumeric(arg));
}

/**
 * Prints out a fancy, colorful message to the console log
 *
 * @param  {String}               message the words to be said
 * @param  {String}               func    the name of the function to link
 * @param  {Integer/Color String} color   CSS color string or error type
 *
 * @return console logs
 */
// Wrong number of params, undefined param, wrong type
var PARAM_COUNT = 0;
var EMPTY_VAR = 1;
var WRONG_TYPE = 2;
var FILE_LOAD = 3;
// p5.js blue, p5.js orange, auto dark green; fallback p5.js darkened magenta
// See testColors below for all the color codes and names
var typeColors = ['#2D7BB6', '#EE9900', '#4DB200', '#C83C00'];
function report(message, func, color) {
  if(doFriendlyWelcome){
    friendlyWelcome();
    doFriendlyWelcome =false;
  }
  if ('undefined' === getType(color)) {
    color   = '#B40033'; // dark magenta
  } else if (getType(color) === 'number') { // Type to color
    color = typeColors[color];
  }
  // LM TEMP commenting this out until we get the whole system working
  // if (func.substring(0,4) === 'load'){
  //   console.log(
  //     '%c> p5.js says: '+message+'%c'+
  //     '[https://github.com/processing/p5.js/wiki/Local-server]',
  //     'background-color:' + color + ';color:#FFF;',
  //     'background-color:transparent;color:' + color +';',
  //     'background-color:' + color + ';color:#FFF;',
  //     'background-color:transparent;color:' + color +';'
  //   );
  // }
  // else{
  //   console.log(
  //     '%c> p5.js says: '+message+'%c [http://p5js.org/reference/#p5/'+func+
  //     ']', 'background-color:' + color + ';color:#FFF;',
  //     'background-color:transparent;color:' + color +';'
  //   );
  // }
}

/**
 * Validate all the parameters of a function for number and type
 * NOTE THIS FUNCTION IS TEMPORARILY DISABLED UNTIL FURTHER WORK
 * AND UPDATES ARE IMPLEMENTED. -LMCCART
 *
 * @param  {String} func  name of function we're checking
 * @param  {Array}  args  pass of the JS default arguments array
 * @param  {Array}  types List of types accepted ['Number', 'String, ...] OR
 *                        a list of lists for each format: [
 *                          ['String', 'Number', 'Number'],
 *                          ['String', 'Number', 'Number', 'Number', 'Number'
 *                        ]
 *
 * @return console logs
 */
p5.prototype._validateParameters = function(func, args, types) {
  if (!isArray(types[0])) {
    types = [types];
  }
  // Check number of parameters
  // Example: "You wrote ellipse(X,X,X). ellipse was expecting 4
  //          parameters. Try ellipse(X,X,X,X)."
  var diff = Math.abs(args.length-types[0].length);
  var message, tindex = 0;
  for (var i=1, len=types.length; i<len; i++) {
    var d = Math.abs(args.length-types[i].length);
    if (d <= diff) {
      tindex = i;
      diff = d;
    }
  }
  var symbol = 'X'; // Parameter placeholder
  if(diff > 0) {
    message = 'You wrote ' + func + '(';
    // Concat an appropriate number of placeholders for call
    if (args.length > 0) {
      message += symbol + Array(args.length).join(',' + symbol);
    }
    message += '). ' + func + ' was expecting ' + types[tindex].length +
      ' parameters. Try ' + func + '(';
    // Concat an appropriate number of placeholders for definition
    if (types[tindex].length > 0) {
      message += symbol + Array(types[tindex].length).join(',' + symbol);
    }
    message += ').';
    // If multiple definitions
    if (types.length > 1) {
      message += ' ' + func + ' takes different numbers of parameters ' +
        'depending on what you want to do. Click this link to learn more: ';
    }
    report(message, func, PARAM_COUNT);
  }
  // Type checking
  // Example: "It looks like ellipse received an empty variable in spot #2."
  // Example: "ellipse was expecting a number for parameter #1,
  //           received "foo" instead."
  for (var format=0; format<types.length; format++) {
    for (var p=0; p < types[format].length && p < args.length; p++) {
      var defType = types[format][p];
      var argType = getType(args[p]);
      if ('undefined' === argType || null === argType) {
        report('It looks like ' + func +
          ' received an empty variable in spot #' + (p+1) +
          '. If not intentional, this is often a problem with scope: ' +
          '[link to scope].', func, EMPTY_VAR);
      } else if (defType !== '*' && !typeMatches(defType, argType, args[p])) {
        message = func + ' was expecting a ' + defType.toLowerCase() +
          ' for parameter #' + (p+1) + ', received ';
        // Wrap strings in quotes
        message += 'string' === argType ? '"' + args[p] + '"' : args[p];
        message += ' instead.';
        // If multiple definitions
        if (types.length > 1) {
          message += ' ' + func + ' takes different numbers of parameters ' +
            'depending on what you want to do. ' +
            'Click this link to learn more:';
        }
        report(message, func, WRONG_TYPE);
      }
    }
  }
};
/*
 * NOTE THIS FUNCTION IS TEMPORARILY DISABLED UNTIL FURTHER WORK
 * AND UPDATES ARE IMPLEMENTED. -LMCCART
 */
p5.prototype._validateParameters = function() {
  return true;
};

var errorCases = {
  '0': {
    fileType: 'image',
    method: 'loadImage',
    message: ' hosting the image online,'
  },
  '1': {
    fileType: 'XML file',
    method: 'loadXML'
  },
  '2': {
    fileType: 'table file',
    method: 'loadTable'
  },
  '3': {
    fileType: 'text file',
    method: 'loadStrings'
  },
  '4': {
    fileType: 'font',
    method: 'loadFont',
    message: ' hosting the font online,'
  },
};
p5._friendlyFileLoadError = function (errorType, filePath) {
  var errorInfo = errorCases[ errorType ];
  var message = 'It looks like there was a problem' +
  ' loading your ' + errorInfo.fileType + '.' +
  ' Try checking if the file path%c [' + filePath + '] %cis correct,' +
  (errorInfo.message || '') + ' or running a local server.';
  report(message, errorInfo.method, FILE_LOAD);
};

function friendlyWelcome() {
  // p5.js brand - magenta: #ED225D
  var astrixBgColor = 'transparent';
  var astrixTxtColor = '#ED225D';
  var welcomeBgColor = '#ED225D';
  var welcomeTextColor = 'white';
  console.log(
  '%c    _ \n'+
  ' /\\| |/\\ \n'+
  ' \\ ` \' /  \n'+
  ' / , . \\  \n'+
  ' \\/|_|\\/ '+
  '\n\n%c> p5.js says: Welcome! '+
  'This is your friendly debugger. ' +
  'To turn me off switch to using “p5.min.js”.',
  'background-color:'+astrixBgColor+';color:' + astrixTxtColor +';',
  'background-color:'+welcomeBgColor+';color:' + welcomeTextColor +';'
  );
}

/**
 * Prints out all the colors in the color pallete with white text.
 * For color blindness testing.
 */
/* function testColors() {
  var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer';
  report(str, 'print', '#ED225D'); // p5.js magenta
  report(str, 'print', '#2D7BB6'); // p5.js blue
  report(str, 'print', '#EE9900'); // p5.js orange
  report(str, 'print', '#A67F59'); // p5.js light brown
  report(str, 'print', '#704F21'); // p5.js gold
  report(str, 'print', '#1CC581'); // auto cyan
  report(str, 'print', '#FF6625'); // auto orange
  report(str, 'print', '#79EB22'); // auto green
  report(str, 'print', '#B40033'); // p5.js darkened magenta
  report(str, 'print', '#084B7F'); // p5.js darkened blue
  report(str, 'print', '#945F00'); // p5.js darkened orange
  report(str, 'print', '#6B441D'); // p5.js darkened brown
  report(str, 'print', '#2E1B00'); // p5.js darkened gold
  report(str, 'print', '#008851'); // auto dark cyan
  report(str, 'print', '#C83C00'); // auto dark orange
  report(str, 'print', '#4DB200'); // auto dark green
} */

// This is a lazily-defined list of p5 symbols that may be
// misused by beginners at top-level code, outside of setup/draw. We'd like
// to detect these errors and help the user by suggesting they move them
// into setup/draw.
//
// For more details, see https://github.com/processing/p5.js/issues/1121.
var misusedAtTopLevelCode = null;
var FAQ_URL = 'https://github.com/processing/p5.js/wiki/' +
              'Frequently-Asked-Questions' +
              '#why-cant-i-assign-variables-using-p5-functions-and-' +
              'variables-before-setup';

function defineMisusedAtTopLevelCode() {
  var uniqueNamesFound = {};

  var getSymbols = function(obj) {
    return Object.getOwnPropertyNames(obj).filter(function(name) {
      if (name[0] === '_') {
        return false;
      }
      if (name in uniqueNamesFound) {
        return false;
      }

      uniqueNamesFound[name] = true;

      return true;
    }).map(function(name) {
      var type;

      if (typeof(obj[name]) === 'function') {
        type = 'function';
      } else if (name === name.toUpperCase()) {
        type = 'constant';
      } else {
        type = 'variable';
      }

      return {name: name, type: type};
    });
  };

  misusedAtTopLevelCode = [].concat(
    getSymbols(p5.prototype),
    // At present, p5 only adds its constants to p5.prototype during
    // construction, which may not have happened at the time a
    // ReferenceError is thrown, so we'll manually add them to our list.
    getSymbols(require('./constants'))
  );

  // This will ultimately ensure that we report the most specific error
  // possible to the user, e.g. advising them about HALF_PI instead of PI
  // when their code misuses the former.
  misusedAtTopLevelCode.sort(function(a, b) {
    return b.name.length - a.name.length;
  });
}

function helpForMisusedAtTopLevelCode(e, log) {
  if (!log) {
    log = console.log.bind(console);
  }

  if (!misusedAtTopLevelCode) {
    defineMisusedAtTopLevelCode();
  }

  // If we find that we're logging lots of false positives, we can
  // uncomment the following code to avoid displaying anything if the
  // user's code isn't likely to be using p5's global mode. (Note that
  // setup/draw are more likely to be defined due to JS function hoisting.)
  //
  //if (!('setup' in window || 'draw' in window)) {
  //  return;
  //}

  misusedAtTopLevelCode.some(function(symbol) {
    // Note that while just checking for the occurrence of the
    // symbol name in the error message could result in false positives,
    // a more rigorous test is difficult because different browsers
    // log different messages, and the format of those messages may
    // change over time.
    //
    // For example, if the user uses 'PI' in their code, it may result
    // in any one of the following messages:
    //
    //   * 'PI' is undefined                           (Microsoft Edge)
    //   * ReferenceError: PI is undefined             (Firefox)
    //   * Uncaught ReferenceError: PI is not defined  (Chrome)

    if (e.message && e.message.match('\\W?'+symbol.name+'\\W') !== null) {
      log('%cDid you just try to use p5.js\'s ' + symbol.name +
          (symbol.type === 'function' ? '() ' : ' ') + symbol.type +
          '? If so, you may want to ' +
          'move it into your sketch\'s setup() function.\n\n' +
          'For more details, see: ' + FAQ_URL,
          'color: #B40033' /* Dark magenta */);
      return true;
    }
  });
}

// Exposing this primarily for unit testing.
p5.prototype._helpForMisusedAtTopLevelCode = helpForMisusedAtTopLevelCode;

if (document.readyState !== 'complete') {
  window.addEventListener('error', helpForMisusedAtTopLevelCode, false);

  // Our job is only to catch ReferenceErrors that are thrown when
  // global (non-instance mode) p5 APIs are used at the top-level
  // scope of a file, so we'll unbind our error listener now to make
  // sure we don't log false positives later.
  window.addEventListener('load', function() {
    window.removeEventListener('error', helpForMisusedAtTopLevelCode, false);
  });
}

module.exports = p5;
<|endoftext|>


<commit_before>/* @flow weak */
require(`node-cjsx`).transform()
import detect from 'detect-port'
import Hapi from 'hapi'
import Boom from 'boom'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import webpack from 'webpack'
import Negotiator from 'negotiator'
import parsePath from 'parse-filepath'
import _ from 'lodash'
import webpackRequire from 'webpack-require'
import opn from 'opn'
import fs from 'fs'
import glob from 'glob'
import rl from 'readline'
import GraphQL from 'hapi-graphql'
import WebpackDevServer from 'webpack-dev-server'
import { pagesDB } from './globals'

import bootstrap from '../bootstrap'

const rlInterface = rl.createInterface({
  input: process.stdin,
  output: process.stdout,
})

import webpackConfig from './webpack.config'
const debug = require(`debug`)(`gatsby:application`)

function startServer (program) {
  const directory = program.directory

  // Load pages for the site.
  return bootstrap(program, (err, schema) => {
    // Generate random port for webpack to listen on.
    // Perhaps should check if port is open.
    const webpackPort = Math.round(Math.random() * 1000 + 1000)
    const compilerConfig = webpackConfig(program, directory, `develop`, webpackPort)

    const compiler = webpack(compilerConfig.resolve())

    let HTMLPath = `${directory}/html`
    // Check if we can't find an html component in root of site.
    if (glob.sync(`${HTMLPath}.*`).length === 0) {
      HTMLPath = `../isomorphic/html`
    }

    // We use the program port not the webpack-dev-server port as if you import
    // files in your html.js they won't be available through the webpack-dev-server.
    // By using the program port, requesting these imported files might accidentally work
    // as the imported files will be available in /public. TODO test how expensive
    // it'd be to do an actual static compile of the html.js on startup to avoid
    // this discprenecy between dev and prod.
    const htmlCompilerConfig = webpackConfig(program, directory, `develop-html`, program.port)

    webpackRequire(htmlCompilerConfig.resolve(), require.resolve(HTMLPath), (error, factory) => {
      if (error) {
        console.log(`Failed to require ${directory}/html.js`)
        error.forEach((e) => {
          console.log(e)
        })
        process.exit()
      }
      const HTML = factory()
      debug(`Configuring develop server`)

      const webpackDevServer = new WebpackDevServer(compiler, {
        hot: true,
        quiet: false,
        noInfo: true,
        host: program.host,
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
        stats: {
          colors: true,
        },
      })

      // Start webpack-dev-server
      webpackDevServer.listen(webpackPort, program.host)

      const server = new Hapi.Server()

      server.connection({
        host: program.host,
        port: program.port,
      })

      // As our two processes (Webpack-Dev-Server + this Hapi.js server) are
      // running on different ports, we proxy requests for the bundle.js to
      // Webpack.
      server.route({
        method: 'GET',
        path: '/commons.js',
        handler: {
          proxy: {
            uri: `http://0.0.0.0:${webpackPort}/commons.js`,
            passThrough: true,
            xforward: true,
          },
        },
      })

      server.route({
        method: `GET`,
        path: `/html/{path*}`,
        handler: (request, reply) => {
          if (request.path === `favicon.ico`) {
            return reply(Boom.notFound())
          }

          try {
            const htmlElement = React.createElement(
              HTML, {
                body: ``,
                scripts: [`commons`],
                headComponents: [],
              }
            )
            let html = ReactDOMServer.renderToStaticMarkup(htmlElement)
            html = `<!DOCTYPE html>\n${html}`
            return reply(html)
          } catch (e) {
            console.log(e.stack)
            throw e
          }
        },
      })

      server.route({
        method: `GET`,
        path: `/{path*}`,
        handler: {
          directory: {
            path: `${program.directory}/public`,
            listing: false,
            index: false,
          },
        },
      })

      server.ext(`onRequest`, (request, reply) => {
        if (request.path === `/graphql`) {
          return reply.continue()
        }

        const negotiator = new Negotiator(request.raw.req)

        // Try to map the url path to match an actual path of a file on disk.
        //const parsed = parsePath(request.path)
        //const page = pagesDB().get(parsed.dirname)

        //let absolutePath = `${program.directory}/pages`
        //let path
        //if (page) {
          //path = `/${parsePath(page.component).dirname}/${parsed.basename}`
          //absolutePath += `/${parsePath(page.component).dirname}/${parsed.basename}`
        //} else {
          //path = request.path
          //absolutePath += request.path
        //}
        //let isFile = false
        //try {
          //isFile = fs.lstatSync(absolutePath).isFile()
        //} catch (e) {
          //// Ignore.
        //}

        // If the path matches a file, return that.
        //if (isFile) {
          //request.setUrl(path)
          //reply.continue()
        // Let people load the bundle.js directly.
        //} else if (request.path === `/bundle.js`) {
        if (request.path === `/bundle.js`) {
          reply.continue()
        } else if (negotiator.mediaType() === `text/html`) {
          request.setUrl(`/html${request.path}`)
          reply.continue()
        } else {
          reply.continue()
        }
      })

      return server.register([
        // Add GraphQL support
        {
          register: GraphQL,
          options: {
            query: {
              graphiql: true,
              pretty: true,
              schema,
            },
            route: {
              path: `/graphql`,
            },
          },
        },
      ], (er) => {
        if (er) {
          console.log(er)
          process.exit()
        }

        server.start((e) => {
          if (e) {
            if (e.code === `EADDRINUSE`) {
              // eslint-disable-next-line max-len
              console.log(`Unable to start Gatsby on port ${program.port} as there's already a process listing on that port.`)
            } else {
              console.log(e)
            }

            process.exit()
          } else {
            if (program.open) {
              opn(server.info.uri)
            }
            console.log(`Listening at:`, server.info.uri)
          }
        })
      })
    })
  })
}

module.exports = (program) => {
  // TODO boot checker — gatsby.config.js/html.js/local install

  // Detect if a process is already listening on the program port.
  // If it is, ask the user if they'd like to use a different port.
  detect(program.port, (err, _port) => {
    if (err) {
      console.error(err)
      process.exit()
    }

    if (program.port !== _port) {
      // eslint-disable-next-line max-len
      const question = `Something is already running at port ${program.port} \nWould you like to run the app at another port instead? [Y/n] `

      return rlInterface.question(question, (answer) => {
        if (answer.length === 0 || answer.match(/^yes|y$/i)) {
          program.port = _port // eslint-disable-line no-param-reassign
        }

        return startServer(program)
      })
    }

    return startServer(program)
  })
}
<commit_msg>Parse the port to a number if needed, further fixing #524 (#526)<commit_after>/* @flow weak */
require(`node-cjsx`).transform()
import detect from 'detect-port'
import Hapi from 'hapi'
import Boom from 'boom'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import webpack from 'webpack'
import Negotiator from 'negotiator'
import parsePath from 'parse-filepath'
import _ from 'lodash'
import webpackRequire from 'webpack-require'
import opn from 'opn'
import fs from 'fs'
import glob from 'glob'
import rl from 'readline'
import GraphQL from 'hapi-graphql'
import WebpackDevServer from 'webpack-dev-server'
import { pagesDB } from './globals'

import bootstrap from '../bootstrap'

const rlInterface = rl.createInterface({
  input: process.stdin,
  output: process.stdout,
})

import webpackConfig from './webpack.config'
const debug = require(`debug`)(`gatsby:application`)

function startServer (program) {
  const directory = program.directory

  // Load pages for the site.
  return bootstrap(program, (err, schema) => {
    // Generate random port for webpack to listen on.
    // Perhaps should check if port is open.
    const webpackPort = Math.round(Math.random() * 1000 + 1000)
    const compilerConfig = webpackConfig(program, directory, `develop`, webpackPort)

    const compiler = webpack(compilerConfig.resolve())

    let HTMLPath = `${directory}/html`
    // Check if we can't find an html component in root of site.
    if (glob.sync(`${HTMLPath}.*`).length === 0) {
      HTMLPath = `../isomorphic/html`
    }

    // We use the program port not the webpack-dev-server port as if you import
    // files in your html.js they won't be available through the webpack-dev-server.
    // By using the program port, requesting these imported files might accidentally work
    // as the imported files will be available in /public. TODO test how expensive
    // it'd be to do an actual static compile of the html.js on startup to avoid
    // this discprenecy between dev and prod.
    const htmlCompilerConfig = webpackConfig(program, directory, `develop-html`, program.port)

    webpackRequire(htmlCompilerConfig.resolve(), require.resolve(HTMLPath), (error, factory) => {
      if (error) {
        console.log(`Failed to require ${directory}/html.js`)
        error.forEach((e) => {
          console.log(e)
        })
        process.exit()
      }
      const HTML = factory()
      debug(`Configuring develop server`)

      const webpackDevServer = new WebpackDevServer(compiler, {
        hot: true,
        quiet: false,
        noInfo: true,
        host: program.host,
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
        stats: {
          colors: true,
        },
      })

      // Start webpack-dev-server
      webpackDevServer.listen(webpackPort, program.host)

      const server = new Hapi.Server()

      server.connection({
        host: program.host,
        port: program.port,
      })

      // As our two processes (Webpack-Dev-Server + this Hapi.js server) are
      // running on different ports, we proxy requests for the bundle.js to
      // Webpack.
      server.route({
        method: 'GET',
        path: '/commons.js',
        handler: {
          proxy: {
            uri: `http://0.0.0.0:${webpackPort}/commons.js`,
            passThrough: true,
            xforward: true,
          },
        },
      })

      server.route({
        method: `GET`,
        path: `/html/{path*}`,
        handler: (request, reply) => {
          if (request.path === `favicon.ico`) {
            return reply(Boom.notFound())
          }

          try {
            const htmlElement = React.createElement(
              HTML, {
                body: ``,
                scripts: [`commons`],
                headComponents: [],
              }
            )
            let html = ReactDOMServer.renderToStaticMarkup(htmlElement)
            html = `<!DOCTYPE html>\n${html}`
            return reply(html)
          } catch (e) {
            console.log(e.stack)
            throw e
          }
        },
      })

      server.route({
        method: `GET`,
        path: `/{path*}`,
        handler: {
          directory: {
            path: `${program.directory}/public`,
            listing: false,
            index: false,
          },
        },
      })

      server.ext(`onRequest`, (request, reply) => {
        if (request.path === `/graphql`) {
          return reply.continue()
        }

        const negotiator = new Negotiator(request.raw.req)

        // Try to map the url path to match an actual path of a file on disk.
        //const parsed = parsePath(request.path)
        //const page = pagesDB().get(parsed.dirname)

        //let absolutePath = `${program.directory}/pages`
        //let path
        //if (page) {
          //path = `/${parsePath(page.component).dirname}/${parsed.basename}`
          //absolutePath += `/${parsePath(page.component).dirname}/${parsed.basename}`
        //} else {
          //path = request.path
          //absolutePath += request.path
        //}
        //let isFile = false
        //try {
          //isFile = fs.lstatSync(absolutePath).isFile()
        //} catch (e) {
          //// Ignore.
        //}

        // If the path matches a file, return that.
        //if (isFile) {
          //request.setUrl(path)
          //reply.continue()
        // Let people load the bundle.js directly.
        //} else if (request.path === `/bundle.js`) {
        if (request.path === `/bundle.js`) {
          reply.continue()
        } else if (negotiator.mediaType() === `text/html`) {
          request.setUrl(`/html${request.path}`)
          reply.continue()
        } else {
          reply.continue()
        }
      })

      return server.register([
        // Add GraphQL support
        {
          register: GraphQL,
          options: {
            query: {
              graphiql: true,
              pretty: true,
              schema,
            },
            route: {
              path: `/graphql`,
            },
          },
        },
      ], (er) => {
        if (er) {
          console.log(er)
          process.exit()
        }

        server.start((e) => {
          if (e) {
            if (e.code === `EADDRINUSE`) {
              // eslint-disable-next-line max-len
              console.log(`Unable to start Gatsby on port ${program.port} as there's already a process listing on that port.`)
            } else {
              console.log(e)
            }

            process.exit()
          } else {
            if (program.open) {
              opn(server.info.uri)
            }
            console.log(`Listening at:`, server.info.uri)
          }
        })
      })
    })
  })
}

module.exports = (program) => {
  const port = typeof program.port === 'string'
    ? parseInt(program.port, 10)
    : program.port

  detect(port, (err, _port) => {
    if (err) {
      console.error(err)
      process.exit()
    }

    if (port !== _port) {
      // eslint-disable-next-line max-len
      const question = `Something is already running at port ${port} \nWould you like to run the app at another port instead? [Y/n] `

      return rlInterface.question(question, (answer) => {
        if (answer.length === 0 || answer.match(/^yes|y$/i)) {
          program.port = _port // eslint-disable-line no-param-reassign
        }

        return startServer(program)
      })
    }

    return startServer(program)
  })
}
<|endoftext|>