<commit_before>import type NodePath from "./index";
import * as t from "../../types";

/**
 * Resolve a "pointer" `NodePath` to it's absolute path.
 */

export function resolve(dangerous, resolved) {
  return this._resolve(dangerous, resolved) || this;
}

export function _resolve(dangerous?, resolved?): ?NodePath {
  // detect infinite recursion
  // todo: possibly have a max length on this just to be safe
  if (resolved && resolved.indexOf(this) >= 0) return;

  // we store all the paths we've "resolved" in this array to prevent infinite recursion
  resolved = resolved || [];
  resolved.push(this);

  if (this.isVariableDeclarator()) {
    if (this.get("id").isIdentifier()) {
      return this.get("init").resolve(dangerous, resolved);
    } else {
      // otherwise it's a request for a pattern and that's a bit more tricky
    }
  } else if (this.isReferencedIdentifier()) {
    var binding = this.scope.getBinding(this.node.name);
    if (!binding) return;

    // reassigned so we can't really resolve it
    if (!binding.constant) return;

    // todo - lookup module in dependency graph
    if (binding.kind === "module") return;

    if (binding.path !== this) {
      return binding.path.resolve(dangerous, resolved);
    }
  } else if (dangerous && this.isMemberExpression()) {
    // this is dangerous, as non-direct target assignments will mutate it's state
    // making this resolution inaccurate

    var targetKey = this.toComputedKey();
    if (!t.isLiteral(targetKey)) return;

    var targetName = targetKey.value;

    var target = this.get("object").resolve(dangerous, resolved);

    if (target.isObjectExpression()) {
      var props = target.get("properties");
      for (var prop of (props: Array)) {
        if (!prop.isProperty()) continue;

        var key = prop.get("key");

        // { foo: obj }
        var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });

        // { "foo": "obj" } or { ["foo"]: "obj" }
        match = match || key.isLiteral({ value: targetName });

        if (match) return prop.get("value").resolve(dangerous, resolved);
      }
    } else if (target.isArrayExpression() && !isNaN(+targetName)) {
      var elems = target.get("elements");
      var elem = elems[targetName];
      if (elem) return elem.resolve(dangerous, resolved);
    }
  }
}

/**
 * Infer the type of the current `NodePath`.
 *
 * NOTE: This is not cached. Use `getTypeAnnotation()` which is cached.
 */

export function getTypeAnnotation(force) {
  if (this.typeAnnotation) return this.typeAnnotation;

  var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
  if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
  return this.typeAnnotation = type;
}

export function _getTypeAnnotationBindingConstantViolations(name, types = []) {
  var binding = this.scope.getBinding(name);

  var types = [];
  this.typeAnnotation = t.unionTypeAnnotation(types);

  for (var constantViolation of (binding.constantViolations: Array)) {
    types.push(constantViolation.getTypeAnnotation());
  }

  if (types.length) {
    return t.createUnionTypeAnnotation(types);
  }
}

/**
 * todo: split up this method
 */

export function _getTypeAnnotation(force?: boolean): ?Object {
  var node = this.node;

  if (!node) {
    // handle initializerless variables, add in checks for loop initializers too
    if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
      var declar       = this.parentPath.parentPath;
      var declarParent = declar.parentPath;

      // for (var NODE in bar) {}
      if (declar.key === "left" && declarParent.isForInStatement()) {
        return t.stringTypeAnnotation();
      }

      // for (var NODE of bar) {}
      if (declar.key === "left" && declarParent.isForOfStatement()) {
        return t.anyTypeAnnotation();
      }

      return t.voidTypeAnnotation();
    } else {
      return;
    }
  }

  if (node.typeAnnotation) {
    return node.typeAnnotation;
  }

  //
  if (this.isVariableDeclarator()) {
    var id = this.get("id");

    if (id.isIdentifier()) {
      var init = this.get("init").getTypeAnnotation();

      // just because we're inferring a VariableDeclarator doesn't mean that it's the same
      // binding path as it may have been shadowed
      if (this.scope.getBinding(id.node.name).path === this) {
        return this._getTypeAnnotationBindingConstantViolations(id.node.name, [init]);
      } else {
        return init;
      }
    } else {
      return;
    }
  }

  //
  if (this.parentPath.isTypeCastExpression()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isTypeCastExpression()) {
    return node.typeAnnotation;
  }

  //
  if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
    return t.genericTypeAnnotation(t.identifier("Array"));
  }

  //
  if (!force && this.parentPath.isReturnStatement()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isReturnStatement()) {
    var funcPath = this.findParent((path) => path.isFunction());
    if (!funcPath) return;

    var returnType = funcPath.node.returnType;
    if (returnType) {
      return returnType;
    } else {
      return this.get("argument").getTypeAnnotation(true);
    }
  }

  //
  if (this.isNewExpression() && this.get("callee").isIdentifier()) {
    // only resolve identifier callee
    return t.genericTypeAnnotation(node.callee);
  }

  //
  if (this.isReferencedIdentifier()) {
    // check if a binding exists of this value and if so then return a union type of all
    // possible types that the binding could be
    var binding = this.scope.getBinding(node.name);
    if (binding) {
      if (binding.identifier.typeAnnotation) {
        return binding.identifier.typeAnnotation;
      } else {
        return this._getTypeAnnotationBindingConstantViolations(node.name, [
          binding.path.getTypeAnnotation()
        ]);
      }
    }

    // built-in values
    if (node.name === "undefined") {
      return t.voidTypeAnnotation();
    } else if (node.name === "NaN" || node.name === "Infinity") {
      return t.numberTypeAnnotation();
    } else if (node.name === "arguments") {
      // todo
    }
  }

  //
  if (this.isObjectExpression()) {
    return t.genericTypeAnnotation(t.identifier("Object"));
  }

  //
  if (this.isFunction() || this.isClass()) {
    return t.genericTypeAnnotation(t.identifier("Function"));
  }

  //
  if (this.isTemplateLiteral()) {
    return t.stringTypeAnnotation();
  }

  //
  if (this.isUnaryExpression()) {
    let operator = node.operator;

    if (operator === "void") {
      return t.voidTypeAnnotation();
    } else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.stringTypeAnnotation();
    } else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    }
  }

  //
  if (this.isBinaryExpression()) {
    let operator = node.operator;

    if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    } else if (operator === "+") {
      var right = this.get("right");
      var left  = this.get("left");

      if (left.isGenericType("Number") && right.isGenericType("Number")) {
        // both numbers so this will be a number
        return t.numberTypeAnnotation();
      } else if (left.isGenericType("String") || right.isGenericType("String")) {
        // one is a string so the result will be a string
        return t.stringTypeAnnotation();
      }

      // unsure if left and right are strings or numbers so stay on the safe side
      return t.unionTypeAnnotation([
        t.stringTypeAnnotation(),
        t.numberTypeAnnotation()
      ]);
    }
  }

  //
  if (this.isLogicalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("left").getTypeAnnotation(),
      this.get("right").getTypeAnnotation()
    ]);
  }

  //
  if (this.isConditionalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("consequent").getTypeAnnotation(),
      this.get("alternate").getTypeAnnotation()
    ]);
  }

  //
  if (this.isSequenceExpression()) {
    return this.get("expressions").pop().getTypeAnnotation(force);
  }

  //
  if (this.isAssignmentExpression()) {
    return this.get("right").getTypeAnnotation(force);
  }

  //
  if (this.isUpdateExpression()) {
    let operator = node.operator;
    if (operator === "++" || operator === "--") {
      return t.numberTypeAnnotation();
    }
  }

  //
  if (this.isLiteral()) {
    var value = node.value;
    if (typeof value === "string") return t.stringTypeAnnotation();
    if (typeof value === "number") return t.numberTypeAnnotation();
    if (typeof value === "boolean") return t.booleanTypeAnnotation();
    if (value === null) return t.voidTypeAnnotation();
    if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
  }

  //
  var callPath;
  if (this.isCallExpression()) callPath = this.get("callee");
  if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
  if (callPath) {
    var callee = callPath.resolve();
    // todo: read typescript/flow interfaces

    if (callee.isFunction()) {
      if (callee.is("async")) {
        if (callee.is("generator")) {
          return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
        } else {
          return t.genericTypeAnnotation(t.identifier("Promise"));
        }
      } else {
        if (callee.node.returnType) {
          return callee.node.returnType;
        } else {
          // todo: get union type of all return arguments
        }
      }
    }
  }
}

/**
 * Description
 */

export function isGenericType(genericName: string): boolean {
  var type = this.getTypeAnnotation();

  if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
    return true;
  }

  if (genericName === "String") {
    return t.isStringTypeAnnotation(type);
  } else if (genericName === "Number") {
    return t.isNumberTypeAnnotation(type);
  } else if (genericName === "Boolean") {
    return t.isBooleanTypeAnnotation(type);
  }

  return false;
}
<commit_msg>don't override types parameter<commit_after>import type NodePath from "./index";
import * as t from "../../types";

/**
 * Resolve a "pointer" `NodePath` to it's absolute path.
 */

export function resolve(dangerous, resolved) {
  return this._resolve(dangerous, resolved) || this;
}

export function _resolve(dangerous?, resolved?): ?NodePath {
  // detect infinite recursion
  // todo: possibly have a max length on this just to be safe
  if (resolved && resolved.indexOf(this) >= 0) return;

  // we store all the paths we've "resolved" in this array to prevent infinite recursion
  resolved = resolved || [];
  resolved.push(this);

  if (this.isVariableDeclarator()) {
    if (this.get("id").isIdentifier()) {
      return this.get("init").resolve(dangerous, resolved);
    } else {
      // otherwise it's a request for a pattern and that's a bit more tricky
    }
  } else if (this.isReferencedIdentifier()) {
    var binding = this.scope.getBinding(this.node.name);
    if (!binding) return;

    // reassigned so we can't really resolve it
    if (!binding.constant) return;

    // todo - lookup module in dependency graph
    if (binding.kind === "module") return;

    if (binding.path !== this) {
      return binding.path.resolve(dangerous, resolved);
    }
  } else if (dangerous && this.isMemberExpression()) {
    // this is dangerous, as non-direct target assignments will mutate it's state
    // making this resolution inaccurate

    var targetKey = this.toComputedKey();
    if (!t.isLiteral(targetKey)) return;

    var targetName = targetKey.value;

    var target = this.get("object").resolve(dangerous, resolved);

    if (target.isObjectExpression()) {
      var props = target.get("properties");
      for (var prop of (props: Array)) {
        if (!prop.isProperty()) continue;

        var key = prop.get("key");

        // { foo: obj }
        var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });

        // { "foo": "obj" } or { ["foo"]: "obj" }
        match = match || key.isLiteral({ value: targetName });

        if (match) return prop.get("value").resolve(dangerous, resolved);
      }
    } else if (target.isArrayExpression() && !isNaN(+targetName)) {
      var elems = target.get("elements");
      var elem = elems[targetName];
      if (elem) return elem.resolve(dangerous, resolved);
    }
  }
}

/**
 * Infer the type of the current `NodePath`.
 *
 * NOTE: This is not cached. Use `getTypeAnnotation()` which is cached.
 */

export function getTypeAnnotation(force) {
  if (this.typeAnnotation) return this.typeAnnotation;

  var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
  if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
  return this.typeAnnotation = type;
}

export function _getTypeAnnotationBindingConstantViolations(name, types = []) {
  var binding = this.scope.getBinding(name);

  this.typeAnnotation = t.unionTypeAnnotation(types);

  for (var constantViolation of (binding.constantViolations: Array)) {
    types.push(constantViolation.getTypeAnnotation());
  }

  if (types.length) {
    return t.createUnionTypeAnnotation(types);
  }
}

