<commit_before>/*   Copyright 2017 Agneta Network Applications, LLC.
 *
 *   Source file: services/middleware/token.js
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
var _ = require('lodash');

module.exports = function(app) {

  function rewriteUserLiteral(req, currentUserLiteral) {
    if (req.accessToken && req.accessToken.userId && currentUserLiteral) {
      // Replace /me/ with /current-user-id/
      var urlBeforeRewrite = req.url;
      req.url = req.url.replace(
        new RegExp('/' + currentUserLiteral + '(/|$|\\?)', 'g'),
        '/' + req.accessToken.userId + '$1');
      if (req.url !== urlBeforeRewrite) {
        //debug('req.url has been rewritten from %s to %s', urlBeforeRewrite,  req.url);
      }
    }
  }

  function escapeRegExp(str) {
    return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }

  var name = app.get('token').name;

  var options = {
    searchDefaultTokenKeys: false,
    cookies: [name],
    headers: [name],
    params: [name]
  };

  var currentUserLiteral = options.currentUserLiteral;
  if (currentUserLiteral && (typeof currentUserLiteral !== 'string')) {
    //debug('Set currentUserLiteral to \'me\' as the value is not a string.');
    currentUserLiteral = 'me';
  }
  if (typeof currentUserLiteral === 'string') {
    currentUserLiteral = escapeRegExp(currentUserLiteral);
  }

  function middleware(req, res, next) {

    req.accessTokens = req.accessTokens || {};

    if (req.accessToken === undefined) {
      Object.defineProperty(req, 'accessToken', {
        get: function() {
          var key = req.app.get('token').name;
          return req.accessTokens[key] || null;
        }
      });
    }

    app.models.AccessToken.findForRequest(req, options, function(err, token) {
      if (err) {
        return next(err);
      }

      if (!token || !app.roles) {
        return next();
      }

      app.models.Account.findById(token.userId, {
        include: app.roles.include,
        fields: {
          id: true
        }
      })
        .then(function(account) {
          if (!account) {
            return next('Account not found from access token');
          }

          save({
            account: account,
            token: token,
            req: req
          });

        })
        .asCallback(next);
    });

  }

  function save(options){

    var account = options.account;
    var token = options.token;
    var req = options.req;

    var roles = _.omit(account.__data, 'id');
    roles = _.mapValues(roles, function(value) {
      return value.id;
    });

    token = token.__data;
    token.roles = roles;

    //console.log('middleware:token:save',name,token);

    req.accessTokens[name] = token || null;
    rewriteUserLiteral(req, currentUserLiteral);
  }

  app.token = {
    middleware: middleware,
    save: save
  };

  return middleware;

};
<commit_msg>Check account ip for whitelist<commit_after>/*   Copyright 2017 Agneta Network Applications, LLC.
 *
 *   Source file: services/middleware/token.js
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
var _ = require('lodash');

module.exports = function(app) {

  function rewriteUserLiteral(req, currentUserLiteral) {
    if (req.accessToken && req.accessToken.userId && currentUserLiteral) {
      // Replace /me/ with /current-user-id/
      var urlBeforeRewrite = req.url;
      req.url = req.url.replace(
        new RegExp('/' + currentUserLiteral + '(/|$|\\?)', 'g'),
        '/' + req.accessToken.userId + '$1');
      if (req.url !== urlBeforeRewrite) {
        //debug('req.url has been rewritten from %s to %s', urlBeforeRewrite,  req.url);
      }
    }
  }

  function escapeRegExp(str) {
    return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }

  var name = app.get('token').name;

  var options = {
    searchDefaultTokenKeys: false,
    cookies: [name],
    headers: [name],
    params: [name]
  };

  var currentUserLiteral = options.currentUserLiteral;
  if (currentUserLiteral && (typeof currentUserLiteral !== 'string')) {
    //debug('Set currentUserLiteral to \'me\' as the value is not a string.');
    currentUserLiteral = 'me';
  }
  if (typeof currentUserLiteral === 'string') {
    currentUserLiteral = escapeRegExp(currentUserLiteral);
  }

  function middleware(req, res, next) {

    req.accessTokens = req.accessTokens || {};

    if (req.accessToken === undefined) {
      Object.defineProperty(req, 'accessToken', {
        get: function() {
          var key = req.app.get('token').name;
          return req.accessTokens[key] || null;
        }
      });
    }

    app.models.AccessToken.findForRequest(req, options, function(err, token) {
      if (err) {
        return next(err);
      }

      if (!token || !app.roles) {
        return next();
      }

      var account;

      app.models.Account.findById(token.userId, {
        include: app.roles.include,
        fields: {
          id: true,
          _ip_whitelist: true
        }
      })
        .then(function(_account) {
          account = _account;
          if (!account) {
            return Promise.reject('Account not found from access token');
          }

          var ip = req.ip || req.connection.remoteAddress;
          //console.log(account._ip_whitelist,ip);

          if(process.env.NODE_ENV == 'development' && ip=='::1'){
            return;
          }

          if(account._ip_whitelist && account._ip_whitelist.length){
            var match = _.find(account._ip_whitelist,{address:ip});
            if(!match){
              return Promise.reject('Account cannot be accessed with your IP');
            }
          }

        })
        .then(function() {

          save({
            account: account,
            token: token,
            req: req
          });

        })
        .asCallback(next);
    });

  }

  function save(options){

    var account = options.account;
    var token = options.token;
    var req = options.req;

    var roles = _.omit(account.__data, 'id');
    roles = _.mapValues(roles, function(value) {
      return value.id;
    });

    token = token.__data;
    token.roles = roles;

    //console.log('middleware:token:save',name,token);

    req.accessTokens[name] = token || null;
    rewriteUserLiteral(req, currentUserLiteral);
  }

  app.token = {
    middleware: middleware,
    save: save
  };

  return middleware;

};
<|endoftext|>


<commit_before>/*!
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const common = require('@google-cloud/common');
const is = require('is');

/**
 * Create a cluster object to interact with your cluster.
 *
 * @class
 * @param {Instance} instance The parent instance of this cluster.
 * @param {string} id Id of the cluster.
 *
 * @example
 * const Bigtable = require('@google-cloud/bigtable');
 * const bigtable = new Bigtable();
 * const instance = bigtable.instance('my-instance');
 * const cluster = instance.cluster('my-cluster');
 */
class Cluster {
  constructor(instance, id) {
    this.bigtable = instance.bigtable;
    this.instance = instance;

    var name;

    if (id.includes('/')) {
      if (id.includes(`${instance.name}/clusters/`)) {
        name = id;
      } else {
        throw new Error(
          `Cluster id '${id}' is not formatted correctly.
Please use the format 'my-cluster' or '${instance.name}/clusters/my-cluster'.`
        );
      }
    } else {
      name = `${instance.name}/clusters/${id}`;
    }
    this.id = name.split('/').pop();
    this.name = name;
  }

  /**
   * Formats zone location.
   *
   * @private
   *
   * @param {string} project The project ID.
   * @param {string} location The zone location.
   * @returns {string}
   *
   * @example
   * Cluster.getLocation_('my-project', 'us-central1-b');
   * // 'projects/my-project/locations/us-central1-b'
   */
  static getLocation_(project, location) {
    if (location.includes('/')) {
      return location;
    }

    // in-case project has '/', split and pick last component
    if (project.includes('/')) {
      project = project.split('/').pop();
    }

    return `projects/${project}/locations/${location}`;
  }

  /**
   * Maps the storage type to the proper integer.
   *
   * @private
   *
   * @param {string} type The storage type (hdd, ssd).
   * @returns {number}
   *
   * @example
   * Cluster.getStorageType_('ssd');
   * // 1
   */
  static getStorageType_(type) {
    const storageTypes = {
      unspecified: 0,
      ssd: 1,
      hdd: 2,
    };

    if (is.string(type)) {
      type = type.toLowerCase();
    }

    return storageTypes[type] || storageTypes.unspecified;
  }

  /**
   * Create a cluster.
   *
   * @param {object} [options] See {@link Instance#createCluster}.
   * @param {function} [callback] The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * const Bigtable = require('@google-cloud/bigtable');
   * const bigtable = new Bigtable();
   * const instance = bigtable.instance('my-instance');
   * const cluster = instance.cluster('my-cluster');
   *
   * cluster.create(function(err, cluster, operation, apiResponse) {
   *   if (err) {
   *     // Error handling omitted.
   *   }
   *
   *   operation
   *     .on('error', console.error)
   *     .on('complete', function() {
   *       // The cluster was created successfully.
   *     });
   * });
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.create().then(function(data) {
   *   const cluster = data[0];
   *   const operation = data[1];
   *   const apiResponse = data[2];
   * });
   */
  create(options, callback) {
    if (is.fn(options)) {
      callback = options;
      options = {};
    }

    this.instance.createCluster(this.id, options, callback);
  }

  /**
   * Delete the cluster.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} [callback] The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * cluster.delete(function(err, apiResponse) {});
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.delete().then(function(data) {
   *   var apiResponse = data[0];
   * });
   */
  delete(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.bigtable.request(
      {
        client: 'BigtableInstanceAdminClient',
        method: 'deleteCluster',
        reqOpts: {
          name: this.name,
        },
        gaxOpts: gaxOptions,
      },
      callback
    );
  }

  /**
   * Check if a cluster exists.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {boolean} callback.exists Whether the cluster exists or not.
   *
   * @example
   * cluster.exists(function(err, exists) {});
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.exists().then(function(data) {
   *   var exists = data[0];
   * });
   */
  exists(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.getMetadata(gaxOptions, err => {
      if (err) {
        if (err.code === 5) {
          callback(null, false);
          return;
        }

        callback(err);
        return;
      }

      callback(null, true);
    });
  }