/**
 * todo: split up this method
 */

export function _getTypeAnnotation(force?: boolean): ?Object {
  var node = this.node;

  if (!node) {
    // handle initializerless variables, add in checks for loop initializers too
    if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
      var declar       = this.parentPath.parentPath;
      var declarParent = declar.parentPath;

      // for (var NODE in bar) {}
      if (declar.key === "left" && declarParent.isForInStatement()) {
        return t.stringTypeAnnotation();
      }

      // for (var NODE of bar) {}
      if (declar.key === "left" && declarParent.isForOfStatement()) {
        return t.anyTypeAnnotation();
      }

      return t.voidTypeAnnotation();
    } else {
      return;
    }
  }

  if (node.typeAnnotation) {
    return node.typeAnnotation;
  }

  //
  if (this.isVariableDeclarator()) {
    var id = this.get("id");

    if (id.isIdentifier()) {
      var init = this.get("init").getTypeAnnotation();

      // just because we're inferring a VariableDeclarator doesn't mean that it's the same
      // binding path as it may have been shadowed
      if (this.scope.getBinding(id.node.name).path === this) {
        return this._getTypeAnnotationBindingConstantViolations(id.node.name, [init]);
      } else {
        return init;
      }
    } else {
      return;
    }
  }

  //
  if (this.parentPath.isTypeCastExpression()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isTypeCastExpression()) {
    return node.typeAnnotation;
  }

  //
  if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
    return t.genericTypeAnnotation(t.identifier("Array"));
  }

  //
  if (!force && this.parentPath.isReturnStatement()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isReturnStatement()) {
    var funcPath = this.findParent((path) => path.isFunction());
    if (!funcPath) return;

    var returnType = funcPath.node.returnType;
    if (returnType) {
      return returnType;
    } else {
      return this.get("argument").getTypeAnnotation(true);
    }
  }

  //
  if (this.isNewExpression() && this.get("callee").isIdentifier()) {
    // only resolve identifier callee
    return t.genericTypeAnnotation(node.callee);
  }

  //
  if (this.isReferencedIdentifier()) {
    // check if a binding exists of this value and if so then return a union type of all
    // possible types that the binding could be
    var binding = this.scope.getBinding(node.name);
    if (binding) {
      if (binding.identifier.typeAnnotation) {
        return binding.identifier.typeAnnotation;
      } else {
        return this._getTypeAnnotationBindingConstantViolations(node.name, [
          binding.path.getTypeAnnotation()
        ]);
      }
    }

    // built-in values
    if (node.name === "undefined") {
      return t.voidTypeAnnotation();
    } else if (node.name === "NaN" || node.name === "Infinity") {
      return t.numberTypeAnnotation();
    } else if (node.name === "arguments") {
      // todo
    }
  }

  //
  if (this.isObjectExpression()) {
    return t.genericTypeAnnotation(t.identifier("Object"));
  }

  //
  if (this.isFunction() || this.isClass()) {
    return t.genericTypeAnnotation(t.identifier("Function"));
  }

  //
  if (this.isTemplateLiteral()) {
    return t.stringTypeAnnotation();
  }

  //
  if (this.isUnaryExpression()) {
    let operator = node.operator;

    if (operator === "void") {
      return t.voidTypeAnnotation();
    } else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.stringTypeAnnotation();
    } else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    }
  }

  //
  if (this.isBinaryExpression()) {
    let operator = node.operator;

    if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    } else if (operator === "+") {
      var right = this.get("right");
      var left  = this.get("left");

      if (left.isGenericType("Number") && right.isGenericType("Number")) {
        // both numbers so this will be a number
        return t.numberTypeAnnotation();
      } else if (left.isGenericType("String") || right.isGenericType("String")) {
        // one is a string so the result will be a string
        return t.stringTypeAnnotation();
      }

      // unsure if left and right are strings or numbers so stay on the safe side
      return t.unionTypeAnnotation([
        t.stringTypeAnnotation(),
        t.numberTypeAnnotation()
      ]);
    }
  }

  //
  if (this.isLogicalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("left").getTypeAnnotation(),
      this.get("right").getTypeAnnotation()
    ]);
  }

  //
  if (this.isConditionalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("consequent").getTypeAnnotation(),
      this.get("alternate").getTypeAnnotation()
    ]);
  }

  //
  if (this.isSequenceExpression()) {
    return this.get("expressions").pop().getTypeAnnotation(force);
  }

  //
  if (this.isAssignmentExpression()) {
    return this.get("right").getTypeAnnotation(force);
  }

  //
  if (this.isUpdateExpression()) {
    let operator = node.operator;
    if (operator === "++" || operator === "--") {
      return t.numberTypeAnnotation();
    }
  }

  //
  if (this.isLiteral()) {
    var value = node.value;
    if (typeof value === "string") return t.stringTypeAnnotation();
    if (typeof value === "number") return t.numberTypeAnnotation();
    if (typeof value === "boolean") return t.booleanTypeAnnotation();
    if (value === null) return t.voidTypeAnnotation();
    if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
  }

  //
  var callPath;
  if (this.isCallExpression()) callPath = this.get("callee");
  if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
  if (callPath) {
    var callee = callPath.resolve();
    // todo: read typescript/flow interfaces

    if (callee.isFunction()) {
      if (callee.is("async")) {
        if (callee.is("generator")) {
          return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
        } else {
          return t.genericTypeAnnotation(t.identifier("Promise"));
        }
      } else {
        if (callee.node.returnType) {
          return callee.node.returnType;
        } else {
          // todo: get union type of all return arguments
        }
      }
    }
  }
}

/**
 * Description
 */

export function isGenericType(genericName: string): boolean {
  var type = this.getTypeAnnotation();

  if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
    return true;
  }

  if (genericName === "String") {
    return t.isStringTypeAnnotation(type);
  } else if (genericName === "Number") {
    return t.isNumberTypeAnnotation(type);
  } else if (genericName === "Boolean") {
    return t.isBooleanTypeAnnotation(type);
  }

  return false;
}
<|endoftext|>


<commit_before>/**
 * A Gulp task for compiling JavaScript through Browserify.
 *
 * To use this in a gulpfile.js:
 *
 *    import BuildTask from 'carbon-factory/lib/gulp/build';
 *    gulp.task('default', BuildTask());
 *
 * You can also pass a hash of options to customise the task:
 *
 *    import BuildTask from 'carbon-factory/lib/gulp/build';
 *
 *    var opts = {
 *      src: "./src/main.js",
 *      jsDest: "./assets/javascripts",
 *      jsFile: "app.js"
 *    }
 *
 *    gulp.task('default', BuildTask(opts));
 *
 * If you have setup the task using the task name 'default' then you can run it
 * through the command line like this:
 *
 *    gulp
 *
 * The process can also be ran without watch files for changes (useful for running single builds):
 *
 *    gulp --build
 *
 * The process can also be ran with specific handlers:
 *
 *    gulp --handler uki
 *
 * This will include a module named `carbon-handler-uki` in the build process.
 */

import aliasify from 'aliasify';
import babel from 'babelify';
import browserify from 'browserify';
import gulp from 'gulp';
import gutil from 'gulp-util';
import mkdirp from 'mkdirp';
import notifier from 'node-notifier';
import parcelify from 'parcelify';
import envify from 'envify/custom';
import sassCssStream from 'sass-css-stream';
import source from 'vinyl-source-stream';
import watchify from 'watchify';
import yargs from 'yargs';
import gulpif from 'gulp-if';
import uglify from 'gulp-uglify';
import streamify from 'gulp-streamify';

var argv = yargs.argv;

export default function (opts) {
  var options = opts;

  return function() {
    var opts = options || {},
        // the entrypoint for the JavaScript application
        src = opts.src || './src/main.js',
        // the destination directory for the generated code
        jsDest = opts.jsDest || './assets/javascripts',
        // the destination file for the generated code
        jsFile = opts.jsFile || 'ui.js',
        // the destination for the css file
        cssDest = opts.cssDest || './assets/stylesheets',
        // the filename to write the css to
        cssFile = opts.cssFile || 'ui.css',
        // the destination for any fonts
        fontDest = opts.fontDest || './assets/fonts',
        // a standalone param to expose components globally
        standalone = opts.standalone || null,
        // if single build, or run and watch
        watch = (argv.build === undefined),
        // if in production mode
        production = argv.production || false;

    if (production) {
      process.env.NODE_ENV = 'production';
    }

    // handles any errors and exits the task
    function handleError(err) {
      // placeholder for toast notification message
      var notifierMessage = '';
      var message = err.message;

      // if location in file available
      if (err.loc) {
        var position = "\nLine: "   + err.loc.line
                     + "\nColumn: " + err.loc.column;
        notifierMessage += position;
        message += position;
      }

      // if code context available
      if (err.codeFrame) {
        message += "\n" + err.codeFrame;
      }

      // additional toast notification variables
      var title = 'Error: '

      // format file path
      if (err.filename) {
        var file = err.filename.split('/');
        title += file[file.length-1];
      }

      // output error messages in toast and in console
      notifier.notify({ title: title, message: notifierMessage } );
      gutil.log(gutil.colors.red(err.name), message);

      // exit task
      this.emit('end');
    }

    // a handler argument if supplied one when running the task
    var handler = argv.handler;

    /**
     * Babel options (for JS/JSX).
     */
    var babelTransform = babel.configure({
      // use experimental es7 class properties
      optional: [ "es7.classProperties" ]
    });

    /**
     * Alias options (to include handler specific JS).
     */
    var aliasTransform = null;

    if (handler) {
      aliasTransform = aliasify.configure({
        aliases: {
          // make it possible to import the original handler if `carbon-handler`
          // is aliased to get something else
          "base-handler": "./src/carbon-handler",
          // if using a handler, alias any imports of `carbon-handler` to use
          // the handler instead
          "carbon-handler": "carbon-handler-" + handler
        }
      });
    }

    /**
     * Envify options (sets env options when compiling code).
     */
    var envifyTransform = envify({
      global: true,
      _: 'purge',
      NODE_ENV: process.env.NODE_ENV
    });

    /**
     * Browserify options (for CommonJS).
     */
    var browserifyOpts = {
      // the entry points for the application
      entries: [ src ],
      // which transforms to apply to the code
      transform: [ babelTransform, aliasTransform, envifyTransform ],
      // lookup paths when importing modules
      paths: [ './src' ]
    };

    if (standalone) {
      browserifyOpts.standalone = standalone;
    }

    var browserified = browserify(browserifyOpts);

    // create dirs for assets
    mkdirp(fontDest, function (err) {
      if (err) console.error(err);
    });
    mkdirp(cssDest, function (err) {
      if (err) console.error(err);
    });

    /**
     * Parcelify options (for Sass/CSS).
     */
    var parcelified = parcelify(browserified, {
      // watch scss files to update on any changes
      watch: watch,
      // where to bundle the output
      bundles: {
        style: cssDest + '/' + cssFile,
        fonts: null
      },
      appTransforms : [
        // sass transformer
        function sassTransformer( file ) {
          // array of include paths allows for overriding entire files
          return sassCssStream( file, {
            includePaths: [
              process.cwd() + "/src/style-config", // check for overrides in local style-config directory
              process.cwd() + "/node_modules/carbon/lib/style-config", // check for original config files
              process.cwd() + "/node_modules" // generic namespace for any other lookups
            ]
          });
        }
      ],
      // where to apply transforms
      appTransformDirs: ['./node_modules/carbon', './']
    }).on('done', function() {
      // when parcelify is ready
      console.log('assets are compiled!');
    }).on('error', function(err) {
      // handle error
      gutil.log("*** CSS Error ***");
      handleError.call(this, err);
    }).on('bundleWritten', function(path, name, parcel) {
      // copy the fonts to the correct directory
      var fonts = [];
      parcel.parcelAssetsByType.fonts.forEach((font) => {
        fonts.push(font.srcPath);
      });
      gulp.src(fonts)
        .pipe(gulp.dest(fontDest));

      // write the css file
      return gulp.src(cssFile)
        .on('error', () => gutil.log("*** Error writing the CSS File ***"))
        .on('error', handleError)
        .pipe(gulp.dest(cssDest));
    });

    /**
     * The pack we are going to watch and build
     */
    var bundler = watch ? watchify(browserified) : browserified;

    /**
     * The main build task.
     */
    function build(f) {
      if (f) gutil.log('Recompiling ' + f);
      return bundler
        .bundle()
        .on('error', () => gutil.log("*** Browserify Error ***"))
        .on('error', handleError)
        .pipe(source(jsFile))
        .pipe(gulpif(production, streamify(uglify())))
        .pipe(gulp.dest(jsDest));
    };

    // run the build immediately and whenever the bundler updates
    bundler.on('update', build);
    build();
  }
};
<commit_msg>increase rebundle speed<commit_after>/**
 * A Gulp task for compiling JavaScript through Browserify.
 *
 * To use this in a gulpfile.js:
 *
 *    import BuildTask from 'carbon-factory/lib/gulp/build';
 *    gulp.task('default', BuildTask());
 *
 * You can also pass a hash of options to customise the task:
 *
 *    import BuildTask from 'carbon-factory/lib/gulp/build';
 *
 *    var opts = {
 *      src: "./src/main.js",
 *      jsDest: "./assets/javascripts",
 *      jsFile: "app.js"
 *    }
 *
 *    gulp.task('default', BuildTask(opts));
 *
 * If you have setup the task using the task name 'default' then you can run it
 * through the command line like this:
 *
 *    gulp
 *
 * The process can also be ran without watch files for changes (useful for running single builds):
 *
 *    gulp --build
 *
 * The process can also be ran with specific handlers:
 *
 *    gulp --handler uki
 *
 * This will include a module named `carbon-handler-uki` in the build process.
 */

import aliasify from 'aliasify';
import babel from 'babelify';
import browserify from 'browserify';
import gulp from 'gulp';
import gutil from 'gulp-util';
import mkdirp from 'mkdirp';
import notifier from 'node-notifier';
import parcelify from 'parcelify';
import envify from 'envify/custom';
import sassCssStream from 'sass-css-stream';
import source from 'vinyl-source-stream';
import watchify from 'watchify';
import yargs from 'yargs';
import gulpif from 'gulp-if';
import uglify from 'gulp-uglify';
import streamify from 'gulp-streamify';

var argv = yargs.argv;

export default function (opts) {
  var options = opts;

  return function() {
    var opts = options || {},
        // the entrypoint for the JavaScript application
        src = opts.src || './src/main.js',
        // the destination directory for the generated code
        jsDest = opts.jsDest || './assets/javascripts',
        // the destination file for the generated code
        jsFile = opts.jsFile || 'ui.js',
        // the destination for the css file
        cssDest = opts.cssDest || './assets/stylesheets',
        // the filename to write the css to
        cssFile = opts.cssFile || 'ui.css',
        // the destination for any fonts
        fontDest = opts.fontDest || './assets/fonts',
        // a standalone param to expose components globally
        standalone = opts.standalone || null,
        // if single build, or run and watch
        watch = (argv.build === undefined),
        // if in production mode
        production = argv.production || false;

    if (production) {
      process.env.NODE_ENV = 'production';
    }

    // handles any errors and exits the task
    function handleError(err) {
      // placeholder for toast notification message
      var notifierMessage = '';
      var message = err.message;

      // if location in file available
      if (err.loc) {
        var position = "\nLine: "   + err.loc.line
                     + "\nColumn: " + err.loc.column;
        notifierMessage += position;
        message += position;
      }

      // if code context available
      if (err.codeFrame) {
        message += "\n" + err.codeFrame;
      }

      // additional toast notification variables
      var title = 'Error: '

      // format file path
      if (err.filename) {
        var file = err.filename.split('/');
        title += file[file.length-1];
      }

      // output error messages in toast and in console
      notifier.notify({ title: title, message: notifierMessage } );
      gutil.log(gutil.colors.red(err.name), message);

      // exit task
      this.emit('end');
    }

    // a handler argument if supplied one when running the task
    var handler = argv.handler;

    /**
     * Babel options (for JS/JSX).
     */
    var babelTransform = babel.configure({
      // use experimental es7 class properties
      optional: [ "es7.classProperties" ]
    });

    /**
     * Alias options (to include handler specific JS).
     */
    var aliasTransform = null;

    if (handler) {
      aliasTransform = aliasify.configure({
        aliases: {
          // make it possible to import the original handler if `carbon-handler`
          // is aliased to get something else
          "base-handler": "./src/carbon-handler",
          // if using a handler, alias any imports of `carbon-handler` to use
          // the handler instead
          "carbon-handler": "carbon-handler-" + handler
        }
      });
    }

    /**
     * Envify options (sets env options when compiling code).
     */
    var envifyTransform = envify({
      global: true,
      _: 'purge',
      NODE_ENV: process.env.NODE_ENV
    });

    /**
     * Browserify options (for CommonJS).
     */
    var browserifyOpts = {
      // the entry points for the application
      entries: [ src ],
      // which transforms to apply to the code
      transform: [ babelTransform, aliasTransform, envifyTransform ],
      // lookup paths when importing modules
      paths: [ './src' ],

      cache: {},

      packageCache: {}
    };

    if (standalone) {
      browserifyOpts.standalone = standalone;
    }

    var browserified = browserify(browserifyOpts);

    // create dirs for assets
    mkdirp(fontDest, function (err) {
      if (err) console.error(err);
    });
    mkdirp(cssDest, function (err) {
      if (err) console.error(err);
    });

    /**
     * Parcelify options (for Sass/CSS).
     */
    var parcelified = parcelify(browserified, {
      // watch scss files to update on any changes
      watch: watch,
      // where to bundle the output
      bundles: {
        style: cssDest + '/' + cssFile,
        fonts: null
      },
      appTransforms : [
        // sass transformer
        function sassTransformer( file ) {
          // array of include paths allows for overriding entire files
          return sassCssStream( file, {
            includePaths: [
              process.cwd() + "/src/style-config", // check for overrides in local style-config directory
              process.cwd() + "/node_modules/carbon/lib/style-config", // check for original config files
              process.cwd() + "/node_modules" // generic namespace for any other lookups
            ]
          });
        }
      ],
      // where to apply transforms
      appTransformDirs: ['./node_modules/carbon', './']
    }).on('done', function() {
      // when parcelify is ready
      console.log('assets are compiled!');
    }).on('error', function(err) {
      // handle error
      gutil.log("*** CSS Error ***");
      handleError.call(this, err);
    }).on('bundleWritten', function(path, name, parcel) {
      // copy the fonts to the correct directory
      var fonts = [];
      parcel.parcelAssetsByType.fonts.forEach((font) => {
        fonts.push(font.srcPath);
      });
      gulp.src(fonts)
        .pipe(gulp.dest(fontDest));

      // write the css file
      return gulp.src(cssFile)
        .on('error', () => gutil.log("*** Error writing the CSS File ***"))
        .on('error', handleError)
        .pipe(gulp.dest(cssDest));
    });

    /**
     * The pack we are going to watch and build
     */
    var bundler = watch ? watchify(browserified) : browserified;

    /**
     * The main build task.
     */
    function build(f) {
      if (f) gutil.log('Recompiling ' + f);
      return bundler
        .bundle()
        .on('error', () => gutil.log("*** Browserify Error ***"))
        .on('error', handleError)
        .pipe(source(jsFile))
        .pipe(gulpif(production, streamify(uglify())))
        .pipe(gulp.dest(jsDest));
    };

    // run the build immediately and whenever the bundler updates
    bundler.on('update', build);
    build();
  }
};
<|endoftext|>


<commit_before>import del from 'del'
import gulp from 'gulp'
import rump from '..'
import configs from '../configs'

const name = ::rump.taskName,
      task = ::gulp.task

// Sync is used until there is a way to do series in Gulp
task(name('clean'), () => {
  del.sync(configs.main.paths.destination.root)
})

// Sync is used until there is a way to do series in Gulp
task(name('clean:safe'), () => {
  if(configs.main.clean) {
    del.sync(configs.main.paths.destination.root)
  }
})
<commit_msg>[ci skip] Code formatting<commit_after>import del from 'del'
import gulp from 'gulp'
import rump from '..'
import configs from '../configs'

const name = ::rump.taskName,
      task = ::gulp.task

// Sync is used until there is a way to do series in Gulp
task(name('clean'), () => del.sync(configs.main.paths.destination.root))

// Sync is used until there is a way to do series in Gulp
task(name('clean:safe'), () => {
  if(configs.main.clean) {
    del.sync(configs.main.paths.destination.root)
  }
})
<|endoftext|>


<commit_before>#!/usr/bin/env node

/** Configure project packaging according to brand-specific parameters.
 *
 * Without any arguments, we indicate the current brand link and the
 * available brands.
 *
 * With one argument, select the indicated brand directory as current and,
 * if the brand directory has changed:
 *
 * - suitably point the <repo>/custom/brand symlink
 * - apply the brand specification file, <repo>/custom/brand/brand_config.json
 * - reestablish the Cordova platforms
 *
 * There are two special brand-name arguments:
 *
 * -  "dash" for priming brand configuration. Establishes the default
 *    value (`SpiderOak`) iff no brand setting is established, but otherwise
 *    doing nothing. Thus we can use it as part of 'npm install' actions, to
 *    establish an initial setting.
 *
 * !  "bang" to redo the processing for the current setting. Useful if the
 *    processign was disrupted, or changes made to the relevant templates.
 *
 * @param {string} The name of the brand directory, in <repo>/custom/brands/, or `-' for initializing
 */

/* App defaults configuration: */
var defaultBrandName = 'SpiderOak',
    defaultBrandIdentifier = "com.spideroak.spideroak";

/* Internal program setup: */
var fs = require('fs'),
    path = require('path'),
    errnos = require('errno-codes'),
    projectRootDir = path.resolve(__dirname, '..', '..'),
    projectCustomDir = path.resolve(__dirname, '..'),
    brandElementsConfigPath = path.join(projectCustomDir,
                                        "brand_elements.json"),
    brandsDir = path.join(projectRootDir, 'custom', 'brands'),
    brandSymlinkLocation = path.join(projectRootDir, 'custom', 'brand'),
    projectConfigFilePath = path.join(brandSymlinkLocation,
                                      'project_config.json'),
    configDotJsonPath = path.join(projectRootDir, ".cordova", "config.json"),
    platformsDir = path.join(projectRootDir, "platforms");

/** Driver, for when this module is run as a script.
 *
 * @param {string} executive javascript engine executing the script
 * @param {string} scriptName
 * @param {string} brandName name of brand dir being selected in custom/brands
 */
function main(executive, scriptName, brandName) {
  var reporting = (! brandName),
      priming = (brandName === "-"),
      refreshing = (brandName === "!");

  blather(relativeToProjectRoot(scriptName));

  if (reporting) {
    report()
  }
  else if (priming) {
    prime();
  }
  else {
    var wasCurrent = getCurrentBrandName();
    if (refreshing) {
      if (! wasCurrent) {
        blather("No current brand to reestablish.");
        process.exit(1);
      }
      else {
        brandName = wasCurrent;
      }
    }
    else if (brandName === wasCurrent) {
      blather("Brand is already current, no change: " + brandName);
      process.exit(0);
    }
    if (! establishBrandByName(brandName, refreshing)) {
      process.exit(1);
    }
  }
  process.exit(0);
}