  /**
   * Get a cluster if it exists.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * cluster.get(function(err, cluster, apiResponse) {
   *   // The `cluster` data has been populated.
   * });
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.get().then(function(data) {
   *   var cluster = data[0];
   *   var apiResponse = data[1];
   * });
   */
  get(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.getMetadata(gaxOptions, (err, metadata) => {
      callback(err, err ? null : this, metadata);
    });
  }

  /**
   * Get the cluster metadata.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined
   *     here: https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.metadata The metadata.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * cluster.getMetadata(function(err, metadata, apiResponse) {});
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.getMetadata().then(function(data) {
   *   var metadata = data[0];
   *   var apiResponse = data[1];
   * });
   */
  getMetadata(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.bigtable.request(
      {
        client: 'BigtableInstanceAdminClient',
        method: 'getCluster',
        reqOpts: {
          name: this.name,
        },
        gaxOpts: gaxOptions,
      },
      (...args) => {
        if (args[1]) {
          this.metadata = args[1];
        }

        callback(...args);
      }
    );
  }

  /**
   * Set the cluster metadata.
   *
   * @param {object} metadata See {@link Instance#createCluster} for the
   *     available metadata options.
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this request.
   * @param {Operation} callback.operation An operation object that can be used
   *     to check the status of the request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * const Bigtable = require('@google-cloud/bigtable');
   * const bigtable = new Bigtable();
   * const instance = bigtable.instance('my-instance');
   * const cluster = instance.cluster('my-cluster');
   *
   * const callback = function(err, operation, apiResponse) {
   *   if (err) {
   *     // Error handling omitted.
   *   }
   *
   *   operation
   *     .on('error', console.error)
   *     .on('complete', function() {
   *       // The cluster was updated successfully.
   *     });
   * };
   *
   * const metadata = {
   *   location: 'us-central1-b',
   *   nodes: 3,
   *   storage: 'ssd'
   * };
   *
   * cluster.setMetadata(metadata, callback);
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.setMetadata(metadata).then(function(data) {
   *   const operation = data[0];
   *   const apiResponse = data[1];
   * });
   */
  setMetadata(metadata, gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    const reqOpts = {
      name: this.name,
    };

    if (metadata.location) {
      reqOpts.location = Cluster.getLocation_(
        this.bigtable.projectId,
        metadata.location
      );
    }

    if (metadata.nodes) {
      reqOpts.serveNodes = metadata.nodes;
    }

    if (metadata.storage) {
      reqOpts.defaultStorageType = Cluster.getStorageType_(metadata.storage);
    }

    this.bigtable.request(
      {
        client: 'BigtableInstanceAdminClient',
        method: 'updateCluster',
        reqOpts,
        gaxOpts: gaxOptions,
      },
      callback
    );
  }
}

/*! Developer Documentation
 *
 * All async methods (except for streams) will return a Promise in the event
 * that a callback is omitted.
 */
common.util.promisifyAll(Cluster);

/**
 * Reference to the {@link Cluster} class.
 * @name module:@google-cloud/bigtable.Cluster
 * @see Cluster
 */
module.exports = Cluster;
<commit_msg>Remove id<->name check for cluster since its not done anywhere else (#188)<commit_after>/*!
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const common = require('@google-cloud/common');
const is = require('is');

/**
 * Create a cluster object to interact with your cluster.
 *
 * @class
 * @param {Instance} instance The parent instance of this cluster.
 * @param {string} id Id of the cluster.
 *
 * @example
 * const Bigtable = require('@google-cloud/bigtable');
 * const bigtable = new Bigtable();
 * const instance = bigtable.instance('my-instance');
 * const cluster = instance.cluster('my-cluster');
 */
class Cluster {
  constructor(instance, id) {
    this.bigtable = instance.bigtable;
    this.instance = instance;

    const name = `${instance.name}/clusters/${id}`;
    this.id = name.split('/').pop();
    this.name = name;
  }

  /**
   * Formats zone location.
   *
   * @private
   *
   * @param {string} project The project ID.
   * @param {string} location The zone location.
   * @returns {string}
   *
   * @example
   * Cluster.getLocation_('my-project', 'us-central1-b');
   * // 'projects/my-project/locations/us-central1-b'
   */
  static getLocation_(project, location) {
    if (location.includes('/')) {
      return location;
    }

    // in-case project has '/', split and pick last component
    if (project.includes('/')) {
      project = project.split('/').pop();
    }

    return `projects/${project}/locations/${location}`;
  }

  /**
   * Maps the storage type to the proper integer.
   *
   * @private
   *
   * @param {string} type The storage type (hdd, ssd).
   * @returns {number}
   *
   * @example
   * Cluster.getStorageType_('ssd');
   * // 1
   */
  static getStorageType_(type) {
    const storageTypes = {
      unspecified: 0,
      ssd: 1,
      hdd: 2,
    };

    if (is.string(type)) {
      type = type.toLowerCase();
    }

    return storageTypes[type] || storageTypes.unspecified;
  }

  /**
   * Create a cluster.
   *
   * @param {object} [options] See {@link Instance#createCluster}.
   * @param {function} [callback] The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * const Bigtable = require('@google-cloud/bigtable');
   * const bigtable = new Bigtable();
   * const instance = bigtable.instance('my-instance');
   * const cluster = instance.cluster('my-cluster');
   *
   * cluster.create(function(err, cluster, operation, apiResponse) {
   *   if (err) {
   *     // Error handling omitted.
   *   }
   *
   *   operation
   *     .on('error', console.error)
   *     .on('complete', function() {
   *       // The cluster was created successfully.
   *     });
   * });
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.create().then(function(data) {
   *   const cluster = data[0];
   *   const operation = data[1];
   *   const apiResponse = data[2];
   * });
   */
  create(options, callback) {
    if (is.fn(options)) {
      callback = options;
      options = {};
    }

    this.instance.createCluster(this.id, options, callback);
  }

  /**
   * Delete the cluster.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} [callback] The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * cluster.delete(function(err, apiResponse) {});
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.delete().then(function(data) {
   *   var apiResponse = data[0];
   * });
   */
  delete(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.bigtable.request(
      {
        client: 'BigtableInstanceAdminClient',
        method: 'deleteCluster',
        reqOpts: {
          name: this.name,
        },
        gaxOpts: gaxOptions,
      },
      callback
    );
  }

  /**
   * Check if a cluster exists.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {boolean} callback.exists Whether the cluster exists or not.
   *
   * @example
   * cluster.exists(function(err, exists) {});
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.exists().then(function(data) {
   *   var exists = data[0];
   * });
   */
  exists(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.getMetadata(gaxOptions, err => {
      if (err) {
        if (err.code === 5) {
          callback(null, false);
          return;
        }

        callback(err);
        return;
      }

      callback(null, true);
    });
  }

  /**
   * Get a cluster if it exists.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * cluster.get(function(err, cluster, apiResponse) {
   *   // The `cluster` data has been populated.
   * });
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.get().then(function(data) {
   *   var cluster = data[0];
   *   var apiResponse = data[1];
   * });
   */
  get(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.getMetadata(gaxOptions, (err, metadata) => {
      callback(err, err ? null : this, metadata);
    });
  }

  /**
   * Get the cluster metadata.
   *
   * @param {object} [gaxOptions] Request configuration options, outlined
   *     here: https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this
   *     request.
   * @param {object} callback.metadata The metadata.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * cluster.getMetadata(function(err, metadata, apiResponse) {});
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.getMetadata().then(function(data) {
   *   var metadata = data[0];
   *   var apiResponse = data[1];
   * });
   */
  getMetadata(gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    this.bigtable.request(
      {
        client: 'BigtableInstanceAdminClient',
        method: 'getCluster',
        reqOpts: {
          name: this.name,
        },
        gaxOpts: gaxOptions,
      },
      (...args) => {
        if (args[1]) {
          this.metadata = args[1];
        }

        callback(...args);
      }
    );
  }

  /**
   * Set the cluster metadata.
   *
   * @param {object} metadata See {@link Instance#createCluster} for the
   *     available metadata options.
   * @param {object} [gaxOptions] Request configuration options, outlined here:
   *     https://googleapis.github.io/gax-nodejs/CallSettings.html.
   * @param {function} callback The callback function.
   * @param {?error} callback.err An error returned while making this request.
   * @param {Operation} callback.operation An operation object that can be used
   *     to check the status of the request.
   * @param {object} callback.apiResponse The full API response.
   *
   * @example
   * const Bigtable = require('@google-cloud/bigtable');
   * const bigtable = new Bigtable();
   * const instance = bigtable.instance('my-instance');
   * const cluster = instance.cluster('my-cluster');
   *
   * const callback = function(err, operation, apiResponse) {
   *   if (err) {
   *     // Error handling omitted.
   *   }
   *
   *   operation
   *     .on('error', console.error)
   *     .on('complete', function() {
   *       // The cluster was updated successfully.
   *     });
   * };
   *
   * const metadata = {
   *   location: 'us-central1-b',
   *   nodes: 3,
   *   storage: 'ssd'
   * };
   *
   * cluster.setMetadata(metadata, callback);
   *
   * //-
   * // If the callback is omitted, we'll return a Promise.
   * //-
   * cluster.setMetadata(metadata).then(function(data) {
   *   const operation = data[0];
   *   const apiResponse = data[1];
   * });
   */
  setMetadata(metadata, gaxOptions, callback) {
    if (is.fn(gaxOptions)) {
      callback = gaxOptions;
      gaxOptions = {};
    }

    const reqOpts = {
      name: this.name,
    };

    if (metadata.location) {
      reqOpts.location = Cluster.getLocation_(
        this.bigtable.projectId,
        metadata.location
      );
    }

    if (metadata.nodes) {
      reqOpts.serveNodes = metadata.nodes;
    }

    if (metadata.storage) {
      reqOpts.defaultStorageType = Cluster.getStorageType_(metadata.storage);
    }

    this.bigtable.request(
      {
        client: 'BigtableInstanceAdminClient',
        method: 'updateCluster',
        reqOpts,
        gaxOpts: gaxOptions,
      },
      callback
    );
  }
}

/*! Developer Documentation
 *
 * All async methods (except for streams) will return a Promise in the event
 * that a callback is omitted.
 */
common.util.promisifyAll(Cluster);

/**
 * Reference to the {@link Cluster} class.
 * @name module:@google-cloud/bigtable.Cluster
 * @see Cluster
 */
module.exports = Cluster;
<|endoftext|>


<commit_before>/*
*
* Description:
* This script is the Node.js server for OpenROV.  It creates a server and instantiates an OpenROV
* and sets the interval to grab frames.  The interval is set with the DELAY variable which is in
* milliseconds.
*
*/

//To eliminate hard coding paths for require, we are modifying the NODE_PATH to include
//out lib folder
var oldpath = '';
if (process.env['NODE_PATH']!==undefined){
 oldpath = process.env['NODE_PATH'];
}
//just in case already been set leave it alone
 process.env['NODE_PATH']=__dirname+'/lib:'+oldpath;
 require('module').Module._initPaths();
 console.log("Set NODE_PATH to: "+process.env['NODE_PATH'] );

var CONFIG = require('./lib/config');
var fs = require('fs');
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server, { log: false, origins: '*:*', path:'/cockpitsocket' });
var EventEmitter = require('events').EventEmitter;
var OpenROVController = require(CONFIG.OpenROVController);
var logger = require('./lib/logger').create(CONFIG);
var mkdirp = require('mkdirp');
var path = require('path');
var PluginLoader = require('./lib/PluginLoader');
var CockpitMessaging = require('./lib/CockpitMessaging');
var Q=require('q');
require('systemd');