/** Print the current brand dir and the available choices. */
function report() {
  var current = getCurrentBrandName();
  blather("Current brand: " +
          current ||
          ((typeof current === "undefined") ? "<no link>" : "<bad link>"));
  blather("Available brands: " + fs.readdirSync(brandsDir).join(", "));
}
/** Only if no brand currently established, set to the default one.
 *
 * ("No brand established" includes invalid link.)
 *
 * @return {boolean} true if brand was changed, false otherwise.
 */
function prime() {
  var current = getCurrentBrandName();
  if (current) {
    blather("No change to already established brand: " + current);
    return false;
  }
  else {
    if (establishBrandByName(defaultBrandName)) {
      blather("Establishing default package brand: " + defaultBrandName);
      return true;
    }
  }
}

/** Get the package's current brand, by name.
 * @returns {string} the name of the brand dir in custom/brands, if valid, or
 * @returns {boolean} false if link points at a non-existent target, or
 * @returns {undefined} undefined if not set.
 */
function getCurrentBrandName() {
  var got, exc;
  try { got = fs.readlinkSync(brandSymlinkLocation); }
  catch (exc) { return undefined; };
  return (fs.existsSync(path.resolve(path.dirname(
    brandSymlinkLocation), got)) &&
          path.basename(got));
}
/** Set the package's brand.
 *
 * This includes:
 *
 * - assert the custom/brand@ link to the indicated custom/brands/name dir,
 *
 * in the case of error:
 *   - apply suitable handling and bail
 *
 * or, on successful linking:
 *   - massaging of the manifest templates with the brand-specific values, and
 *   - recreation of the various platforms, which will incorporate the results.
 *
 * @param {string} brandName name of brand dir in custom/brands/
 * @returns {boolean} true if successful, false if not.
 */
function establishBrandByName(brandName, doingRefresh) {
  var brandPath = path.join(brandsDir, brandName),
      relpath = path.join('brands', brandName);
  if (! fs.existsSync(brandPath)) {
    blather("No such brand dir %s" + brandPath);
    return false;
  }
  else {
    try {
      fs.readlinkSync(brandSymlinkLocation);
      fs.unlinkSync(brandSymlinkLocation);
    }
    catch (err) {
      if (err.errno === errnos.EINVAL.errno) {
        // Exists, but not a symlink
        blather("File or directory blocking brand symlink, " +
                    "please remove it: " + brandSymlinkLocation);
        process.exit(1);
      }
    }
    var disposition = doingRefresh ? "Reestablishing" : "Set";
    blather(disposition + " package brand: " + brandName);
    fs.symlinkSync(relpath, brandSymlinkLocation);
    if (! fs.readlinkSync(brandSymlinkLocation)) {
      throw new Error("Brand link creation failed");
    }
    else {
      adjustManifestsToBrand();
      createCordovaPlatforms();
      blather("Done.");
      return true;
    }
  }
}

/** Produce various platform manifests including brand-specific values.
 *
 * > .cordova/config.json - fabricate entirely, identifier, projectName
 * > www/config.xml - substitute values in .template:
 *       projectName, description, name
 * > www/res/config/AndroidManifest.xml - substitute values in .template:
 *       identifier, projectName
 * > www/res/config/SpiderOak-Info.plist - substitute values in .template:
 *       identifier
 */
function adjustManifestsToBrand() {
  var projectConfig = require(path.join(brandSymlinkLocation,
                                        "project_config.json")),
      brandElementsConfig = require(brandElementsConfigPath),
      i;
  fabricateConfigDotJson(projectConfig);
  for (i in brandElementsConfig) {
    var relpath = brandElementsConfig[i][0],
        elementsSpec = brandElementsConfig[i][1],
        confResultFile = path.join(projectRootDir,
                                   path.join.apply({}, relpath.split("/"))),
        confResultFileTemplate = confResultFile + ".template";
    fabricateConfigFromTemplate(confResultFile, confResultFileTemplate,
                                projectConfig, elementsSpec);
  }
}
/** Create project config file from template, brand values, and elements spec.
 *
 * Each elements spec is a list containing two or three items:
 * 1. Name of projectConfig value to substitute
 * 2. Path to tag within template structure - XPath for XML, plist for .plist
 * 3. Optional tag attribute to receive the value.
 * When no tag attribute is specified, the tag itself receives the value.
 *
 * Errors are thrown if specified projectConfig attributes or template tags
 * or tag attributes are not found.
 *
 * @param {string} resultPath to the output file
 * @param {string} templatePath to the input file
 * @param {object} projectConfig with the fields and brand-specific values
 * @param {object} elementsSpec identifying the changes - see above for details
 */
function fabricateConfigFromTemplate(resultPath, templatePath,
                                     projectConfig, elementsSpec) {
  var ext = path.extname(resultPath),
      transformer = ((ext === ".plist") ?
                     PlistTemplateTransformer :
                     XMLTemplateTransformer),
      subject = new transformer(templatePath, resultPath);

  for (i in elementsSpec) {
    var curSpec = elementsSpec[i],
        field = curSpec[0],
        tagPath = curSpec[1],
        attrName = curSpec[2],
        value = projectConfig[field];

    subject.replace(value, tagPath, attrName);
  }
  fs.writeFileSync(resultPath, subject, {mode: "0644"});
  blather("Fabricated project configuration file " +
          relativeToProjectRoot(resultPath));
}

/** Create platforms per changed configs, removing existing ones if present.
 * We just remove all the existing platforms and then recreate them.
 */
function createCordovaPlatforms() {
  var shell = require('shelljs'),
      platforms = fs.readdirSync(platformsDir),
      init = false,
      removeCmd, addCmd, code;

  debugger;
  platforms = platforms.filter(function(fname) {
    return (fname[0] !== '.') ? fname : false;
  });
  platforms = platforms.join(" ");

  if (platforms === "") {
    platforms = "ios android";
  }
  else {
    removeCmd = "cordova platform remove " + platforms;
    blather("Removing existing cordova platforms: " + removeCmd);
    code = shell.exec(removeCmd).code;
    if (code !== 0) {
      blather("Platforms remove failed (" + code + "): " + addCmd);
      process.exit(1)
    }
  }
  addCmd = "cordova platform add " + platforms;
  blather((init ? "Creating" : "Recreating") +
          " cordova platforms: " + addCmd);
  code = shell.exec(addCmd).code;
  if (code !== 0) {
    blather("Platforms add failed (" + code + "): " + addCmd);
    process.exit(1)
  }
}

function PlistTemplateTransformer(templatePath, resultPath) {
  this.plist = require('plist');
  this.subject = this.plist.parseFileSync(templatePath, 'utf-8');
}
PlistTemplateTransformer.prototype.replace = function(value, tagPath, attr) {
  // We don't implement attr replacement in plist transformer.
  this.subject[tagPath] = value;
};
PlistTemplateTransformer.prototype.toString = function() {
  return this.plist.build(this.subject);
};
function XMLTemplateTransformer(templatePath, resultPath) {
  var et = require('elementtree');
  this.templatePath = templatePath;
  this.subject = et.parse(fs.readFileSync(templatePath, 'utf-8').toString());
}
XMLTemplateTransformer.prototype.replace = function(value, tagPath, attr) {
  var tag = this.subject.find(tagPath);
  attr ? tag.set(attr, value) : tag.text = value;
};
XMLTemplateTransformer.prototype.toString = function() {
  return this.subject.write({indent: true});
};

function fabricateConfigDotJson(projectConfig) {
  var data = {id: projectConfig.identifier, name: projectConfig.projectName};
  fs.writeFileSync(configDotJsonPath, JSON.stringify(data) + "\n",
                   {mode: 0644});
  blather("Fabricated " + relativeToProjectRoot(configDotJsonPath));
}

function relativeToProjectRoot(thePath) {
  return path.relative(projectRootDir, thePath);
}
function blather(message) {
  console.log("[BrandPackage] %s", message)
}

if (require.main === module) {
    main(process.argv[0], process.argv[1], process.argv[2]);
}
<commit_msg>Make the default platforms script variables,<commit_after>#!/usr/bin/env node

/** Configure project packaging according to brand-specific parameters.
 *
 * Without any arguments, we indicate the current brand link and the
 * available brands.
 *
 * With one argument, select the indicated brand directory as current and,
 * if the brand directory has changed:
 *
 * - suitably point the <repo>/custom/brand symlink
 * - apply the brand specification file, <repo>/custom/brand/brand_config.json
 * - reestablish the Cordova platforms
 *
 * There are two special brand-name arguments:
 *
 * -  "dash" for priming brand configuration. Establishes the default
 *    value (`SpiderOak`) iff no brand setting is established, but otherwise
 *    doing nothing. Thus we can use it as part of 'npm install' actions, to
 *    establish an initial setting.
 *
 * !  "bang" to redo the processing for the current setting. Useful if the
 *    processign was disrupted, or changes made to the relevant templates.
 *
 * @param {string} The name of the brand directory, in <repo>/custom/brands/, or `-' for initializing
 */

/* App defaults configuration: */
var defaultBrandName = 'SpiderOak',
    defaultBrandIdentifier = "com.spideroak.spideroak";

/* Internal program setup: */
var fs = require('fs'),
    path = require('path'),
    errnos = require('errno-codes'),
    projectRootDir = path.resolve(__dirname, '..', '..'),
    projectCustomDir = path.resolve(__dirname, '..'),
    brandElementsConfigPath = path.join(projectCustomDir,
                                        "brand_elements.json"),
    brandsDir = path.join(projectRootDir, 'custom', 'brands'),
    brandSymlinkLocation = path.join(projectRootDir, 'custom', 'brand'),
    projectConfigFilePath = path.join(brandSymlinkLocation,
                                      'project_config.json'),
    configDotJsonPath = path.join(projectRootDir, ".cordova", "config.json"),
    platformsDir = path.join(projectRootDir, "platforms"),
    defaultPlatforms = "ios android";

/** Driver, for when this module is run as a script.
 *
 * @param {string} executive javascript engine executing the script
 * @param {string} scriptName
 * @param {string} brandName name of brand dir being selected in custom/brands
 */
function main(executive, scriptName, brandName) {
  var reporting = (! brandName),
      priming = (brandName === "-"),
      refreshing = (brandName === "!");

  blather(relativeToProjectRoot(scriptName));

  if (reporting) {
    report()
  }
  else if (priming) {
    prime();
  }
  else {
    var wasCurrent = getCurrentBrandName();
    if (refreshing) {
      if (! wasCurrent) {
        blather("No current brand to reestablish.");
        process.exit(1);
      }
      else {
        brandName = wasCurrent;
      }
    }
    else if (brandName === wasCurrent) {
      blather("Brand is already current, no change: " + brandName);
      process.exit(0);
    }
    if (! establishBrandByName(brandName, refreshing)) {
      process.exit(1);
    }
  }
  process.exit(0);
}

/** Print the current brand dir and the available choices. */
function report() {
  var current = getCurrentBrandName();
  blather("Current brand: " +
          current ||
          ((typeof current === "undefined") ? "<no link>" : "<bad link>"));
  blather("Available brands: " + fs.readdirSync(brandsDir).join(", "));
}
/** Only if no brand currently established, set to the default one.
 *
 * ("No brand established" includes invalid link.)
 *
 * @return {boolean} true if brand was changed, false otherwise.
 */
function prime() {
  var current = getCurrentBrandName();
  if (current) {
    blather("No change to already established brand: " + current);
    return false;
  }
  else {
    if (establishBrandByName(defaultBrandName)) {
      blather("Establishing default package brand: " + defaultBrandName);
      return true;
    }
  }
}

/** Get the package's current brand, by name.
 * @returns {string} the name of the brand dir in custom/brands, if valid, or
 * @returns {boolean} false if link points at a non-existent target, or
 * @returns {undefined} undefined if not set.
 */
function getCurrentBrandName() {
  var got, exc;
  try { got = fs.readlinkSync(brandSymlinkLocation); }
  catch (exc) { return undefined; };
  return (fs.existsSync(path.resolve(path.dirname(
    brandSymlinkLocation), got)) &&
          path.basename(got));
}
/** Set the package's brand.
 *
 * This includes:
 *
 * - assert the custom/brand@ link to the indicated custom/brands/name dir,
 *
 * in the case of error:
 *   - apply suitable handling and bail
 *
 * or, on successful linking:
 *   - massaging of the manifest templates with the brand-specific values, and
 *   - recreation of the various platforms, which will incorporate the results.
 *
 * @param {string} brandName name of brand dir in custom/brands/
 * @returns {boolean} true if successful, false if not.
 */
function establishBrandByName(brandName, doingRefresh) {
  var brandPath = path.join(brandsDir, brandName),
      relpath = path.join('brands', brandName);
  if (! fs.existsSync(brandPath)) {
    blather("No such brand dir %s" + brandPath);
    return false;
  }
  else {
    try {
      fs.readlinkSync(brandSymlinkLocation);
      fs.unlinkSync(brandSymlinkLocation);
    }
    catch (err) {
      if (err.errno === errnos.EINVAL.errno) {
        // Exists, but not a symlink
        blather("File or directory blocking brand symlink, " +
                    "please remove it: " + brandSymlinkLocation);
        process.exit(1);
      }
    }
    var disposition = doingRefresh ? "Reestablishing" : "Set";
    blather(disposition + " package brand: " + brandName);
    fs.symlinkSync(relpath, brandSymlinkLocation);
    if (! fs.readlinkSync(brandSymlinkLocation)) {
      throw new Error("Brand link creation failed");
    }
    else {
      adjustManifestsToBrand();
      createCordovaPlatforms();
      blather("Done.");
      return true;
    }
  }
}

/** Produce various platform manifests including brand-specific values.
 *
 * > .cordova/config.json - fabricate entirely, identifier, projectName
 * > www/config.xml - substitute values in .template:
 *       projectName, description, name
 * > www/res/config/AndroidManifest.xml - substitute values in .template:
 *       identifier, projectName
 * > www/res/config/SpiderOak-Info.plist - substitute values in .template:
 *       identifier
 */
function adjustManifestsToBrand() {
  var projectConfig = require(path.join(brandSymlinkLocation,
                                        "project_config.json")),
      brandElementsConfig = require(brandElementsConfigPath),
      i;
  fabricateConfigDotJson(projectConfig);
  for (i in brandElementsConfig) {
    var relpath = brandElementsConfig[i][0],
        elementsSpec = brandElementsConfig[i][1],
        confResultFile = path.join(projectRootDir,
                                   path.join.apply({}, relpath.split("/"))),
        confResultFileTemplate = confResultFile + ".template";
    fabricateConfigFromTemplate(confResultFile, confResultFileTemplate,
                                projectConfig, elementsSpec);
  }
}
/** Create project config file from template, brand values, and elements spec.
 *
 * Each elements spec is a list containing two or three items:
 * 1. Name of projectConfig value to substitute
 * 2. Path to tag within template structure - XPath for XML, plist for .plist
 * 3. Optional tag attribute to receive the value.
 * When no tag attribute is specified, the tag itself receives the value.
 *
 * Errors are thrown if specified projectConfig attributes or template tags
 * or tag attributes are not found.
 *
 * @param {string} resultPath to the output file
 * @param {string} templatePath to the input file
 * @param {object} projectConfig with the fields and brand-specific values
 * @param {object} elementsSpec identifying the changes - see above for details
 */
function fabricateConfigFromTemplate(resultPath, templatePath,
                                     projectConfig, elementsSpec) {
  var ext = path.extname(resultPath),
      transformer = ((ext === ".plist") ?
                     PlistTemplateTransformer :
                     XMLTemplateTransformer),
      subject = new transformer(templatePath, resultPath);

  for (i in elementsSpec) {
    var curSpec = elementsSpec[i],
        field = curSpec[0],
        tagPath = curSpec[1],
        attrName = curSpec[2],
        value = projectConfig[field];

    subject.replace(value, tagPath, attrName);
  }
  fs.writeFileSync(resultPath, subject, {mode: "0644"});
  blather("Fabricated project configuration file " +
          relativeToProjectRoot(resultPath));
}

/** Create platforms per changed configs, removing existing ones if present.
 * We just remove all the existing platforms and then recreate them.
 */
function createCordovaPlatforms() {
  var shell = require('shelljs'),
      platforms = fs.readdirSync(platformsDir),
      init = false,
      removeCmd, addCmd, code;

  debugger;
  platforms = platforms.filter(function(fname) {
    return (fname[0] !== '.') ? fname : false;
  });
  platforms = platforms.join(" ");

  if (platforms === "") {
    platforms = defaultPlatforms;
  }
  else {
    removeCmd = "cordova platform remove " + platforms;
    blather("Removing existing cordova platforms: " + removeCmd);
    code = shell.exec(removeCmd).code;
    if (code !== 0) {
      blather("Platforms remove failed (" + code + "): " + addCmd);
      process.exit(1)
    }
  }
  addCmd = "cordova platform add " + platforms;
  blather((init ? "Creating" : "Recreating") +
          " cordova platforms: " + addCmd);
  code = shell.exec(addCmd).code;
  if (code !== 0) {
    blather("Platforms add failed (" + code + "): " + addCmd);
    process.exit(1)
  }
}

function PlistTemplateTransformer(templatePath, resultPath) {
  this.plist = require('plist');
  this.subject = this.plist.parseFileSync(templatePath, 'utf-8');
}
PlistTemplateTransformer.prototype.replace = function(value, tagPath, attr) {
  // We don't implement attr replacement in plist transformer.
  this.subject[tagPath] = value;
};
PlistTemplateTransformer.prototype.toString = function() {
  return this.plist.build(this.subject);
};
function XMLTemplateTransformer(templatePath, resultPath) {
  var et = require('elementtree');
  this.templatePath = templatePath;
  this.subject = et.parse(fs.readFileSync(templatePath, 'utf-8').toString());
}
XMLTemplateTransformer.prototype.replace = function(value, tagPath, attr) {
  var tag = this.subject.find(tagPath);
  attr ? tag.set(attr, value) : tag.text = value;
};
XMLTemplateTransformer.prototype.toString = function() {
  return this.subject.write({indent: true});
};

function fabricateConfigDotJson(projectConfig) {
  var data = {id: projectConfig.identifier, name: projectConfig.projectName};
  fs.writeFileSync(configDotJsonPath, JSON.stringify(data) + "\n",
                   {mode: 0644});
  blather("Fabricated " + relativeToProjectRoot(configDotJsonPath));
}

function relativeToProjectRoot(thePath) {
  return path.relative(projectRootDir, thePath);
}
function blather(message) {
  console.log("[BrandPackage] %s", message)
}

if (require.main === module) {
    main(process.argv[0], process.argv[1], process.argv[2]);
}
<|endoftext|>


<commit_before>import './index.less'
import video from './video'
import rayInput from './rayInput'

let container = null
let	renderer = null
let	effect = null
let	controls = null
let	scene = null
let	camera = null
let	plane = null
let btn = null
let wheels = null
let	VRMode = false
let wheelSpin = true

// Set up Three.js
initThreeJS()
// Set up VR rendering
initVREffect()
// Create the scene content
initScene()
// Set up VR camera controls
initVRControls()

// init ray input
initRayInput()

// Run the run loop
run()
// Bind Dom Events
bindEvents()

function initThreeJS() {
	container = document.getElementById('container')
	// Create the Three.js renderer and attach it to our canvas
	renderer = new THREE.WebGLRenderer( { antialias: true } )
	// Set the viewport size
	renderer.setSize(window.innerWidth, window.innerHeight)
	container.appendChild(renderer.domElement)

	window.addEventListener('resize', function(event) {
		renderer.setSize(window.innerWidth, window.innerHeight)
	}, false)
}

function initRayInput() {
	rayInput.init(camera)
}

function initVREffect() {
// Set up Cardboard renderer
	effect = new THREE.StereoEffect(renderer)
	effect.setSize(window.innerWidth, window.innerHeight)

	// StereoEffect's default separation is in cm, we're in M
	// Actual cardboard eye separation is 2.5in
	// Finally, separation is per-eye so divide by 2
	effect.separation = 2.5 * 0.0254 / 2
}

function initScene() {
	// Create a new Three.js scene
	scene = new THREE.Scene()
	// Add  a camera so we can view the scene
	// Note that this camera's FOV is ignored in favor of the
	// Oculus-supplied FOV for each used inside VREffect.
	// See VREffect.js h/t Michael Blix
	camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 0.1, 4000 )

	scene.add(camera)

	scene.add(video.init())

    var listener = new THREE.AudioListener();
    camera.add( listener );
    var audioLoader = new THREE.AudioLoader();
    var sound4 = new THREE.Audio( listener );
    audioLoader.load( 'src/home/videos/tractor.mp3', function( buffer ) {
        sound4.setBuffer( buffer );
        sound4.setLoop(true);
        sound4.setVolume(0.02);
        sound4.play();
    });

    var ambient = new THREE.AmbientLight( 0x222222 );
    scene.add( ambient );
    var directionalLight = new THREE.DirectionalLight( 0xbbbbbb );
    directionalLight.position.set( 0, 200, 50 ).normalize();
    scene.add( directionalLight );

	createTractor()

}

let defaultMaterial,  highlightMaterial