var serveIndex = require('serve-index');
var favicon = require('serve-favicon');
var logger = require('morgan');
var methodOverride = require('method-override');
var session = require('express-session');
var bodyParser = require('body-parser');
var multer = require('multer');
var errorHandler = require('errorhandler');

var pluginFolder = CONFIG.preferences.get('pluginsDownloadDirectory');

app.use(express.static(__dirname + '/static/'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.set('port', process.env.LISTEN_FDS > 0 ? 'systemd' : CONFIG.port);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs', { pretty: true });
app.use(favicon(__dirname + '/static/favicon.ico'));
app.use(logger('dev'));
app.use('/components', express.static(path.join(__dirname, 'static/bower_components')));
app.use('/components', express.static(pluginFolder));
app.use('/components', express.static(path.join(__dirname, 'static/webcomponents')));

app.use('/components', express.static(path.join(__dirname,'plugins/telemetry/public/bower_components')));
app.use('/components/telemetry', express.static(path.join(__dirname,'plugins/telemetry/public/webcomponents')));
app.use('/components/telemetry', serveIndex(path.join(__dirname,'plugins/telemetry/public/webcomponents')));
console.log("!!!"+ path.join(__dirname, 'src/static/bower_components'));
// Keep track of plugins js and css to load them in the view
var scripts = [], styles = [], applets = [];
var sysscripts = [];

// setup required directories
mkdirp(CONFIG.preferences.get('photoDirectory'));
process.env.NODE_ENV = true;
var globalEventLoop = new EventEmitter();
var DELAY = Math.round(1000 / CONFIG.video_frame_rate);
io= require('./static/js/socketIOStoreAndForward.js')(io);
var client = new CockpitMessaging(io);
client = require('./static/js/eventEmitterStoreAndForward.js')(client);
var controller = new OpenROVController(globalEventLoop, client);

var pathInfo = function()
{
 return {
     scripts: scripts,
     styles: styles,
     sysscripts: sysscripts,
     applets: applets
 }
}

// Prepare dependency map for plugins
var deps = {
 server: server,
 app: app,
 rov: controller,
 cockpit: client,
 config: CONFIG,
 globalEventLoop: globalEventLoop,
 loadedPlugins: [],
 pathInfo: pathInfo
};

app.get('/config.js', function (req, res) {
 res.type('application/javascript');
 res.send('var CONFIG = ' + JSON.stringify(CONFIG));
});

//socket.io cross domain access
app.use(function (req, res, next) {
 res.header('Access-Control-Allow-Origin', '*');
 res.header('Access-Control-Allow-Headers', 'X-Requested-With');
 res.header('Access-Control-Allow-Headers', 'Content-Type');
 res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
 next();
});
var connections = 0;
// SOCKET connection ==============================
connections += 1;
if (connections == 1)
 controller.start();
// opens socket with client

deps.cockpit.on('disconnect', function () {
 connections -= 1;
 console.log('disconnect detected');
 if (connections === 0)
   controller.stop();
});
controller.on('rovsys', function (data) {
 deps.cockpit.emit('rovsys', data);
});

if (process.platform === 'linux') {
 process.on('SIGTERM', function () {
   console.error('got SIGTERM, shutting down...');
   process.exit(0);
 });
 process.on('SIGINT', function () {
   console.error('got SIGINT, shutting down...');
   process.exit(0);
 });
}

// Load the plugins
function addPluginAssets(result) {
 scripts = scripts.concat(result.scripts);
 console.log("====== Scripts ======")
 console.dir(result.scripts);
 result.scripts.forEach(function (asset) {
   console.log("SCRIPT: " + asset);
 });
 styles = styles.concat(result.styles);
 result.assets.forEach(function (asset) {
   console.log("TEST: " + asset.path);
   console.dir(asset);
   app.use('/' + asset.path, express.static(asset.assets));
 });
 applets = applets.concat(result.applets)
 if (result.plugins !== undefined){
   deps.loadedPlugins=deps.loadedPlugins.concat(result.plugins);
 }
}
var loader = new PluginLoader();

mkdirp.sync(pluginFolder);

var funcs = [
//  loader.loadPlugins(path.join(__dirname, 'ui-plugins'), 'ui-plugin', deps),
 loader.loadPlugins(path.join(__dirname, 'system-plugins'), 'system-plugin', deps),
 loader.loadPlugins(path.join(__dirname, 'plugins'), 'plugin', deps),
 loader.loadPlugins(pluginFolder, 'community-plugin', deps, function (file) {
   return file.substring(0, 15) === 'openrov-plugin-';
 })
]

Q.allSettled(funcs).then(function(results){
 results.forEach(function (result) {
   if (result.state === "fulfilled") {
       var value = result.value;
       addPluginAssets(value);
   } else {
       var reason = result.reason;
       console.error(reason);
       debugger;
   }
 });
 console.warn("Executing Now");
 console.dir(deps.loadedPlugins);

 deps.loadedPlugins.forEach(function(plugin){
   if (plugin.start !== undefined){
     plugin.start();
   }
 });

})
.fail(function (error) {
   console.log("Executing Error");
   if (error !== undefined){
     console.dir(error);
   }
   process.exit -1;
   throw new Error("Error in loading plugins");
   console.assert(false);

//    console.log(error);
//    throw error;
})

controller.start();
// Start the web server
server.listen(app.get('port'), function () {
 console.log('Started listening on port: ' + app.get('port'));
});
<commit_msg>Moved event emitter to eventemtter2 in node<commit_after>/*
*
* Description:
* This script is the Node.js server for OpenROV.  It creates a server and instantiates an OpenROV
* and sets the interval to grab frames.  The interval is set with the DELAY variable which is in
* milliseconds.
*
*/

//To eliminate hard coding paths for require, we are modifying the NODE_PATH to include
//out lib folder
var oldpath = '';
if (process.env['NODE_PATH']!==undefined){
 oldpath = process.env['NODE_PATH'];
}
//just in case already been set leave it alone
 process.env['NODE_PATH']=__dirname+'/lib:'+oldpath;
 require('module').Module._initPaths();
 console.log("Set NODE_PATH to: "+process.env['NODE_PATH'] );

var CONFIG = require('./lib/config');
var fs = require('fs');
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server, { log: false, origins: '*:*', path:'/cockpitsocket' });
var EventEmitter = require('events').EventEmitter;
var EventEmitter2 = require('eventemitter2').EventEmitter2;
var OpenROVController = require(CONFIG.OpenROVController);
var logger = require('./lib/logger').create(CONFIG);
var mkdirp = require('mkdirp');
var path = require('path');
var PluginLoader = require('./lib/PluginLoader');
var CockpitMessaging = require('./lib/CockpitMessaging');
var Q=require('q');
require('systemd');

var serveIndex = require('serve-index');
var favicon = require('serve-favicon');
var logger = require('morgan');
var methodOverride = require('method-override');
var session = require('express-session');
var bodyParser = require('body-parser');
var multer = require('multer');
var errorHandler = require('errorhandler');

var pluginFolder = CONFIG.preferences.get('pluginsDownloadDirectory');

app.use(express.static(__dirname + '/static/'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.set('port', process.env.LISTEN_FDS > 0 ? 'systemd' : CONFIG.port);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs', { pretty: true });
app.use(favicon(__dirname + '/static/favicon.ico'));
app.use(logger('dev'));
app.use('/components', express.static(path.join(__dirname, 'static/bower_components')));
app.use('/components', express.static(pluginFolder));
app.use('/components', express.static(path.join(__dirname, 'static/webcomponents')));

app.use('/components', express.static(path.join(__dirname,'plugins/telemetry/public/bower_components')));
app.use('/components/telemetry', express.static(path.join(__dirname,'plugins/telemetry/public/webcomponents')));
app.use('/components/telemetry', serveIndex(path.join(__dirname,'plugins/telemetry/public/webcomponents')));
console.log("!!!"+ path.join(__dirname, 'src/static/bower_components'));
// Keep track of plugins js and css to load them in the view
var scripts = [], styles = [], applets = [];
var sysscripts = [];

// setup required directories
mkdirp(CONFIG.preferences.get('photoDirectory'));
process.env.NODE_ENV = true;
var globalEventLoop = require('./static/js/eventEmitterStoreAndForward.js')(new EventEmitter2());
var DELAY = Math.round(1000 / CONFIG.video_frame_rate);
io= require('./static/js/socketIOStoreAndForward.js')(io);
var client = new CockpitMessaging(io);
client = require('./static/js/eventEmitterStoreAndForward.js')(client);
var controller = new OpenROVController(globalEventLoop, client);

var pathInfo = function()
{
 return {
     scripts: scripts,
     styles: styles,
     sysscripts: sysscripts,
     applets: applets
 }
}

// Prepare dependency map for plugins
var deps = {
 server: server,
 app: app,
 rov: controller,
 cockpit: client,
 config: CONFIG,
 globalEventLoop: globalEventLoop,
 loadedPlugins: [],
 pathInfo: pathInfo
};

app.get('/config.js', function (req, res) {
 res.type('application/javascript');
 res.send('var CONFIG = ' + JSON.stringify(CONFIG));
});

//socket.io cross domain access
app.use(function (req, res, next) {
 res.header('Access-Control-Allow-Origin', '*');
 res.header('Access-Control-Allow-Headers', 'X-Requested-With');
 res.header('Access-Control-Allow-Headers', 'Content-Type');
 res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
 next();
});
var connections = 0;
// SOCKET connection ==============================
connections += 1;
if (connections == 1)
 controller.start();
// opens socket with client

deps.cockpit.on('disconnect', function () {
 connections -= 1;
 console.log('disconnect detected');
 if (connections === 0)
   controller.stop();
});
controller.on('rovsys', function (data) {
 deps.cockpit.emit('rovsys', data);
});

if (process.platform === 'linux') {
 process.on('SIGTERM', function () {
   console.error('got SIGTERM, shutting down...');
   process.exit(0);
 });
 process.on('SIGINT', function () {
   console.error('got SIGINT, shutting down...');
   process.exit(0);
 });
}

// Load the plugins
function addPluginAssets(result) {
 scripts = scripts.concat(result.scripts);
 console.log("====== Scripts ======")
 console.dir(result.scripts);
 result.scripts.forEach(function (asset) {
   console.log("SCRIPT: " + asset);
 });
 styles = styles.concat(result.styles);
 result.assets.forEach(function (asset) {
   console.log("TEST: " + asset.path);
   console.dir(asset);
   app.use('/' + asset.path, express.static(asset.assets));
 });
 applets = applets.concat(result.applets)
 if (result.plugins !== undefined){
   deps.loadedPlugins=deps.loadedPlugins.concat(result.plugins);
 }
}
var loader = new PluginLoader();

mkdirp.sync(pluginFolder);

var funcs = [
//  loader.loadPlugins(path.join(__dirname, 'ui-plugins'), 'ui-plugin', deps),
 loader.loadPlugins(path.join(__dirname, 'system-plugins'), 'system-plugin', deps),
 loader.loadPlugins(path.join(__dirname, 'plugins'), 'plugin', deps),
 loader.loadPlugins(pluginFolder, 'community-plugin', deps, function (file) {
   return file.substring(0, 15) === 'openrov-plugin-';
 })
]

Q.allSettled(funcs).then(function(results){
 results.forEach(function (result) {
   if (result.state === "fulfilled") {
       var value = result.value;
       addPluginAssets(value);
   } else {
       var reason = result.reason;
       console.error(reason);
       debugger;
   }
 });
 console.warn("Executing Now");
 console.dir(deps.loadedPlugins);

 deps.loadedPlugins.forEach(function(plugin){
   if (plugin.start !== undefined){
     plugin.start();
   }
 });

})
.fail(function (error) {
   console.log("Executing Error");
   if (error !== undefined){
     console.dir(error);
   }
   process.exit -1;
   throw new Error("Error in loading plugins");
   console.assert(false);

//    console.log(error);
//    throw error;
})

controller.start();
// Start the web server
server.listen(app.get('port'), function () {
 console.log('Started listening on port: ' + app.get('port'));
});
<|endoftext|>


<commit_before>/* global cat, echo, exec, exit, mv, rm */
require("shelljs/global");

const nomnom = require("nomnom");
const fs = require("fs");
const path = require("path");
const _ = require("underscore");
const chalk = require("chalk");

const pkg = require(path.join(__dirname, "..", "package.json"));
const emptyIndexFile = path.join(__dirname, "..", "empty_indexes.txt");
const transformBasePath = path.join(__dirname, "..", "transforms");
const runFirst = [];
const runLast = [
    "remove-stilr.js",
    "convert-to-radium.js",
    "resolve-relative-imports.js"
];

const getTransforms = function () {
    const transforms = fs.readdirSync(transformBasePath)
        .filter(function (filename) {
            return filename.match(".js$");
        })
        .filter(function (filename) {
            return runFirst.indexOf(filename) === -1;
        })
        .filter(function (filename) {
            return runLast.indexOf(filename) === -1;
        });

    const orderedTransforms = [].concat(runFirst, transforms, runLast);

    return orderedTransforms;
};

const opts = nomnom
    .options({
        src: {
            position: 0,
            help: "Source directory to run the transforms against"
        },
        all: {
            flag: true,
            abbr: "A",
            help: "Run all transforms in transforms folder"
        },
        single: {
            help: "Run individual transforms. Use `wildcat-codemod --transforms` for a list of avaliable transforms.",
            abbr: "S"
        },
        clean: {
            flag: true,
            help: "Remove any files that have been marked for deletion",
            abbr: "C"
        },
        norename: {
            flag: true,
            help: "Don't rename .jsx files to .js",
            abbr: "N"
        }
    })
    .option("transforms", {
        abbr: "t",
        flag: true,
        help: "Print a list of available transforms",
        callback: function () {
            const orderedTransforms = getTransforms();

            console.log();
            console.log(chalk.bold("Usage:"), "wildcat-codemod [src] --single", chalk.blue("[transform]"));
            console.log();
            console.log(chalk.blue("Transforms:"));
            console.log(orderedTransforms.map(function (t) {
                return "   " + t.replace(".js", "");
            }).join("\n"));
        }
    })
    .option("version", {
        abbr: "v",
        flag: true,
        help: "Print version and exit",
        callback: function () {
            return pkg.version;
        }
    }).parse();

if (opts.transforms) {
    exit(0);
}

const buildCMD = function (filePath, file) {
    return "jscodeshift -t " + filePath + " " + file + " --extensions 'jsx,js'";
};

const markForDeletion = function () {
    if (!fs.existsSync(emptyIndexFile)) {
        fs.writeFileSync(emptyIndexFile, "");
    }

    const files = cat(emptyIndexFile)
                    .split("\n")
                    .filter(function (f) {
                        return f !== "";
                    });

    const uniqueFiles = _.uniq(files).map(function (f) {
        return path.relative(process.cwd(), f);
    });

    if (uniqueFiles.length) {
        const filesList = uniqueFiles.join("\n");
        filesList.to(emptyIndexFile);

        echo();
        echo(chalk.gray(filesList));
        echo();
        echo(chalk.cyan("The above index files have been marked for deletion."));
        echo(chalk.cyan("These are considered shell files with no useful functionality."));
        echo(chalk.cyan("Their references have been removed from the codebase and can be safely deleted."));
        echo(chalk.yellow("run `wildcat-codemod -C` to delete them"));
    }

    echo();
    echo("---------------------------------------------");
    echo(chalk.bold("Next steps:"));
    echo();
    echo("1. If you haven't yet, clone a copy of the web project to serve as your web-wildcat repository:");
    echo(chalk.cyan("git clone --branch wildcat git@github.dm.nfl.com:NFL/web.git web-wildcat"));
    echo();
    echo("2. Drop your project folder into " + chalk.cyan("web-wildcat/src/domains/*/*/sites/[your-project]"));
    echo("3. Run " + chalk.cyan("`npm run lint`") + ". This should surface missing/invalid import paths.");
    echo("4. Run " + chalk.cyan("`npm run dev`") + ", load https://www.nfl.dev:3000/[your-project], and cross your fingers!");
    echo();
};

const renameFiles = function () {
    var files = find(opts.src)
                    .filter(function (file) {
                        return file.match(/\.jsx$/);
                    });

    echo("\nRenaming " + files.length + " files from .jsx to .js");

    files.map(function (file) {
        mv(file, file.replace("jsx", "js"));
    });
};

const applyTransform = function (transforms) {
    if (!transforms.length) {
        return setTimeout(markForDeletion, 1000);
    }

    const transformName = transforms.shift();
    const transformFilePath = require.resolve(path.join(transformBasePath, transformName));

    const renamedSrc = opts.norename ? opts.src : opts.src.replace(".jsx", ".js");
    const cmd = buildCMD(transformFilePath, renamedSrc);

    echo("\nApplying transform", transformName);

    exec(cmd, function (err) {
        if (err) {
            console.error(err);
        }

        applyTransform(transforms);
    });
};

const deleteEmptyIndexes = function () {
    echo("Removing unused index files");

    const emptyIndexFiles = cat(emptyIndexFile);

    if (emptyIndexFiles === null) {
        return;
    }

    emptyIndexFiles
        .split("\n")
        .filter(function (f) {
            return f !== "";
        })
        .map(function (f) {
            return rm(f);
        });
    rm(emptyIndexFile);
};

if (!opts.src && !opts.clean) {
    echo("src option is required");
    exit(1);
}

if (opts.clean) {
    deleteEmptyIndexes();
    exit(0);
} else {
    fs.writeFileSync(emptyIndexFile, "");
}

if (!opts.norename) {
    renameFiles();
}

if (opts.all) {
    applyTransform(getTransforms());
} else if (opts.single) {
    applyTransform([
        opts.single
    ]);
}
<commit_msg>*shakes fist at @dhoward*<commit_after>/* global cat, echo, exec, exit, mv, rm */
require("shelljs/global");

const nomnom = require("nomnom");
const fs = require("fs");
const path = require("path");
const _ = require("underscore");
const chalk = require("chalk");

const pkg = require(path.join(__dirname, "..", "package.json"));
const emptyIndexFile = path.join(__dirname, "..", "empty_indexes.txt");
const transformBasePath = path.join(__dirname, "..", "transforms");
const runFirst = [];
const runLast = [
    "remove-stilr.js",
    "convert-to-radium.js",
    "resolve-relative-imports.js"
];

const getTransforms = function () {
    const transforms = fs.readdirSync(transformBasePath)
        .filter(function (filename) {
            return filename.match(".js$");
        })
        .filter(function (filename) {
            return runFirst.indexOf(filename) === -1;
        })
        .filter(function (filename) {
            return runLast.indexOf(filename) === -1;
        });

    const orderedTransforms = [].concat(runFirst, transforms, runLast);

    return orderedTransforms;
};

const opts = nomnom
    .options({
        src: {
            position: 0,
            help: "Source directory to run the transforms against"
        },
        all: {
            flag: true,
            abbr: "A",
            help: "Run all transforms in transforms folder"
        },
        single: {
            help: "Run individual transforms. Use `wildcat-codemod --transforms` for a list of avaliable transforms.",
            abbr: "S"
        },
        clean: {
            flag: true,
            help: "Remove any files that have been marked for deletion",
            abbr: "C"
        },
        norename: {
            flag: true,
            help: "Don't rename .jsx files to .js",
            abbr: "N"
        },
        transforms: {
            abbr: "t",
            flag: true,
            help: "Print a list of available transforms",
            callback: function () {
                const orderedTransforms = getTransforms();

                console.log();
                console.log(chalk.bold("Usage:"), "wildcat-codemod [src] --single", chalk.blue("[transform]"));
                console.log();
                console.log(chalk.blue("Transforms:"));
                console.log(orderedTransforms.map(function (t) {
                    return "   " + t.replace(".js", "");
                }).join("\n"));
            }
        },
        version: {
            abbr: "v",
            flag: true,
            help: "Print version and exit",
            callback: function () {
                return pkg.version;
            }
        }
    }).parse();

if (opts.transforms) {
    exit(0);
}

const buildCMD = function (filePath, file) {
    return "jscodeshift -t " + filePath + " " + file + " --extensions 'jsx,js'";
};

const markForDeletion = function () {
    if (!fs.existsSync(emptyIndexFile)) {
        fs.writeFileSync(emptyIndexFile, "");
    }

    const files = cat(emptyIndexFile)
                    .split("\n")
                    .filter(function (f) {
                        return f !== "";
                    });

    const uniqueFiles = _.uniq(files).map(function (f) {
        return path.relative(process.cwd(), f);
    });

    if (uniqueFiles.length) {
        const filesList = uniqueFiles.join("\n");
        filesList.to(emptyIndexFile);

        echo();
        echo(chalk.gray(filesList));
        echo();
        echo(chalk.cyan("The above index files have been marked for deletion."));
        echo(chalk.cyan("These are considered shell files with no useful functionality."));
        echo(chalk.cyan("Their references have been removed from the codebase and can be safely deleted."));
        echo(chalk.yellow("run `wildcat-codemod -C` to delete them"));
    }

    echo();
    echo("---------------------------------------------");
    echo(chalk.bold("Next steps:"));
    echo();
    echo("1. If you haven't yet, clone a copy of the web project to serve as your web-wildcat repository:");
    echo(chalk.cyan("git clone --branch wildcat git@github.dm.nfl.com:NFL/web.git web-wildcat"));
    echo();
    echo("2. Drop your project folder into " + chalk.cyan("web-wildcat/src/domains/*/*/sites/[your-project]"));
    echo("3. Run " + chalk.cyan("`npm run lint`") + ". This should surface missing/invalid import paths.");
    echo("4. Run " + chalk.cyan("`npm run dev`") + ", load https://www.nfl.dev:3000/[your-project], and cross your fingers!");
    echo();
};

const renameFiles = function () {
    var files = find(opts.src)
                    .filter(function (file) {
                        return file.match(/\.jsx$/);
                    });

    echo("\nRenaming " + files.length + " files from .jsx to .js");

    files.map(function (file) {
        mv(file, file.replace("jsx", "js"));
    });
};

const applyTransform = function (transforms) {
    if (!transforms.length) {
        return setTimeout(markForDeletion, 1000);
    }

    const transformName = transforms.shift();
    const transformFilePath = require.resolve(path.join(transformBasePath, transformName));

    const renamedSrc = opts.norename ? opts.src : opts.src.replace(".jsx", ".js");
    const cmd = buildCMD(transformFilePath, renamedSrc);

    echo("\nApplying transform", transformName);

    exec(cmd, function (err) {
        if (err) {
            console.error(err);
        }

        applyTransform(transforms);
    });
};

const deleteEmptyIndexes = function () {
    echo("Removing unused index files");

    const emptyIndexFiles = cat(emptyIndexFile);

    if (emptyIndexFiles === null) {
        return;
    }

    emptyIndexFiles
        .split("\n")
        .filter(function (f) {
            return f !== "";
        })
        .map(function (f) {
            return rm(f);
        });
    rm(emptyIndexFile);
};

if (!opts.src && !opts.clean) {
    echo("src option is required");
    exit(1);
}

if (opts.clean) {
    deleteEmptyIndexes();
    exit(0);
} else {
    fs.writeFileSync(emptyIndexFile, "");
}

if (!opts.norename) {
    renameFiles();
}

if (opts.all) {
    applyTransform(getTransforms());
} else if (opts.single) {
    applyTransform([
        opts.single
    ]);
}
<|endoftext|>


<commit_before>// build-dependencies: core, source, map
// build-dependencies: functionconstruction, argumentstoobservables
// build-dependencies: when

Bacon.combineAsArray = function() {
  var streams = argumentsToObservables(arguments).slice();
  for (var index = 0, stream; index < streams.length; index++) {
    stream = streams[index];
    if (!isObservable(stream)) {
      streams[index] = Bacon.constant(stream);
    }
  }
  if (streams.length) {
    var sources = (() => {
      var result = [];
      for (var i = 0, s; i < streams.length; i++) {
        s = streams[i];
        result.push(new Source(s, true));
      }
      return result;
    })();
    return withDesc(new Bacon.Desc(Bacon, "combineAsArray", streams), Bacon.when(sources, (function(...xs) { return xs; })).toProperty());
  } else {
    return Bacon.constant([]);
  }
};

Bacon.onValues = function(...streams) {
  return Bacon.combineAsArray(streams.slice(0, streams.length - 1)).onValues(streams[streams.length - 1]);
};

Bacon.combineWith = function() {
  var [streams, f] = argumentsToObservablesAndFunction(arguments);
  var desc = new Bacon.Desc(Bacon, "combineWith", [f, ...streams]);
  return withDesc(desc, Bacon.combineAsArray(streams).map(function(values) { return f(...values); }));
};

Bacon.Observable.prototype.combine = function(other, f) {
  var combinator = toCombinator(f);
  var desc = new Bacon.Desc(this, "combine", [other, f]);
  return withDesc(desc, Bacon.combineAsArray(this, other).map(function(values) { return combinator(values[0], values[1]); }));
};
<commit_msg>premature optimization<commit_after>// build-dependencies: core, source, map
// build-dependencies: functionconstruction, argumentstoobservables
// build-dependencies: when

Bacon.combineAsArray = function() {
  var streams = argumentsToObservables(arguments)
  var cloned = false
  for (var index = 0, stream; index < streams.length; index++) {
    stream = streams[index];
    if (!isObservable(stream)) {
      if (!cloned) {
        cloned = true
        streams = streams.slice()
      }
      streams[index] = Bacon.constant(stream);
    }
  }
  if (streams.length) {
    var sources = (() => {
      var result = [];
      for (var i = 0, s; i < streams.length; i++) {
        s = streams[i];
        result.push(new Source(s, true));
      }
      return result;
    })();
    return withDesc(new Bacon.Desc(Bacon, "combineAsArray", streams), Bacon.when(sources, (function(...xs) { return xs; })).toProperty());
  } else {
    return Bacon.constant([]);
  }
};

Bacon.onValues = function(...streams) {
  return Bacon.combineAsArray(streams.slice(0, streams.length - 1)).onValues(streams[streams.length - 1]);
};

Bacon.combineWith = function() {
  var [streams, f] = argumentsToObservablesAndFunction(arguments);
  var desc = new Bacon.Desc(Bacon, "combineWith", [f, ...streams]);
  return withDesc(desc, Bacon.combineAsArray(streams).map(function(values) { return f(...values); }));
};

Bacon.Observable.prototype.combine = function(other, f) {
  var combinator = toCombinator(f);
  var desc = new Bacon.Desc(this, "combine", [other, f]);
  return withDesc(desc, Bacon.combineAsArray(this, other).map(function(values) { return combinator(values[0], values[1]); }));
};
<|endoftext|>


<commit_before>var stderr                 = process.stderr,
    fs                     = require('fs'),
    path                   = require('path'),
    inlineSourceMapComment = require('inline-source-map-comment')

var TypeSystem  = require('./typesystem').TypeSystem,
    Parser      = require('./parser'),
    reportError = require('./util').reportError,
    Compiler    = require('./compiler')

// Parse command-line arguments
var optimist = require('optimist')
var argv = optimist
    .usage('Usage: hb [command] [options]')
    .boolean('m')
    .alias('m', 'map')
    .boolean('v')
    .boolean('s')
    .alias('s', 'single')
    // .demand(1)
    .argv

// Logging -------------------------------------------------------------------

var winston = require('winston'),
    logger  = new winston.Logger()
logger.add(winston.transports.Console, {
  colorize: true,
  level:    (argv.v ? 'info' : 'warn')
})

function showHelp () {
  var help = optimist.help().trim()
  help += "\n\n"
  help += "Commands:\n"
  help += "  run [file]                Compile and run a file\n"
  help += "  compile [options] [file]  Compile a file to JavaScript; writes to STDOUT\n"
  help += "  inspect [file]            Print the compiled AST of a file\n"
  help += "  help                      Show this help message\n\n"
  help += "Options:\n"
  help += "  -m, --map                 Include source maps in output\n"
  help += "  -v                        Verbose"
  help += "  -s, --single              Don't include imports (uses RequireJS)\n"
  console.error(help)
}

if (argv._.length === 0) {
  showHelp()
  process.exit(1)
}

// Utility function to read a file, parse it, walk it, and then return
// the finalized tree. On error it prints a nice error report and then
// calls `process.exit`.
function treeForFile (file) {
  var contents = null
  try {
    contents = fs.readFileSync(file).toString()
  } catch (err) {
    if (err.code === 'ENOENT') {
      logger.error("File not found: "+file)
      process.exit(1)
    }
    throw err
  }
  var name     = path.basename(file),
      parser   = new Parser()

  parser.file = name
  // Parse and type-check the file; catch and report any errors
  try {
    var tree       = parser.parse(contents),
        typesystem = new TypeSystem()
    typesystem.walk(tree)
  } catch (err) {
    reportError(err)
    process.exit(1)
  }
  return tree
}// treeForFile

function parseAndWalk (file, code) {
  var parser     = new Parser(),
      typesystem = new TypeSystem()
  parser.file = file
  var tree = parser.parse(contents)
  typesystem.walk(tree)
  return tree
}

function fileFromArgs (args, idx) {
  var file = args[idx]
  if (!file) {
    logger.error("Missing file to inspect")
    process.exit(2)
  }
  return file
}

var compileOpts = {
  isEntry: true
}
var targetOpts = {}

function compileFile (args) {
  var filePath      = fileFromArgs(args, 0),
      // Get the directory of the file for the import-path
      fileDirectory = path.dirname(filePath)
  var compiler = new Compiler()
  compiler.importPath.push(fileDirectory)
  var file = compiler.compile(filePath, compileOpts)
  return file
}

var commands = {
  inspect: function (args) {
    var file = compileFile(args)
    file.tree.print()
    process.exit(0)
  },// inspect
  compile: function (args) {
    var file = compileFile(args)
    // If there's no imports and exports then set it to single mode
    if (file.tree.imports.length === 0) {
      targetOpts.single = true
    }
    // Load the JavaScript compile target and print the compiled source
    require('./targets/javascript')
    process.stdout.write(file.tree.compile(targetOpts))
    // Check whether we should also print the source-map
    var includeMap = argv.map
    if (includeMap) {
      process.stdout.write(inlineSourceMapComment(file.tree.sourceMap))
      process.stdout.write("\n")
    }
  },
  run: function (args) {
    var file = compileFile(args)
    // Load the JavaScript compile target
    require('./targets/javascript')
    // Load the vm module and JavaScript target compiler
    var vm = require('vm')
    // Compile the whole file into a bundle to run
    var compiledSource = file.tree.compile()
    // Expose "require(...)" to the script
    global.require = require;
    // Run the compiled source in the VM
    vm.runInThisContext(compiledSource)
  },
  help: function (args) {
    showHelp()
  }
}

function run () {
  var commandArg = argv._[0],
      otherArgs  = argv._.slice(1),
      command    = commands[commandArg]

  if (!command) {
    return stderr.write("Unrecognized command '"+commandArg+"'\n")
  }
  // Check if there was a "--single" option to force single-file target
  // compilation mode
  if (argv.single === true) {
    targetOpts.single = true
  }
  command(otherArgs)
}

module.exports = {run: run}

<commit_msg>Improve error messages from command runner<commit_after>var stderr                 = process.stderr,
    fs                     = require('fs'),
    path                   = require('path'),
    inlineSourceMapComment = require('inline-source-map-comment')

var TypeSystem  = require('./typesystem').TypeSystem,
    Parser      = require('./parser'),
    reportError = require('./util').reportError,
    Compiler    = require('./compiler')

// Parse command-line arguments
var optimist = require('optimist')
var argv = optimist
    .usage('Usage: hb [command] [options]')
    .boolean('m')
    .alias('m', 'map')
    .boolean('v')
    .boolean('s')
    .alias('s', 'single')
    // .demand(1)
    .argv

// Logging -------------------------------------------------------------------

var winston = require('winston'),
    logger  = new winston.Logger()
logger.add(winston.transports.Console, {
  colorize: true,
  level:    (argv.v ? 'info' : 'warn')
})

function showHelp () {
  var help = optimist.help().trim()
  help += "\n\n"
  help += "Commands:\n"
  help += "  run [file]                Compile and run a file\n"
  help += "  compile [options] [file]  Compile a file to JavaScript; writes to STDOUT\n"
  help += "  inspect [file]            Print the compiled AST of a file\n"
  help += "  help                      Show this help message\n\n"
  help += "Options:\n"
  help += "  -m, --map                 Include source maps in output\n"
  help += "  -v                        Verbose"
  help += "  -s, --single              Don't include imports (uses RequireJS)\n"
  console.error(help)
}

if (argv._.length === 0) {
  showHelp()
  process.exit(1)
}

// Utility function to read a file, parse it, walk it, and then return
// the finalized tree. On error it prints a nice error report and then
// calls `process.exit`.
function treeForFile (file) {
  var contents = null
  try {
    contents = fs.readFileSync(file).toString()
  } catch (err) {
    if (err.code === 'ENOENT') {
      logger.error("File not found: "+file)
      process.exit(1)
    }
    throw err
  }
  var name     = path.basename(file),
      parser   = new Parser()

  parser.file = name
  // Parse and type-check the file; catch and report any errors
  try {
    var tree       = parser.parse(contents),
        typesystem = new TypeSystem()
    typesystem.walk(tree)
  } catch (err) {
    reportError(err)
    process.exit(1)
  }
  return tree
}// treeForFile

function parseAndWalk (file, code) {
  var parser     = new Parser(),
      typesystem = new TypeSystem()
  parser.file = file
  var tree = parser.parse(contents)
  typesystem.walk(tree)
  return tree
}

function fileFromArgs (args, idx) {
  var file = args[idx]
  if (!file) {
    logger.error("Missing file to inspect")
    process.exit(2)
  }
  return file
}

var compileOpts = {
  isEntry: true
}
var targetOpts = {}

function compileFile (args) {
  var filePath      = fileFromArgs(args, 0),
      // Get the directory of the file for the import-path
      fileDirectory = path.dirname(filePath)
  try {
    var compiler = new Compiler()
    compiler.importPath.push(fileDirectory)
    var file = compiler.compile(filePath, compileOpts)
  } catch (err) {
    reportError(err)
    process.exit(1)
  }
  return file
}

var commands = {
  inspect: function (args) {
    var file = compileFile(args)
    file.tree.print()
    process.exit(0)
  },// inspect
  compile: function (args) {
    var file = compileFile(args)
    // If there's no imports and exports then set it to single mode
    if (file.tree.imports.length === 0) {
      targetOpts.single = true
    }
    // Load the JavaScript compile target and print the compiled source
    require('./targets/javascript')
    process.stdout.write(file.tree.compile(targetOpts))
    // Check whether we should also print the source-map
    var includeMap = argv.map
    if (includeMap) {
      process.stdout.write(inlineSourceMapComment(file.tree.sourceMap))
      process.stdout.write("\n")
    }
  },
  run: function (args) {
    var file = compileFile(args)
    // Load the JavaScript compile target
    require('./targets/javascript')
    // Load the vm module and JavaScript target compiler
    var vm = require('vm')
    // Compile the whole file into a bundle to run
    var compiledSource = file.tree.compile()
    // Expose "require(...)" to the script
    global.require = require;
    // Run the compiled source in the VM
    vm.runInThisContext(compiledSource)
  },
  help: function (args) {
    showHelp()
  }
}

function run () {
  var commandArg = argv._[0],
      otherArgs  = argv._.slice(1),
      command    = commands[commandArg]

  if (!command) {
    return stderr.write("Unrecognized command '"+commandArg+"'\n")
  }
  // Check if there was a "--single" option to force single-file target
  // compilation mode
  if (argv.single === true) {
    targetOpts.single = true
  }
  command(otherArgs)
}

module.exports = {run: run}

<|endoftext|>


<commit_before>/* global define */
/*jslint bitwise: true */
(function (window) {
  'use strict';

  var Complex = function () {

    var self = {
      div: function (p, q) {
        var a = p.re,
          b = p.im,
          c = q.re,
          d = q.im;
        var n = (c * c + d * d);
        var x = {
          re: (a * c + b * d) / n,
          im: (b * c - a * d) / n
        };
        return x;
      },
      mul: function (p, q) {
        var a = p.re,
          b = p.im,
          c = q.re,
          d = q.im;
        var x = {
          re: (a * c - b * d),
          im: (a + b) * (c + d) - a * c - b * d
        };
        return x;
      },
      add: function (p,q) {
          var x = {
          re: p.re + q.re,
          im: p.im + q.im
        };
        return x;
      },
      sub: function (p,q) {
          var x = {
          re: p.re - q.re,
          im: p.im - q.im
        };
        return x;
      },
      phase: function (n) {
        return Math.atan2(n.im, n.re);
      },
      magnitude: function (n) {
        return Math.sqrt(n.re * n.re + n.im * n.im);
      }
    };
    return self;
  };
  if (typeof module === 'object' && module && typeof module.exports === 'object') {
    module.exports = Complex;
  } else {
    window.Complex = Complex;
    if (typeof define === 'function' && define.amd) {
      define(Complex);
    }
  }
})(window);
<commit_msg>beautified<commit_after>/* global define */
/*jslint bitwise: true */
(function (window) {
  'use strict';

  var Complex = function () {

    var self = {
      div: function (p, q) {
        var a = p.re,
          b = p.im,
          c = q.re,
          d = q.im;
        var n = (c * c + d * d);
        var x = {
          re: (a * c + b * d) / n,
          im: (b * c - a * d) / n
        };
        return x;
      },
      mul: function (p, q) {
        var a = p.re,
          b = p.im,
          c = q.re,
          d = q.im;
        var x = {
          re: (a * c - b * d),
          im: (a + b) * (c + d) - a * c - b * d
        };
        return x;
      },
      add: function (p, q) {
        var x = {
          re: p.re + q.re,
          im: p.im + q.im
        };
        return x;
      },
      sub: function (p, q) {
        var x = {
          re: p.re - q.re,
          im: p.im - q.im
        };
        return x;
      },
      phase: function (n) {
        return Math.atan2(n.im, n.re);
      },
      magnitude: function (n) {
        return Math.sqrt(n.re * n.re + n.im * n.im);
      }
    };
    return self;
  };
  if (typeof module === 'object' && module && typeof module.exports === 'object') {
    module.exports = Complex;
  } else {
    window.Complex = Complex;
    if (typeof define === 'function' && define.amd) {
      define(Complex);
    }
  }
})(window);
<|endoftext|>


<commit_before>import Vue from 'vue';
import { camelToKebab, assign, pick, omit, mapValues } from './utils';

const VERSION = Number(Vue.version.split('.')[0]);

const LIFECYCLE_KEYS = [
  'init',
  'created',
  'beforeCompile',
  'compiled',
  'ready',
  'attached',
  'detached',
  'beforeDestroy',
  'destroyed',

  // 2.0
  'beforeCreate',
  'beforeMount',
  'mounted',
  'beforeUpdate',
  'updated',
  'activated',
  'deactivated'
];

export function connect(options = {}) {
  const {
    gettersToProps = {},
    actionsToProps = {},
    actionsToEvents = {},
    lifecycle = {}
  } = options;

  return function(name, Component) {
    const propKeys = Object.keys(gettersToProps).concat(Object.keys(actionsToProps));
    const eventKeys = Object.keys(actionsToEvents);

    const containerProps = omit(getProps(Component), propKeys);

    const options = {
      props: containerProps,
      components: {
        [name]: Component
      },
      vuex: {
        getters: gettersToProps,
        actions: assign({}, actionsToProps, actionsToEvents)
      }
    };

    insertRenderer(options, name, propKeys.concat(Object.keys(containerProps)), eventKeys);

    const lifecycle_ = mapValues(pick(lifecycle, LIFECYCLE_KEYS), f => {
      return function boundLifecycle() {
        f.call(this, this.$store);
      };
    });

    return Vue.extend(assign(options, lifecycle_));
  };
}

function insertRenderer(options, name, propKeys, eventKeys) {
  if (VERSION >= 2) {
    options.render = function(h) {
      return h(name, {
        props: pick(this, propKeys),
        on: pick(this, eventKeys)
      });
    };
  } else {
    const props = propKeys.map(bindProp);
    const events = eventKeys.map(bindEvent);
    options.template = `<${name} ${props.concat(events).join(' ')}></${name}>`;
  }
}

function getProps(Component) {
  if (typeof Component === 'function') {
    return Component.options.props || {};
  }
  return Component.props || {};
}

function bindProp(key) {
  return `:${camelToKebab(key)}="${key}"`;
}

function bindEvent(key) {
  return `@${camelToKebab(key)}="${key}"`;
}
<commit_msg>Lifecycle to mixin<commit_after>import Vue from 'vue';
import { camelToKebab, assign, pick, omit, mapValues } from './utils';

const VERSION = Number(Vue.version.split('.')[0]);

const LIFECYCLE_KEYS = [
  'init',
  'created',
  'beforeCompile',
  'compiled',
  'ready',
  'attached',
  'detached',
  'beforeDestroy',
  'destroyed',

  // 2.0
  'beforeCreate',
  'beforeMount',
  'mounted',
  'beforeUpdate',
  'updated',
  'activated',
  'deactivated'
];

export function connect(options = {}) {
  const {
    gettersToProps = {},
    actionsToProps = {},
    actionsToEvents = {},
    lifecycle = {}
  } = options;

  return function(name, Component) {
    const propKeys = Object.keys(gettersToProps).concat(Object.keys(actionsToProps));
    const eventKeys = Object.keys(actionsToEvents);

    const containerProps = omit(getProps(Component), propKeys);

    const options = {
      props: containerProps,
      components: {
        [name]: Component
      },
      vuex: {
        getters: gettersToProps,
        actions: assign({}, actionsToProps, actionsToEvents)
      }
    };

    insertLifecycleMixin(options, lifecycle);
    insertRenderer(options, name, propKeys.concat(Object.keys(containerProps)), eventKeys);

    return Vue.extend(options);
  };
}

function insertRenderer(options, name, propKeys, eventKeys) {
  if (VERSION >= 2) {
    options.render = function(h) {
      return h(name, {
        props: pick(this, propKeys),
        on: pick(this, eventKeys)
      });
    };
  } else {
    const props = propKeys.map(bindProp);
    const events = eventKeys.map(bindEvent);
    options.template = `<${name} ${props.concat(events).join(' ')}></${name}>`;
  }
}

function insertLifecycleMixin(options, lifecycle) {
  options.mixins = [
    mapValues(pick(lifecycle, LIFECYCLE_KEYS), f => {
      return function boundLifecycle() {
        f.call(this, this.$store);
      };
    })
  ];
}

function getProps(Component) {
  if (typeof Component === 'function') {
    return Component.options.props || {};
  }
  return Component.props || {};
}

function bindProp(key) {
  return `:${camelToKebab(key)}="${key}"`;
}

function bindEvent(key) {
  return `@${camelToKebab(key)}="${key}"`;
}
<|endoftext|>


<commit_before>/** @jsx element */

import {subscribe, unsubscribe, getLast} from './actions'
import {component, element} from 'vdux'
import deepEqual from '@f/deep-equal'
import mapValues from '@f/map-values'
import objEqual from '@f/equal-obj'
import objSome from 'object-some'
import {mw} from './middleware'
import reducer from './reducer'
import filter from '@f/filter'
import splice from '@f/splice'
import map from '@f/map-obj'
import union from '@f/union'

const orderParams = /orderByValue|orderByChild|orderByKey/gi

function mapState (obj) {
  return map((url = {}, name) => ({
    name,
    url,
    pageSize: url.pageSize,
    loading: true,
    error: null,
    value: null
  }), obj)
}

        // const {pageSize, queryParams} = mapping
        // if (pageSize) {
        //   yield actions.setPageSize(pageSize)
        // }
        // {...mapping, queryParams: (queryParams || []).concat(`limitToFirst=${pageSize}`)}

function connect (fn) {
  return function (Ui) {
    const Component = component({
      initialState ({props, state, local}) {
        return {
          ...mapState(fn(props)),
          savedKeys: [],
          page: 0
        }
      },

      * onCreate ({props, state, path, actions, context}) {
        const mapping = fn(props, context)
        if (objSome(mapping, (val = {}, key) => {
          return val.pageSize && !(val.queryParams && val.queryParams.find(v => v.search(orderParams) > -1))
        })) {
          throw new Error('vdux-fire error: pageSize requires an orderBy queryParam')
        }
        yield actions.subscribeAll(path, fn(props))
      },

      * onUpdate (prev, next) {
        if (!deepEqual(prev.props, next.props)) {
          // console.log('update', prev.props, next.props)
          const prevProps = fn(prev.props)
          const nextProps = fn(next.props)
          const newProps = filter((prop, key) => !prevProps[key] || prevProps[key] !== prop, nextProps)
          const removeProps = filter((prop, key) => !nextProps[key] || nextProps[key] !== prop, prevProps)
          if (Object.keys(removeProps).length > 0) {
            yield unsubscribeAll(next.path, removeProps)
          }
          if (Object.keys(newProps).length > 0) {
            const mapped = mapState(newProps)
            // yield mapValues(prop => next.actions.update(prop), mapped)
            yield next.actions.subscribeAll(next.path, newProps)
          }
        }
      },

      render ({props, state, children, actions}) {
        const mapping = fn(props)
        // XXX CLEAN THIS UP
        const injectedNext = map((val, key) => {
          if (val && val.pageSize && !val.done) {
            return {...val, next: actions.nextPage(key)}
          }
          return val
        }, state)

        return (
          <Ui {...props} {...injectedNext} >
            {children}
          </Ui>
        )
      },

      controller: {
        * nextPage ({props, state, actions, path}, key) {
          const mapping = fn(props)
          const {cursor} = state
          const pageNum = state.page + 1
          yield actions.setPage(pageNum)

          yield actions.subscribe(
            path,
            {
              ...mapping[key],
              queryParams: (mapping[key].queryParams || []).concat(`startAt=${cursor}`,),
              mergeValues: true,
              page: pageNum
            },
            key
          )
        },
        * subscribe ({state}, path, ref, key, childKey) {
          if (ref) {
            typeof (ref) === 'string'
              ? yield subscribe({path, ref, name: key, childKey})
              : yield subscribe({
                  ref,
                  path,
                  childKey,
                  name: key
                })
            }
        },
        * subscribeAll ({actions}, path, refs) {
          for (let key in refs) {
            const ref = refs[key]
            if (!ref || (ref.list && ref.list.lenght === 0)) {
              yield actions.update({name: key})
              continue
            }

            if (ref.pageSize) {
              yield getLast({path, ref, key})
            }
            if (ref.list) {
              for (let leaf in ref.list) {
                yield actions.subscribe(path, {...ref, ref: `${ref.ref}/${ref.list[leaf]}`}, key, ref.list[leaf])
              }
              continue
            }
            yield actions.subscribe(path, ref, key)
          }
        },
        * mergeValue ({state, actions}, {name, value, key, page, prevSib, orderBy}) {
          const list = state[name].value
            ? join(state[name].value, {val: value, key}, prevSib)
            : [{val: value, key}]
          const lastItem = list[list.length - 1]
          if (lastItem.key === state[name].lastItem) {
            yield actions.donePaging(name)
          }
          yield actions.update({name, value: list, key})
          const cursor = orderByToKey(orderBy, {value: lastItem.val, key: lastItem.key})
          if (cursor) {
            yield actions.setCursor()
          } else {
            throw new Error(`vdux-fire error: ref does not have sort key '${orderBy.split('=')[1]}'`)
          }
        }
      },

      reducer: {
        setPage: (state, page) => ({page}),
        setCursor: (state, cursor) => ({cursor}),
        donePaging: (state, name) => ({[name]: {...state[name], done: true}}),
        setLastItem: (state, {name, snap, orderBy}) => ({
          [name]: {
            ...state[name],
            lastItem: snap.key
          }
        }),
        update,
        mapNewState: (state, payload) => ({
          ...state,
          ...payload
        }),
        removeKey: (state, {name, key}) => ({
          [name]: {
            ...state[name],
            value: state[name].value.filter(v => v.key !== key)
          }
        })
      },

      middleware: [
        mw
      ],

      onRemove ({path}) {
        return unsubscribe({path})
      }
    })

    return Component
  }
}

function update (state, payload) {
  if (payload.childKey) {
    return {
      ...state,
      [payload.name]: {
        ...state[payload.name],
        loading: false,
        value: {
          ...(state[payload.name] || {}).value,
          [payload.childKey]: {
            ...payload.value
          }
        }
      }
    }
  }
  return {
    [payload.name]: {
      ...state[payload.name],
      ...payload,
      loading: false
    }
  }
}

function join (a, b, prevSib) {
  const oldIdx = a.findIndex(v => v.key === b.key)
  if (oldIdx > -1) {
    a[oldIdx] = b
    return a
  }
  if (prevSib) {
    const prevIdx = a.findIndex(v => v.key === prevSib)
    return splice(a, prevIdx + 1, 0, b)
  }
  return a.concat(b)
}

function * unsubscribeAll (path, refs) {
  for (let key in refs) {
    const ref = refs[key]
    if (ref) {
      typeof (ref) === 'string'
        ? yield unsubscribe({path, ref, name: key})
        : yield unsubscribe({
            ref: ref.ref,
            name: key,
            path
          })
      }
  }
}

function orderByToKey (sort, val) {
  const [orderBy, child] = sort.split('=')
  const orders = {
    'orderByKey': val.key,
    'orderByValue': val.value,
    'orderByChild': val[child]
  }
  return orders[orderBy]
}

export default connect
export {
  reducer
}
<commit_msg>length<commit_after>/** @jsx element */

import {subscribe, unsubscribe, getLast} from './actions'
import {component, element} from 'vdux'
import deepEqual from '@f/deep-equal'
import mapValues from '@f/map-values'
import objEqual from '@f/equal-obj'
import objSome from 'object-some'
import {mw} from './middleware'
import reducer from './reducer'
import filter from '@f/filter'
import splice from '@f/splice'
import map from '@f/map-obj'
import union from '@f/union'

const orderParams = /orderByValue|orderByChild|orderByKey/gi

function mapState (obj) {
  return map((url = {}, name) => ({
    name,
    url,
    pageSize: url.pageSize,
    loading: true,
    error: null,
    value: null
  }), obj)
}

        // const {pageSize, queryParams} = mapping
        // if (pageSize) {
        //   yield actions.setPageSize(pageSize)
        // }
        // {...mapping, queryParams: (queryParams || []).concat(`limitToFirst=${pageSize}`)}

function connect (fn) {
  return function (Ui) {
    const Component = component({
      initialState ({props, state, local}) {
        return {
          ...mapState(fn(props)),
          savedKeys: [],
          page: 0
        }
      },

      * onCreate ({props, state, path, actions, context}) {
        const mapping = fn(props, context)
        if (objSome(mapping, (val = {}, key) => {
          return val.pageSize && !(val.queryParams && val.queryParams.find(v => v.search(orderParams) > -1))
        })) {
          throw new Error('vdux-fire error: pageSize requires an orderBy queryParam')
        }
        yield actions.subscribeAll(path, fn(props))
      },

      * onUpdate (prev, next) {
        if (!deepEqual(prev.props, next.props)) {
          // console.log('update', prev.props, next.props)
          const prevProps = fn(prev.props)
          const nextProps = fn(next.props)
          const newProps = filter((prop, key) => !prevProps[key] || prevProps[key] !== prop, nextProps)
          const removeProps = filter((prop, key) => !nextProps[key] || nextProps[key] !== prop, prevProps)
          if (Object.keys(removeProps).length > 0) {
            yield unsubscribeAll(next.path, removeProps)
          }
          if (Object.keys(newProps).length > 0) {
            const mapped = mapState(newProps)
            // yield mapValues(prop => next.actions.update(prop), mapped)
            yield next.actions.subscribeAll(next.path, newProps)
          }
        }
      },

      render ({props, state, children, actions}) {
        const mapping = fn(props)
        // XXX CLEAN THIS UP
        const injectedNext = map((val, key) => {
          if (val && val.pageSize && !val.done) {
            return {...val, next: actions.nextPage(key)}
          }
          return val
        }, state)

        return (
          <Ui {...props} {...injectedNext} >
            {children}
          </Ui>
        )
      },

      controller: {
        * nextPage ({props, state, actions, path}, key) {
          const mapping = fn(props)
          const {cursor} = state
          const pageNum = state.page + 1
          yield actions.setPage(pageNum)

          yield actions.subscribe(
            path,
            {
              ...mapping[key],
              queryParams: (mapping[key].queryParams || []).concat(`startAt=${cursor}`,),
              mergeValues: true,
              page: pageNum
            },
            key
          )
        },
        * subscribe ({state}, path, ref, key, childKey) {
          if (ref) {
            typeof (ref) === 'string'
              ? yield subscribe({path, ref, name: key, childKey})
              : yield subscribe({
                  ref,
                  path,
                  childKey,
                  name: key
                })
            }
        },
        * subscribeAll ({actions}, path, refs) {
          for (let key in refs) {
            const ref = refs[key]
            if (!ref || (ref.list && ref.list.length === 0)) {
              yield actions.update({name: key})
              continue
            }

            if (ref.pageSize) {
              yield getLast({path, ref, key})
            }
            if (ref.list) {
              for (let leaf in ref.list) {
                yield actions.subscribe(path, {...ref, ref: `${ref.ref}/${ref.list[leaf]}`}, key, ref.list[leaf])
              }
              continue
            }
            yield actions.subscribe(path, ref, key)
          }
        },
        * mergeValue ({state, actions}, {name, value, key, page, prevSib, orderBy}) {
          const list = state[name].value
            ? join(state[name].value, {val: value, key}, prevSib)
            : [{val: value, key}]
          const lastItem = list[list.length - 1]
          if (lastItem.key === state[name].lastItem) {
            yield actions.donePaging(name)
          }
          yield actions.update({name, value: list, key})
          const cursor = orderByToKey(orderBy, {value: lastItem.val, key: lastItem.key})
          if (cursor) {
            yield actions.setCursor()
          } else {
            throw new Error(`vdux-fire error: ref does not have sort key '${orderBy.split('=')[1]}'`)
          }
        }
      },

      reducer: {
        setPage: (state, page) => ({page}),
        setCursor: (state, cursor) => ({cursor}),
        donePaging: (state, name) => ({[name]: {...state[name], done: true}}),
        setLastItem: (state, {name, snap, orderBy}) => ({
          [name]: {
            ...state[name],
            lastItem: snap.key
          }
        }),
        update,
        mapNewState: (state, payload) => ({
          ...state,
          ...payload
        }),
        removeKey: (state, {name, key}) => ({
          [name]: {
            ...state[name],
            value: state[name].value.filter(v => v.key !== key)
          }
        })
      },

      middleware: [
        mw
      ],

      onRemove ({path}) {
        return unsubscribe({path})
      }
    })

    return Component
  }
}

function update (state, payload) {
  if (payload.childKey) {
    return {
      ...state,
      [payload.name]: {
        ...state[payload.name],
        loading: false,
        value: {
          ...(state[payload.name] || {}).value,
          [payload.childKey]: {
            ...payload.value
          }
        }
      }
    }
  }
  return {
    [payload.name]: {
      ...state[payload.name],
      ...payload,
      loading: false
    }
  }
}

function join (a, b, prevSib) {
  const oldIdx = a.findIndex(v => v.key === b.key)
  if (oldIdx > -1) {
    a[oldIdx] = b
    return a
  }
  if (prevSib) {
    const prevIdx = a.findIndex(v => v.key === prevSib)
    return splice(a, prevIdx + 1, 0, b)
  }
  return a.concat(b)
}

function * unsubscribeAll (path, refs) {
  for (let key in refs) {
    const ref = refs[key]
    if (ref) {
      typeof (ref) === 'string'
        ? yield unsubscribe({path, ref, name: key})
        : yield unsubscribe({
            ref: ref.ref,
            name: key,
            path
          })
      }
  }
}

function orderByToKey (sort, val) {
  const [orderBy, child] = sort.split('=')
  const orders = {
    'orderByKey': val.key,
    'orderByValue': val.value,
    'orderByChild': val[child]
  }
  return orders[orderBy]
}

export default connect
export {
  reducer
}
<|endoftext|>