function createTractor() {

    let objLoader = new THREE.OBJLoader()

    objLoader.setPath( 'src/home/obj/' )
    objLoader.load( 'tractorbody.obj', function ( object ) {

        var material = new THREE.MeshPhongMaterial( { color: 0xdd2211 } );

        object.traverse( function ( child ) {

            if ( child instanceof THREE.Mesh ) {

                child.material = material;

            }

        } );

		object.position.x = 0
		object.position.y = -6
		object.position.z = 1

		object.scale.x = 12
		object.scale.y = 12
		object.scale.z = 12

		scene.add( object )

	})

	objLoader.load( 'tracwheels.obj', function ( object ) {

		var material = new THREE.MeshLambertMaterial( { color: 0x333333 } );

		object.traverse( function ( child ) {

			if ( child instanceof THREE.Mesh ) {

				child.material = material;

			}

		} );

		object.position.x = 0
		object.position.y = -3.5
		object.position.z = -1.8

		object.scale.x = 12
		object.scale.y = 12
		object.scale.z = 12

		wheels = object

		scene.add( object )

	})

	// let panelUrl = require('./images/panel.png')
    //
	// let loader = new THREE.TextureLoader()
    //
	// loader.load(panelUrl, function(map){
	// 	// Now, create a Basic material; pass in the map
	// 	let material = new THREE.MeshBasicMaterial({ map: map })
	// 	// Create the cube geometry
	// 	let geometry = new THREE.PlaneGeometry(2, 2, 2)
	// 	// And put the geometry and material together into a mesh
	// 	plane = new THREE.Mesh(geometry, material)
	// 	// Move the mesh back from the camera and tilt it toward the viewer
	// 	plane.position.z = -2
	// 	plane.position.y = -1
	// 	plane.rotation.x = Math.PI / -4
	// 	// plane.rotation.y = Math.PI / 5
	// 	// Finally, add the mesh to our scene
	// 	scene.add(plane)
	// })
    //
	// let lookUrl = require('./images/look.png')
    //
	// loader.load(lookUrl, function(map){
	// 	// Now, create a Basic material; pass in the map
	// 	let material = new THREE.MeshBasicMaterial({ map: map })
	// 	// Create the cube geometry
	// 	let geometry = new THREE.CubeGeometry(0.5, 0.5, 0.5)
	// 	// And put the geometry and material together into a mesh
	// 	btn = new THREE.Mesh(geometry, material)
	// 	// Move the mesh back from the camera and tilt it toward the viewer
	// 	btn.position.z = -1.95
	// 	btn.position.y = -0.85
	// 	btn.rotation.x = Math.PI / -4
	// 	// plane.rotation.y = Math.PI / 5
	// 	// Finally, add the mesh to our scene
	// 	scene.add(btn)
	// })

	let panelUrl = require('./images/panel.png')

	let loader = new THREE.TextureLoader()

	loader.load(panelUrl, function(map){
		// Now, create a Basic material; pass in the map
		let material = new THREE.MeshBasicMaterial({ map: map })
		// Create the cube geometry
		let geometry = new THREE.PlaneGeometry(2, 2, 2)
		// And put the geometry and material together into a mesh
		plane = new THREE.Mesh(geometry, material)
		// Move the mesh back from the camera and tilt it toward the viewer
		plane.position.z = -2
					plane.position.y = -1
		plane.rotation.x = Math.PI / -4
		// plane.rotation.y = Math.PI / 5
		// Finally, add the mesh to our scene
		scene.add(plane)
	})

	let lookUrl = require('./images/look.png')

	loader.load(lookUrl, function(map){
		// Now, create a Basic material; pass in the map
		let material = defaultMaterial = new THREE.MeshBasicMaterial({ map: map })
		// Create the cube geometry
		let geometry = new THREE.CubeGeometry(0.5, 0.5, 0.5)
		// And put the geometry and material together into a mesh
		btn = new THREE.Mesh(geometry, material)

		rayInput.add(btn, () => {
			btn.material = highlightMaterial
		}, () => {
			btn.material = defaultMaterial
			video.play()
		}, () => {
			video.stop()
			wheelStahp()
		})

		// Move the mesh back from the camera and tilt it toward the viewer
		btn.position.z = -1.95
		btn.position.y = -0.85
		btn.rotation.x = Math.PI / -4
		// plane.rotation.y = Math.PI / 5
		// Finally, add the mesh to our scene
		scene.add(btn)
	})

	let higlightMapUrl = require('./images/look2.png')

	loader.load(higlightMapUrl, function (map) {
		// Now, create a Basic material; pass in the map
		highlightMaterial = new THREE.MeshBasicMaterial({map: map})
	})
}

function initVRControls() {
	// Set up VR camera controls
	controls = new THREE.DeviceOrientationControls(camera)
}

let duration = 10000; // ms
let currentTime = Date.now()

function animate() {
	if(!wheels || !wheelSpin){
		return
	}

	let now = Date.now()
	let deltat = now - currentTime
	currentTime = now
	let fract = deltat / duration
	let angle = Math.PI * 2 * fract
	wheels.rotation.x -= angle
}

function run() {
	requestAnimationFrame(run)

	if(VRMode){
		// ------------- CardBoard Mode ------------------
		// Render the scene
		effect.render( scene, camera )
	}else{
		// ---------------- Normal Mode ------------------
		renderer.render( scene, camera )
	}

	// Update the VR camera controls
	controls.update()

	// Update the ray input
	rayInput.update()

	// Spin the cube for next frame
	animate()
}

function wheelStahp() {
	wheelSpin = false
}

function bindEvents(){
	document.querySelector('#btn-vr').addEventListener('click', () => {
		VRMode = !VRMode

		if ( container.mozRequestFullScreen ) {
			container.mozRequestFullScreen()
		} else {
			container.webkitRequestFullscreen()
		}
	}, false)
}
<commit_msg>remove old code<commit_after>import './index.less'
import video from './video'
import rayInput from './rayInput'

let container = null
let	renderer = null
let	effect = null
let	controls = null
let	scene = null
let	camera = null
let	plane = null
let btn = null
let wheels = null
let	VRMode = false
let wheelSpin = true

// Set up Three.js
initThreeJS()
// Set up VR rendering
initVREffect()
// Create the scene content
initScene()
// Set up VR camera controls
initVRControls()

// init ray input
initRayInput()

// Run the run loop
run()
// Bind Dom Events
bindEvents()

function initThreeJS() {
	container = document.getElementById('container')
	// Create the Three.js renderer and attach it to our canvas
	renderer = new THREE.WebGLRenderer( { antialias: true } )
	// Set the viewport size
	renderer.setSize(window.innerWidth, window.innerHeight)
	container.appendChild(renderer.domElement)

	window.addEventListener('resize', function(event) {
		renderer.setSize(window.innerWidth, window.innerHeight)
	}, false)
}

function initRayInput() {
	rayInput.init(camera)
}

function initVREffect() {
// Set up Cardboard renderer
	effect = new THREE.StereoEffect(renderer)
	effect.setSize(window.innerWidth, window.innerHeight)

	// StereoEffect's default separation is in cm, we're in M
	// Actual cardboard eye separation is 2.5in
	// Finally, separation is per-eye so divide by 2
	effect.separation = 2.5 * 0.0254 / 2
}

function initScene() {
	// Create a new Three.js scene
	scene = new THREE.Scene()
	// Add  a camera so we can view the scene
	// Note that this camera's FOV is ignored in favor of the
	// Oculus-supplied FOV for each used inside VREffect.
	// See VREffect.js h/t Michael Blix
	camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 0.1, 4000 )

	scene.add(camera)

	scene.add(video.init())

    var listener = new THREE.AudioListener();
    camera.add( listener );
    var audioLoader = new THREE.AudioLoader();
    var sound4 = new THREE.Audio( listener );
    audioLoader.load( 'src/home/videos/tractor.mp3', function( buffer ) {
        sound4.setBuffer( buffer );
        sound4.setLoop(true);
        sound4.setVolume(0.02);
        sound4.play();
    });

    var ambient = new THREE.AmbientLight( 0x222222 );
    scene.add( ambient );
    var directionalLight = new THREE.DirectionalLight( 0xbbbbbb );
    directionalLight.position.set( 0, 200, 50 ).normalize();
    scene.add( directionalLight );

	createTractor()

}

let defaultMaterial,  highlightMaterial

function createTractor() {

    let objLoader = new THREE.OBJLoader()

    objLoader.setPath( 'src/home/obj/' )
    objLoader.load( 'tractorbody.obj', function ( object ) {

        var material = new THREE.MeshPhongMaterial( { color: 0xdd2211 } );

        object.traverse( function ( child ) {

            if ( child instanceof THREE.Mesh ) {

                child.material = material;

            }

        } );

		object.position.x = 0
		object.position.y = -6
		object.position.z = 1

		object.scale.x = 12
		object.scale.y = 12
		object.scale.z = 12

		scene.add( object )

	})

	objLoader.load( 'tracwheels.obj', function ( object ) {

		var material = new THREE.MeshLambertMaterial( { color: 0x333333 } );

		object.traverse( function ( child ) {

			if ( child instanceof THREE.Mesh ) {

				child.material = material;

			}

		} );

		object.position.x = 0
		object.position.y = -3.5
		object.position.z = -1.8

		object.scale.x = 12
		object.scale.y = 12
		object.scale.z = 12

		wheels = object

		scene.add( object )

	})

	let panelUrl = require('./images/panel.png')

	let loader = new THREE.TextureLoader()

	loader.load(panelUrl, function(map){
		// Now, create a Basic material; pass in the map
		let material = new THREE.MeshBasicMaterial({ map: map })
		// Create the cube geometry
		let geometry = new THREE.PlaneGeometry(2, 2, 2)
		// And put the geometry and material together into a mesh
		plane = new THREE.Mesh(geometry, material)
		// Move the mesh back from the camera and tilt it toward the viewer
		plane.position.z = -2
					plane.position.y = -1
		plane.rotation.x = Math.PI / -4
		// plane.rotation.y = Math.PI / 5
		// Finally, add the mesh to our scene
		scene.add(plane)
	})

	let lookUrl = require('./images/look.png')

	loader.load(lookUrl, function(map){
		// Now, create a Basic material; pass in the map
		let material = defaultMaterial = new THREE.MeshBasicMaterial({ map: map })
		// Create the cube geometry
		let geometry = new THREE.CubeGeometry(0.5, 0.5, 0.5)
		// And put the geometry and material together into a mesh
		btn = new THREE.Mesh(geometry, material)

		rayInput.add(btn, () => {
			btn.material = highlightMaterial
		}, () => {
			btn.material = defaultMaterial
			video.play()
		}, () => {
			video.stop()
			wheelStahp()
		})

		// Move the mesh back from the camera and tilt it toward the viewer
		btn.position.z = -1.95
		btn.position.y = -0.85
		btn.rotation.x = Math.PI / -4
		// plane.rotation.y = Math.PI / 5
		// Finally, add the mesh to our scene
		scene.add(btn)
	})

	let higlightMapUrl = require('./images/look2.png')

	loader.load(higlightMapUrl, function (map) {
		// Now, create a Basic material; pass in the map
		highlightMaterial = new THREE.MeshBasicMaterial({map: map})
	})
}

function initVRControls() {
	// Set up VR camera controls
	controls = new THREE.DeviceOrientationControls(camera)
}

let duration = 10000; // ms
let currentTime = Date.now()

function animate() {
	if(!wheels || !wheelSpin){
		return
	}

	let now = Date.now()
	let deltat = now - currentTime
	currentTime = now
	let fract = deltat / duration
	let angle = Math.PI * 2 * fract
	wheels.rotation.x -= angle
}

function run() {
	requestAnimationFrame(run)

	if(VRMode){
		// ------------- CardBoard Mode ------------------
		// Render the scene
		effect.render( scene, camera )
	}else{
		// ---------------- Normal Mode ------------------
		renderer.render( scene, camera )
	}

	// Update the VR camera controls
	controls.update()

	// Update the ray input
	rayInput.update()

	// Spin the cube for next frame
	animate()
}

function wheelStahp() {
	wheelSpin = false
}

function bindEvents(){
	document.querySelector('#btn-vr').addEventListener('click', () => {
		VRMode = !VRMode

		if ( container.mozRequestFullScreen ) {
			container.mozRequestFullScreen()
		} else {
			container.webkitRequestFullscreen()
		}
	}, false)
}
<|endoftext|>


<commit_before>
export default function(cfg) {
    return (
`<!doctype html>

    <meta charset="utf-8">
    <title>Webpack Visualizer</title>
    <meta name="description" content="Visualize and analyze your Webpack bundle to see which modules are taking up space and which might be duplicates." />
    <meta name="viewport" content="width=750, initial-scale=1"/>
    <link rel="stylesheet" href="style.css"/>

${cfg.appHTML}

`
    );
}
<commit_msg>removed exp code<commit_after>
export default function(cfg) {
    return (
`<!doctype html>

    <meta charset="utf-8">
    <title>Webpack Visualizer</title>
    <meta name="description" content="Visualize and analyze your Webpack bundle to see which modules are taking up space and which might be duplicates." />
    <meta name="viewport" content="width=750, initial-scale=1"/>
    <link rel="stylesheet" href="style.css"/>

${cfg.appHTML}

`
    );
}
<|endoftext|>


<commit_before>describe('sagui', function () {
  // TODO: add testing
  it('should be tested');
});
<commit_msg>Fixes linter error<commit_after>describe('sagui', function () {
  // TODO: add testing
  it('should be tested')
})
<|endoftext|>


<commit_before>D.import_port_flavour('dom-do-submit', {
  dir: 'out',
  outside_exit: function(ship) {
    if(this.element)
      this.element.submit()
  },
  outside_add: function() {
    this.element = document.getElementById(this.settings.thing)

    if(!this.element)
      return D.set_error('That dom thing ("' + this.settings.thing + '") is not present')

    if(!this.element.hasOwnProperty('innerText'))
      return D.set_error('That dom thing has no innerText')
  }
})
<commit_msg>innerText -> submit<commit_after>D.import_port_flavour('dom-do-submit', {
  dir: 'out',
  outside_exit: function(ship) {
    if(this.element)
      this.element.submit()
  },
  outside_add: function() {
    this.element = document.getElementById(this.settings.thing)

    if(!this.element)
      return D.set_error('That dom thing ("' + this.settings.thing + '") is not present')

    if(!this.element.hasOwnProperty('submit'))
      return D.set_error('That dom thing has no submit')
  }
})
<|endoftext|>


<commit_before>const h = require('hyperscript');
const tippy = require('tippy.js');

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

const formatContent = require('./format-content');
const collection = require('./collection');
const getPublications = require('./publications');

//Manage the creation and display of metadata HTML content
//Requires a valid name, cytoscape element, and parsedMetadata array
class MetadataTip {

  constructor(name, data, cyElement) {
    this.name = name;
    this.data = data.parsedMetadata;
    //Add an extra piece of metadata for proteins
    if(data.class === "macromolecule")
      this.data.push(["Search Link",data.label]);
    this.cyElement = cyElement;
    this.db = config.databases;
    this.viewStatus = {};
  }

  //Show Tippy Tooltip
  show(cy, callback) {
    //Get tooltip object from class
    let tooltip = this.tooltip;
    let tooltipExt = tooltip;
    let zoom= this.zoom;
    let isEdge=this.cyElement.isEdge();

    getPublications(this.data).then(function (data) {
      this.data = data;

      console.log(data);

      //Hide all other tooltips
      this.hideAll(cy);

      //If no tooltip exists create one
      if (!tooltip||(zoom!=cy.zoom()&&isEdge)) {
        zoom=cy.zoom();
        //Generate HTML
        let tooltipHTML = this.generateToolTip(zoom,isEdge,callback);
        let expandedHTML = this.generateExtendedToolTip(zoom,isEdge,callback);

        //Create tippy object
        let refObject = this.cyElement.popperRef();
        tooltip = tippy(refObject, { html: tooltipHTML, theme: 'light', interactive: true, trigger: 'manual', hideOnClick: false, arrow: true, placement: 'bottom',distance: isEdge? -25*zoom+7:10}).tooltips[0];
        tooltipExt = tippy(refObject, { html: expandedHTML, theme: 'light', interactive: true, trigger: 'manual', hideOnClick: false, arrow: true, placement: 'bottom',distance: isEdge?-25*zoom+7:10}).tooltips[0];

        //Save tooltips
        this.tooltip = tooltip;
        this.zoom=zoom;
        this.tooltipExt = tooltipExt;
      }

      //Show Tooltip
      tooltip.show();
      this.visible = true;
    }.bind(this));
  }

  //Validate the name of object and use Display Name as the fall back option
  validateName() {
    if (!(this.name)) {
      let displayName = this.data.filter(pair => pair[0] === 'Display Name');
      if (displayName.length > 0) { this.name = displayName[0][1].toString(); }
    }
  }

  //Generate HTML Elements for tooltips
  generateToolTip(zoom,isEdge,callback) {
    //Order the data array
    let data = collection.toTop(this.data, config.tooltipOrder);
    data = collection.toBottom(data, config.tooltipReverseOrder);

    if (!(data) || data.length === 0) {
      return formatContent.noDataWarning(this.name);
    }

    //Ensure name is not blank
    this.validateName();

    //Generate the expand field option
    const expandFunction = this.displayMore(zoom,isEdge);

    if (!(this.data)) { this.data = []; }
    return h('div.tooltip-image', [
      h('div.tooltip-heading', this.name),
      h('div.tooltip-internal', h('div', (data).map(item => formatContent.parseMetadata(item, true, expandFunction, this.name)), this))
    ]);
  }

  //Generate HTML Elements for the side bar
  generateExtendedToolTip(zoom,isEdge,callback) {
    //Order the data array
    let data = collection.toTop(this.data, config.tooltipOrder);
    data = collection.toBottom(data, config.tooltipReverseOrder);
    if (!(data)) data = [];

    if (!(data) || data.length === 0) {
      return formatContent.noDataWarning(this.name);
    }

    //Ensure name is not blank
    this.validateName();

    //Generate expansion and collapse functions
    const expandFunction = this.displayMore(zoom,isEdge);
    const collapseFunction = this.displayLess(zoom,isEdge);

    const getExpansionFunction = item => !this.isExpanded(item[0]) ? expandFunction : collapseFunction;

    if (!(this.data)) { this.data = []; }
    return h('div.tooltip-image', [
      h('div.tooltip-heading', this.name),
      h('div.tooltip-internal', h('div', (data).map(item => formatContent.parseMetadata(item, !this.isExpanded(item[0]), getExpansionFunction(item), this.name), this)))
    ]
    );
  }

  //Hide all tooltip objects
  hideAll(cy) {
    cy.elements().each(function (element) {
      var tempElement = element.scratch('_tooltip');
      if (tempElement && tempElement.isVisible()) { tempElement.hide(); }
    });
  }

  //Hide Tippy tooltip
  hide() {
    if (this.tooltip) {
      this.tooltip.hide();
      this.tooltipExt.hide();
    }
    this.visible = false;
    this.viewStatus = {};
  }

  //Destroy Tippy tooltip
  destroy() {
    if (this.tooltip) {
      this.tooltip.destroy(this.tooltip.store[0].popper);
      this.tooltip = null;
    }
  }

  //Get display status of tooltip
  isVisible() {
    return this.visible;
  }

  //Display the expanded tooltip
  expandToolTip(expansionObject, expansionField, fieldStatus,zoom,isEdge) {
    //Modify view status
    expansionObject.viewStatus[expansionField] = fieldStatus;

    //Hide existing tooltip
    const existingToolTip = expansionObject.tooltipExt;
    existingToolTip.hide();

    //Get tooltip objects
    let tooltip = expansionObject.tooltip;
    const expandedHTML = expansionObject.generateExtendedToolTip(zoom,isEdge);

    //Create tippy object
    let refObject = expansionObject.cyElement.popperRef();
    let tooltipExt = tippy(refObject, { html: expandedHTML,
      theme: 'light',
      interactive: true,
      trigger: 'manual',
      hideOnClick: false,
      arrow: true,
      placement: 'bottom',
      animation: 'shift',
      duration : 1,
      distance: isEdge? -25*zoom+7:10
    }).tooltips[0];

    //Hide and show
    tooltip.hide();
    tooltipExt.show();

    //Save extended tooltip
    expansionObject.tooltipExt = tooltipExt;
  }

  //Return a function that binds a tooltip to the expanded tooltip view
  displayMore(zoom,isEdge) {
    let that = this;
    return (field) => that.expandToolTip(that, field, true,zoom,isEdge);
  }

  //Return a function that binds an expanded tooltip to the minimized view.
  displayLess(zoom,isEdge) {
    let that = this;
    return (field) => that.expandToolTip(that, field, false,zoom,isEdge);
  }

  //Return the expansion status of a specified field
  isExpanded(field) {
    return this.viewStatus[field];
  }

}

module.exports = MetadataTip;<commit_msg>Removed console output line(s)<commit_after>const h = require('hyperscript');
const tippy = require('tippy.js');

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

const formatContent = require('./format-content');
const collection = require('./collection');
const getPublications = require('./publications');

//Manage the creation and display of metadata HTML content
//Requires a valid name, cytoscape element, and parsedMetadata array
class MetadataTip {

  constructor(name, data, cyElement) {
    this.name = name;
    this.data = data.parsedMetadata;
    //Add an extra piece of metadata for proteins
    if(data.class === "macromolecule")
      this.data.push(["Search Link",data.label]);
    this.cyElement = cyElement;
    this.db = config.databases;
    this.viewStatus = {};
  }

  //Show Tippy Tooltip
  show(cy, callback) {
    //Get tooltip object from class
    let tooltip = this.tooltip;
    let tooltipExt = tooltip;
    let zoom= this.zoom;
    let isEdge=this.cyElement.isEdge();

    getPublications(this.data).then(function (data) {
      this.data = data;

      //Hide all other tooltips
      this.hideAll(cy);

      //If no tooltip exists create one
      if (!tooltip||(zoom!=cy.zoom()&&isEdge)) {
        zoom=cy.zoom();
        //Generate HTML
        let tooltipHTML = this.generateToolTip(zoom,isEdge,callback);
        let expandedHTML = this.generateExtendedToolTip(zoom,isEdge,callback);

        //Create tippy object
        let refObject = this.cyElement.popperRef();
        tooltip = tippy(refObject, { html: tooltipHTML, theme: 'light', interactive: true, trigger: 'manual', hideOnClick: false, arrow: true, placement: 'bottom',distance: isEdge? -25*zoom+7:10}).tooltips[0];
        tooltipExt = tippy(refObject, { html: expandedHTML, theme: 'light', interactive: true, trigger: 'manual', hideOnClick: false, arrow: true, placement: 'bottom',distance: isEdge?-25*zoom+7:10}).tooltips[0];

        //Save tooltips
        this.tooltip = tooltip;
        this.zoom=zoom;
        this.tooltipExt = tooltipExt;
      }

      //Show Tooltip
      tooltip.show();
      this.visible = true;
    }.bind(this));
  }

  //Validate the name of object and use Display Name as the fall back option
  validateName() {
    if (!(this.name)) {
      let displayName = this.data.filter(pair => pair[0] === 'Display Name');
      if (displayName.length > 0) { this.name = displayName[0][1].toString(); }
    }
  }

  //Generate HTML Elements for tooltips
  generateToolTip(zoom,isEdge,callback) {
    //Order the data array
    let data = collection.toTop(this.data, config.tooltipOrder);
    data = collection.toBottom(data, config.tooltipReverseOrder);

    if (!(data) || data.length === 0) {
      return formatContent.noDataWarning(this.name);
    }

    //Ensure name is not blank
    this.validateName();

    //Generate the expand field option
    const expandFunction = this.displayMore(zoom,isEdge);

    if (!(this.data)) { this.data = []; }
    return h('div.tooltip-image', [
      h('div.tooltip-heading', this.name),
      h('div.tooltip-internal', h('div', (data).map(item => formatContent.parseMetadata(item, true, expandFunction, this.name)), this))
    ]);
  }

  //Generate HTML Elements for the side bar
  generateExtendedToolTip(zoom,isEdge,callback) {
    //Order the data array
    let data = collection.toTop(this.data, config.tooltipOrder);
    data = collection.toBottom(data, config.tooltipReverseOrder);
    if (!(data)) data = [];

    if (!(data) || data.length === 0) {
      return formatContent.noDataWarning(this.name);
    }

    //Ensure name is not blank
    this.validateName();

    //Generate expansion and collapse functions
    const expandFunction = this.displayMore(zoom,isEdge);
    const collapseFunction = this.displayLess(zoom,isEdge);

    const getExpansionFunction = item => !this.isExpanded(item[0]) ? expandFunction : collapseFunction;

    if (!(this.data)) { this.data = []; }
    return h('div.tooltip-image', [
      h('div.tooltip-heading', this.name),
      h('div.tooltip-internal', h('div', (data).map(item => formatContent.parseMetadata(item, !this.isExpanded(item[0]), getExpansionFunction(item), this.name), this)))
    ]
    );
  }

  //Hide all tooltip objects
  hideAll(cy) {
    cy.elements().each(function (element) {
      var tempElement = element.scratch('_tooltip');
      if (tempElement && tempElement.isVisible()) { tempElement.hide(); }
    });
  }

  //Hide Tippy tooltip
  hide() {
    if (this.tooltip) {
      this.tooltip.hide();
      this.tooltipExt.hide();
    }
    this.visible = false;
    this.viewStatus = {};
  }

  //Destroy Tippy tooltip
  destroy() {
    if (this.tooltip) {
      this.tooltip.destroy(this.tooltip.store[0].popper);
      this.tooltip = null;
    }
  }

  //Get display status of tooltip
  isVisible() {
    return this.visible;
  }

  //Display the expanded tooltip
  expandToolTip(expansionObject, expansionField, fieldStatus,zoom,isEdge) {
    //Modify view status
    expansionObject.viewStatus[expansionField] = fieldStatus;

    //Hide existing tooltip
    const existingToolTip = expansionObject.tooltipExt;
    existingToolTip.hide();

    //Get tooltip objects
    let tooltip = expansionObject.tooltip;
    const expandedHTML = expansionObject.generateExtendedToolTip(zoom,isEdge);

    //Create tippy object
    let refObject = expansionObject.cyElement.popperRef();
    let tooltipExt = tippy(refObject, { html: expandedHTML,
      theme: 'light',
      interactive: true,
      trigger: 'manual',
      hideOnClick: false,
      arrow: true,
      placement: 'bottom',
      animation: 'shift',
      duration : 1,
      distance: isEdge? -25*zoom+7:10
    }).tooltips[0];

    //Hide and show
    tooltip.hide();
    tooltipExt.show();

    //Save extended tooltip
    expansionObject.tooltipExt = tooltipExt;
  }

  //Return a function that binds a tooltip to the expanded tooltip view
  displayMore(zoom,isEdge) {
    let that = this;
    return (field) => that.expandToolTip(that, field, true,zoom,isEdge);
  }

  //Return a function that binds an expanded tooltip to the minimized view.
  displayLess(zoom,isEdge) {
    let that = this;
    return (field) => that.expandToolTip(that, field, false,zoom,isEdge);
  }

  //Return the expansion status of a specified field
  isExpanded(field) {
    return this.viewStatus[field];
  }

}

module.exports = MetadataTip;<|endoftext|>


<commit_before>/**
 * 限制输入框 v0.1beta
 * 基于jquery简单实现文本框输入限制
 * @auther Maxith chou
 */
$(document).ready(function(){bindInput();});
function bindInput(){
	var all = document.all ? document.all : $('input[type="text"]'),doms = new Array();
	for (var i = 0; i < all.length; i++) {
		var type = $(all[i]).attr('inputLimit');
		if(type != null){
			doms[doms.length] = all[i];
		}
	}
	for (var i = 0; i < doms.length; i++) {
		var item = doms[i],type = $(item).attr('inputLimit');
		switch (type){
			case 'number_only':
				item.onkeypress = function(event){
					var e = window.event||event,
						code = e.keyCode || e.which;
					return code>=48&&code<=57;
				};
				item.onblur = function(event){
					if(this.value.lastIndexOf(".")==(this.value.length-1)){
		                this.value = this.value.substr(0,this.value.length-1);
	                }else if(isNaN(this.value)){
	                    this.value = "";
	                }
				};
				item.onpaste = function(event){
					var s=clipboardData.getData('text');
	                if(!/\D/.test(s));
	                value=s.replace(/^0*/,'');
	                return false;
				};
				item.ondragenter = function(event){
					return false;
				};
				item.onkeyup = function(event){
					if(this.value.length >= 2){
						if(/(^0+)/.test(this.value))this.value=this.value.replace(/^0*/, '');
					}
				};
				break;
			case 'number_decimal':
				item.onkeypress = function(event){
					var e = window.event||event,
						code = e.keyCode || e.which;
					if(code == 46){
						if(this.value.length < 1){
							return false;
						}
	                    if(this.value.indexOf(".")!= -1){
	                        return false;
	                    }
	                }else{
	                    return code == 46||code>=48&&code<=57;
	                }
				};
				item.onblur = function(event){
					if(this.value.lastIndexOf(".")==(this.value.length-1)){
		                this.value = this.value.substr(0,this.value.length-1);
	                }else if(isNaN(this.value)){
	                    this.value = "";
	                }
				};
				item.onpaste = function(event){
					var s=clipboardData.getData('text');
	                if(!/\D/.test(s));
	                value=s.replace(/^0*/,'');
	                return false;
				};
				item.ondragenter = function(event){
					return false;
				};
				item.onkeyup = function(event){
					if(this.value.indexOf(".") == -1){
						if(this.value.length >= 2){
							if(/(^0+)/.test(this.value))this.value=this.value.replace(/^0*/, '');
						}
					}else{
						if(this.value.length == 1){
							this.value = '';
						}
					}
				};
				break;
			case 'number_integer':
				item.onkeypress = function(event){
					var e = window.event||event,
						code = e.keyCode || e.which;
					if(code == 45){
	                    if(getCursorPosition(this) > 0){
	                    	return false;
	                    }
						if(this.value.indexOf("-")!=-1){
	                        return false;
	                    }
	                }
					return code == 45||code>=48&&code<=57;
				};
				item.onblur = function(event){
					if(this.value.lastIndexOf(".")==(this.value.length-1)){
		                this.value = this.value.substr(0,this.value.length-1);
	                }else if(isNaN(this.value)){
	                    this.value = "";
	                }
				};
				item.onpaste = function(event){
					var s=clipboardData.getData('text');
	                if(!/\D/.test(s));
	                value=s.replace(/^0*/,'');
	                return false;
				};
				item.ondragenter = function(event){
					return false;
				};
				item.onkeyup = function(event){
					if(this.value.length >= 2){
						if(/(^0+)/.test(this.value))this.value=this.value.replace(/^0*/, '');
					}
				};
				break;
				//TODO 其余类型限制
		}
	}
}
/**
 * 光标位置判断
 */
function getCursorPosition(el){
     var pos = 0;
     if ('selectionStart' in el) {
         pos = el.selectionStart;
     } else if ('selection' in document) {
         el.focus();
         var Sel = document.selection.createRange();
         var SelLength = document.selection.createRange().text.length;
         Sel.moveStart('character', -el.value.length);
         pos = Sel.text.length - SelLength;
     }
     return pos;
 }
<commit_msg>全新版本~~<commit_after>/**
 * 限制输入框 v0.2
 * 基于jquery简单实现文本框输入限制
 *
 * 	我系渣渣辉,介系里没有挽过的船新版本,挤需体验三番钟，里造会汗我一样，爱象借款插件
 *
 * @auther Maxith chou
 * @date 2018年2月6日
 */
//正整数
$(document).on({
    keypress: function (event) {
        var e = window.event || event,
            code = e.keyCode || e.which;
        if (code == 46) {
            if (this.value.length < 1) {
                return false;
            }
            if (this.value.indexOf(".") != -1) {
                return false;
            }
        } else {
            if (this.value.length != 0 && this.value.indexOf(".") != -1
                && (this.value.length - this.value.indexOf(".")) > 2
                && (getCursorPosition(this) - this.value.indexOf(".")) > 0) {
                return false;
            }
            return code == 46 || code >= 48 && code <= 57;
        }
    },
    blur: function (event) {
        if (this.value.lastIndexOf(".") == 0) {
            this.value = '0' + this.value;
        }
        if (this.value.lastIndexOf(".") == (this.value.length - 1)) {
            this.value = this.value.substr(0, this.value.length - 1);
        } else if (isNaN(this.value)) {
            this.value = "";
        }
    },
    paste: function (event) {
        var s = event.originalEvent.clipboardData.getData('text');
        if (!/\D/.test(s)) ;
        this.value = s.replace(/^0*/, '');
        return false;
    },
    dragenter: function (event) {
        return false;
    },
    keyup: function (event) {
        if (this.value.indexOf(".") == -1) {
            if (this.value.length >= 2) {
                if (/(^0+)/.test(this.value)) this.value = this.value.replace(/^0*/, '');
            }
        } else {
            if (this.value.length == 1) {
                this.value = '';
            }
        }
    }
}, '.input-limit-positive');

//负整数
$(document).on({
    keypress: function (event) {
        var e = window.event || event,
            code = e.keyCode || e.which;
        if (code == 46) {
            if (this.value.length < 1) {
                return false;
            }
            if (this.value.indexOf(".") != -1) {
                return false;
            }
        } else if (code == 45) {
            if (getCursorPosition(this) > 0) {
                return false;
            }
            if (this.value.indexOf("-") != -1) {
                return false;
            }
        } else {
            if (this.value.length != 0 && this.value.indexOf(".") != -1
                && (this.value.length - this.value.indexOf(".")) > 2
                && (getCursorPosition(this) - this.value.indexOf(".")) > 0) {
                return false;
            }
            return code == 45 || code == 46 || code >= 48 && code <= 57;
        }
    },
    blur: function (event) {
        if (this.value.lastIndexOf(".") == 0) {
            this.value = '0' + this.value;
        }
        if (this.value.lastIndexOf(".") == (this.value.length - 1)) {
            this.value = this.value.substr(0, this.value.length - 1);
        } else if (isNaN(this.value)) {
            this.value = "";
        }
    },
    paste: function (event) {
        var s = event.originalEvent.clipboardData.getData('text');
        if (!/\D/.test(s)) ;
        this.value = s.replace(/^0*/, '');
        return false;
    },
    dragenter: function (event) {
        return false;
    },
    keyup: function (event) {
        if (this.value.indexOf(".") == -1) {
            if (this.value.length >= 2) {
                if (/(^0+)/.test(this.value)) this.value = this.value.replace(/^0*/, '');
            }
        } else {
            if (this.value.length == 1) {
                this.value = '';
            }
        }
    }
}, '.input-limit-minus');

$(document).on({
    keypress: function (event) {
        var e = window.event || event,
            code = e.keyCode || e.which;
        if (code == 46) {
            if (this.value.length < 1) {
                return false;
            }
            if (this.value.indexOf(".") != -1) {
                return false;
            }
        } else {
            return code == 46 || code >= 48 && code <= 57;
        }
    },
    blur: function (event) {
        if (this.value.lastIndexOf(".") == (this.value.length - 1)) {
            this.value = this.value.substr(0, this.value.length - 1);
        } else if (isNaN(this.value)) {
            this.value = "";
        }
    },
    paste: function (event) {
        var s = event.originalEvent.event.originalEvent.clipboardData.getData('text');
        if (!/\D/.test(s)) ;
        this.value = s.replace(/^0*/, '');
        return false;
    },
    dragenter: function (event) {
        return false;
    },
    keyup: function (event) {
        if (this.value.indexOf(".") == -1) {
            if (this.value.length >= 2) {
                if (/(^0+)/.test(this.value)) this.value = this.value.replace(/^0*/, '');
            }
        } else {
            if (this.value.length == 1) {
                this.value = '';
            }
        }
    }
}, 'input-limit-decimal');
/**
 * 光标位置判断
 */
function getCursorPosition(el){
    var pos = 0;
    if ('selectionStart' in el) {
        pos = el.selectionStart;
    } else if ('selection' in document) {
        el.focus();
        var Sel = document.selection.createRange();
        var SelLength = document.selection.createRange().text.length;
        Sel.moveStart('character', -el.value.length);
        pos = Sel.text.length - SelLength;
    }
    return pos;
}
<|endoftext|>