<commit_before>/*
 *   Copyright 2014-2016 Guy Bedford (http://guybedford.com)
 *
 *   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 ConfigFile = require('./config-file');
var path = require('path');
var ui = require('../ui');
var processDeps = require('../common').processDeps;
var hasProperties = require('../common').hasProperties;
var config = require('./index');

/*
 * Package.json Configuration Class
 *
 * Public Properties
 * - name
 * - packages
 * - baseURL
 * - lib
 * - dist
 * - configFile
 * - configFileDev
 * - configFileBrowser
 * - configFileNode
 * - dependencies
 * - peerDependencies
 * - devDependencies
 * - overrides
 *
 * Public Methods
 * - write
 * - prompt
 *
 */
module.exports = PackageConfig;
function PackageConfig(fileName) {
  this.file = new ConfigFile(fileName, [
    'name',
    'main',
    ['directories', [
      'lib',
      'dist',
      'baseURL',
      'packages'
    ]],
    ['configFiles', [
      'jspm',
      'jspm:dev',
      'jspm:browser',
      'jspm:node'
    ]],
    'configFile',
    'registry',
    'dependencies',
    'devDependencies',
    'peerDependencies',
    ['jspm', [
      'name',
      'main',
      ['directories', [
        'lib',
        'dist',
        'baseURL',
        'packages'
      ]],
      ['configFiles', [
        'jspm',
        'jspm:dev',
        'jspm:browser',
        'jspm:node'
      ]],
      'configFile',
      'registry',
      'dependencies',
      'devDependencies',
      'peerDependencies',
      'overrides'
    ]],
    'overrides'
  ]);

  this.dir = path.dirname(path.resolve(fileName));

  this.jspmPrefix = this.file.has(['jspm']);
  this.jspmAware = this.jspmPrefix || this.file.has(['registry']);

  // jspm: true is allowed
  try {
    if (this.file.getValue(['jspm']))
      this.jspmPrefix = false;
  }
  catch(e) {}

  if (!this.jspmAware)
    this.jspmPrefix = true;

  this.name = prefixedGetValue.call(this, ['name'], 'string') || !this.jspmAware && 'app';

  var baseURLValue = prefixedGetValue.call(this, ['directories', 'baseURL'], 'string') || '';
  if (baseURLValue[0] == '/' || baseURLValue.indexOf('//') != -1 || baseURLValue.indexOf('\\\\') != -1 || baseURLValue.indexOf(':') != -1) {
    ui.log('warn', 'Server baseURL should be a relative file path. Reverting to current project folder.');
    baseURLValue = '';
  }

  this.baseURL = path.resolve(this.dir, baseURLValue);

  this.populateDefaultPaths();

  this.overrides = prefixedGetObject.call(this, ['overrides'], true) || {};

  this.depsPrefixed = this.jspmPrefix;
  if (this.jspmAware &&
      !this.file.has(['jspm', 'dependencies']) &&
      !this.file.has(['jspm', 'peerDependencies']) &&
      !this.file.has(['jspm', 'devDependencies']) &&
      (this.file.has(['dependencies']) ||
      this.file.has(['peerDependencies']) ||
      this.file.has(['devDependencies'])))
    this.depsPrefixed = false;

  var depsBase = this.depsPrefixed ? ['jspm'] : [];

  var registry = prefixedGetValue.call(this, ['registry'], 'string');

  // only read dependences if package.json is "jspm aware"
  if (this.jspmAware) {
    this.dependencies = processDeps(this.file.getObject(depsBase.concat(['dependencies'])), registry);
    this.peerDependencies = processDeps(this.file.getObject(depsBase.concat(['peerDependencies'])), registry);
    this.devDependencies = processDeps(this.file.getObject(depsBase.concat(['devDependencies'])), registry);

    // dedupe deps - must be either a devDependency, dependency or peerDependency
    var self = this;
    Object.keys(this.devDependencies).forEach(function(dep) {
      if (self.peerDependencies && self.peerDependencies[dep] || self.dependencies && self.dependencies[dep])
        delete self.devDependencies[dep];
    });
    Object.keys(this.dependencies).forEach(function(dep) {
      if (self.peerDependencies && self.peerDependencies[dep])
        delete self.dependencies[dep];
    });
}
  else {
    this.dependencies = {};
    this.peerDependencies = {};
    this.devDependencies = {};
  }
}

PackageConfig.prototype.populateDefaultPaths = function(forceValidDefaults) {
  var libValue = prefixedGetValue.call(this, ['directories', 'lib'], 'string');
  this.hasLib = !!libValue;
  this.lib = this.lib || (libValue ? path.resolve(this.dir, libValue) : path.resolve(this.baseURL, 'src'));

  if (path.relative(this.baseURL, this.lib)[0] == '.') {
    if (forceValidDefaults)
      this.lib = path.resolve(this.baseURL, 'src');
    else
      ui.log('warn', '%directories.lib% in the package.json must be within the baseURL for paths to resolve correctly.');
  }

  var distValue = prefixedGetValue.call(this, ['directories', 'dist'], 'string');
  this.dist = distValue ? path.resolve(this.dir, distValue) : path.resolve(this.baseURL, 'dist');

  if (path.relative(this.baseURL, this.dist)[0] == '.') {
    if (forceValidDefaults)
      this.dist = path.resolve(this.baseURL, 'dist');
    else
      ui.log('warn', '%directories.dist% in the package.json must be within the baseURL for paths to resolve correctly.');
  }

  var packagesValue = prefixedGetValue.call(this, ['directories', 'packages'], 'string');
  this.packages = packagesValue ? path.resolve(this.dir, packagesValue) : path.resolve(this.baseURL, 'jspm_packages');

  if (path.relative(this.baseURL, this.packages)[0] == '.') {
    if (forceValidDefaults)
      this.packages = path.resolve(this.baseURL, 'jspm_packages');
    else
      ui.log('warn', '%directories.packages% in the package.json must be within the baseURL for paths to resolve correctly.');
  }

  var configFileValue = prefixedGetValue.call(this, ['configFiles', 'jspm'], 'string') || prefixedGetValue.call(this, ['configFile'], 'string');
  this.configFile = configFileValue ? path.resolve(this.dir, configFileValue) : path.resolve(this.baseURL, 'jspm.config.js');

  // these are only created when explicitly opting in
  this.configFileDev = prefixedGetValue.call(this, ['configFiles', 'jspm:dev'], 'string') || path.dirname(this.configFile) + path.sep + 'jspm.dev.js';
  this.configFileBrowser = prefixedGetValue.call(this, ['configFiles', 'jspm:browser'], 'string') || path.dirname(this.configFile) + path.sep + 'jspm.browser.js';
  this.configFileNode = prefixedGetValue.call(this, ['configFiles', 'jspm:node'], 'string') || path.dirname(this.configFile) + path.sep + 'jspm.node.js';

  if (config.loader)
    config.loader.file.rename(this.configFile);
};

PackageConfig.prototype.setPrefix = function(jspmPrefix) {
  // removes the "jspm" property in the package.json
  // flattening it down the to base-level
  if (this.jspmPrefix && this.file.has(['jspm']) && !jspmPrefix) {
    var jspmProperties = this.file.getProperties(['jspm']);
    var baseProperties = this.file.getProperties([]);

    var depsPrefixed = this.depsPrefixed;
    if (depsPrefixed) {
      this.file.remove(['dependencies']);
      this.file.remove(['peerDependencies']);
      this.file.remove(['devDependencies']);
    }

    var self = this;

    jspmProperties.forEach(function(prop) {
      self.file.remove([prop.key]);
      baseProperties.push(prop);
    });

    this.file.remove(['jspm']);

    this.file.changed = true;
    this.jspmPrefix = false;
  }
  else if (!this.jspmPrefix && jspmPrefix) {
    this.jspmPrefix = true;
    this.depsBase = ['jspm'];

    if (this.file.getValue(['jspm']))
      this.file.remove(['jspm']);
  }
};

PackageConfig.prototype.write = function() {
  // sync public properties with underlying file representation
  var registry = prefixedGetValue.call(this, ['registry'], 'string');
  function writeDependencies(dependencies) {
    var outDependencies = {};

    Object.keys(dependencies).forEach(function(depName) {
      var dep = dependencies[depName];

      if (!dep)
        return;

      var depValue;

      if (dep.registry == registry) {
        if (depName == dep.package)
          depValue = dep.version || '*';
        else
          depValue = dep.exactPackage;
      }
      else {
        depValue = dep.exactName;
      }

      outDependencies[depName] = depValue;
    });

    return outDependencies;
  }

  if (this.name) {
    prefixedSetValue.call(this, ['name'], this.name, this.jspmAware && 'app');
  }
  else {
    this.file.remove(['name']);
    this.file.remove(['jspm', 'name']);
  }

  var depsBase = this.depsPrefixed ? ['jspm'] : [];

  if (this.main)
    prefixedSetValue.call(this, ['main'], this.main);

  this.file.setObject(depsBase.concat('dependencies'), writeDependencies(this.dependencies), !this.file.has(['dependencies']) && !this.file.has(['jspm', 'dependencies']));
  this.file.setObject(depsBase.concat('peerDependencies'), writeDependencies(this.peerDependencies), !this.file.has(['peerDependencies']) && !this.file.has(['jspm', 'peerDependencies']));
  this.file.setObject(depsBase.concat('devDependencies'), writeDependencies(this.devDependencies), !this.file.has(['devDependencies']) && !this.file.has(['jspm', 'devDependencies']));

  var self = this;
  Object.keys(this.overrides).forEach(function(o) {
    if (!hasProperties(self.overrides[o]))
      delete self.overrides[o];
  });
  prefixedSetObject.call(this, ['overrides'], this.overrides, true);

  var baseURL = toRelativePath.call(this, this.baseURL);
  var baseURLPath = baseURL + (baseURL ? '/' : '');

  prefixedSetValue.call(this, ['directories', 'baseURL'], baseURL || '.', '.');
  prefixedSetValue.call(this, ['directories', 'packages'], toRelativePath.call(this, this.packages), baseURLPath + 'jspm_packages');
  if (this.hasLib)
    prefixedSetValue.call(this, ['directories', 'lib'], toRelativePath.call(this, this.lib));
  prefixedSetValue.call(this, ['directories', 'dist'], toRelativePath.call(this, this.dist), baseURLPath + 'dist');

  prefixedSetValue.call(this, ['configFiles', 'jspm'], toRelativePath.call(this, this.configFile), baseURLPath + 'jspm.config.js');

  var configDir = toRelativePath.call(this, path.dirname(this.configFile));
  configDir = configDir + (configDir ? '/' : '');

  if (this.configFileDev)
    prefixedSetValue.call(this, ['configFiles', 'jspm:dev'], toRelativePath.call(this, this.configFileDev), configDir + 'jspm.dev.js');
  else
    this.file.remove(['jspm', 'configFiles', 'jspm:dev']) && this.file.remove(['configFiles', 'jspm:dev']);

  if (this.configFileBrowser)
    prefixedSetValue.call(this, ['configFiles', 'jspm:browser'], toRelativePath.call(this, this.configFileBrowser), configDir + 'jspm.browser.js');
  else
    this.file.remove(['jspm', 'configFiles', 'jspm:browser']) && this.file.remove(['configFiles', 'jspm:browser']);

  if (this.configFileNode)
    prefixedSetValue.call(this, ['configFiles', 'jspm:node'], toRelativePath.call(this, this.configFileNode), configDir + 'jspm.node.js');
  else
    this.file.remove(['jspm', 'configFiles', 'jspm:node']) && this.file.remove(['configFiles', 'jspm:node']);

  // always ensure we save as jspm aware
  if (!this.file.has(['jspm']) && !this.file.has(['registry'])) {
    if (this.jspmPrefix)
      this.file.setObject(['jspm'], {});
    else
      this.file.setValue(['jspm'], true);
  }

  return this.file.write();
};

function prefixedSetObject(memberArray, object, clearIfEmpty) {
  var prefixed = ['jspm'].concat(memberArray);

  var newPrefixed = this.jspmPrefix && !this.jspmAware;

  if (!newPrefixed && this.file.has(prefixed))
    this.file.setObject(prefixed, object, clearIfEmpty);
  else if (!newPrefixed && this.file.has(memberArray))
    this.file.setObject(memberArray, object, clearIfEmpty);
  else if (this.jspmPrefix)
    this.file.setObject(prefixed, object, clearIfEmpty);
  else
    this.file.setObject(memberArray, object, clearIfEmpty);
}

function prefixedSetValue(memberArray, value, defaultValue) {
  var prefixed = ['jspm'].concat(memberArray);

  var newPrefixed = this.jspmPrefix && !this.jspmAware;

  // if already specified, continue to specify
  if (!newPrefixed && this.file.has(prefixed))
    this.file.setValue(prefixed, value);
  else if (!newPrefixed && this.file.has(memberArray))
    this.file.setValue(memberArray, value);

  // otherwise only specify if not default
  else if (this.jspmPrefix && value !== defaultValue)
    this.file.setValue(prefixed, value);
  else if (value !== defaultValue)
    this.file.setValue(memberArray, value);
}

function prefixedGetValue(memberArray, type) {
  return this.jspmPrefix && this.file.getValue(['jspm'].concat(memberArray), type) || this.file.getValue(memberArray, type);
}

function prefixedGetObject(memberArray, nested) {
  return this.jspmPrefix && this.file.getObject(['jspm'].concat(memberArray), nested) || this.file.getObject(memberArray, nested);
}

function toRelativePath(absPath) {
  return path.relative(this.dir, absPath).replace(/\\/g, '/');
}<commit_msg>fix support for empty string lib<commit_after>/*
 *   Copyright 2014-2016 Guy Bedford (http://guybedford.com)
 *
 *   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 ConfigFile = require('./config-file');
var path = require('path');
var ui = require('../ui');
var processDeps = require('../common').processDeps;
var hasProperties = require('../common').hasProperties;
var config = require('./index');

/*
 * Package.json Configuration Class
 *
 * Public Properties
 * - name
 * - packages
 * - baseURL
 * - lib
 * - dist
 * - configFile
 * - configFileDev
 * - configFileBrowser
 * - configFileNode
 * - dependencies
 * - peerDependencies
 * - devDependencies
 * - overrides
 *
 * Public Methods
 * - write
 * - prompt
 *
 */
module.exports = PackageConfig;
function PackageConfig(fileName) {
  this.file = new ConfigFile(fileName, [
    'name',
    'main',
    ['directories', [
      'lib',
      'dist',
      'baseURL',
      'packages'
    ]],
    ['configFiles', [
      'jspm',
      'jspm:dev',
      'jspm:browser',
      'jspm:node'
    ]],
    'configFile',
    'registry',
    'dependencies',
    'devDependencies',
    'peerDependencies',
    ['jspm', [
      'name',
      'main',
      ['directories', [
        'lib',
        'dist',
        'baseURL',
        'packages'
      ]],
      ['configFiles', [
        'jspm',
        'jspm:dev',
        'jspm:browser',
        'jspm:node'
      ]],
      'configFile',
      'registry',
      'dependencies',
      'devDependencies',
      'peerDependencies',
      'overrides'
    ]],
    'overrides'
  ]);

  this.dir = path.dirname(path.resolve(fileName));

  this.jspmPrefix = this.file.has(['jspm']);
  this.jspmAware = this.jspmPrefix || this.file.has(['registry']);

  // jspm: true is allowed
  try {
    if (this.file.getValue(['jspm']))
      this.jspmPrefix = false;
  }
  catch(e) {}

  if (!this.jspmAware)
    this.jspmPrefix = true;

  this.name = prefixedGetValue.call(this, ['name'], 'string') || !this.jspmAware && 'app';

  var baseURLValue = prefixedGetValue.call(this, ['directories', 'baseURL'], 'string') || '';
  if (baseURLValue[0] == '/' || baseURLValue.indexOf('//') != -1 || baseURLValue.indexOf('\\\\') != -1 || baseURLValue.indexOf(':') != -1) {
    ui.log('warn', 'Server baseURL should be a relative file path. Reverting to current project folder.');
    baseURLValue = '';
  }

  this.baseURL = path.resolve(this.dir, baseURLValue);

  this.populateDefaultPaths();

  this.overrides = prefixedGetObject.call(this, ['overrides'], true) || {};

  this.depsPrefixed = this.jspmPrefix;
  if (this.jspmAware &&
      !this.file.has(['jspm', 'dependencies']) &&
      !this.file.has(['jspm', 'peerDependencies']) &&
      !this.file.has(['jspm', 'devDependencies']) &&
      (this.file.has(['dependencies']) ||
      this.file.has(['peerDependencies']) ||
      this.file.has(['devDependencies'])))
    this.depsPrefixed = false;

  var depsBase = this.depsPrefixed ? ['jspm'] : [];

  var registry = prefixedGetValue.call(this, ['registry'], 'string');

  // only read dependences if package.json is "jspm aware"
  if (this.jspmAware) {
    this.dependencies = processDeps(this.file.getObject(depsBase.concat(['dependencies'])), registry);
    this.peerDependencies = processDeps(this.file.getObject(depsBase.concat(['peerDependencies'])), registry);
    this.devDependencies = processDeps(this.file.getObject(depsBase.concat(['devDependencies'])), registry);

    // dedupe deps - must be either a devDependency, dependency or peerDependency
    var self = this;
    Object.keys(this.devDependencies).forEach(function(dep) {
      if (self.peerDependencies && self.peerDependencies[dep] || self.dependencies && self.dependencies[dep])
        delete self.devDependencies[dep];
    });
    Object.keys(this.dependencies).forEach(function(dep) {
      if (self.peerDependencies && self.peerDependencies[dep])
        delete self.dependencies[dep];
    });
}
  else {
    this.dependencies = {};
    this.peerDependencies = {};
    this.devDependencies = {};
  }
}

PackageConfig.prototype.populateDefaultPaths = function(forceValidDefaults) {
  var libValue = prefixedGetValue.call(this, ['directories', 'lib'], 'string');
  this.hasLib = typeof libValue == 'string';
  this.lib = this.hasLib ? libValue || '.' : (libValue ? path.resolve(this.dir, libValue) : path.resolve(this.baseURL, 'src'));

  if (path.relative(this.baseURL, this.lib)[0] == '.') {
    if (forceValidDefaults)
      this.lib = path.resolve(this.baseURL, 'src');
    else
      ui.log('warn', '%directories.lib% in the package.json must be within the baseURL for paths to resolve correctly.');
  }

  var distValue = prefixedGetValue.call(this, ['directories', 'dist'], 'string');
  this.dist = typeof distValue == 'string' ? path.resolve(this.dir, distValue) : path.resolve(this.baseURL, 'dist');

  if (path.relative(this.baseURL, this.dist)[0] == '.') {
    if (forceValidDefaults)
      this.dist = path.resolve(this.baseURL, 'dist');
    else
      ui.log('warn', '%directories.dist% in the package.json must be within the baseURL for paths to resolve correctly.');
  }

  var packagesValue = prefixedGetValue.call(this, ['directories', 'packages'], 'string');
  this.packages = typeof packagesValue == 'string' ? path.resolve(this.dir, packagesValue) : path.resolve(this.baseURL, 'jspm_packages');

  if (path.relative(this.baseURL, this.packages)[0] == '.') {
    if (forceValidDefaults)
      this.packages = path.resolve(this.baseURL, 'jspm_packages');
    else
      ui.log('warn', '%directories.packages% in the package.json must be within the baseURL for paths to resolve correctly.');
  }

  var configFileValue = prefixedGetValue.call(this, ['configFiles', 'jspm'], 'string') || prefixedGetValue.call(this, ['configFile'], 'string');
  this.configFile = configFileValue ? path.resolve(this.dir, configFileValue) : path.resolve(this.baseURL, 'jspm.config.js');

  // these are only created when explicitly opting in
  this.configFileDev = prefixedGetValue.call(this, ['configFiles', 'jspm:dev'], 'string') || path.dirname(this.configFile) + path.sep + 'jspm.dev.js';
  this.configFileBrowser = prefixedGetValue.call(this, ['configFiles', 'jspm:browser'], 'string') || path.dirname(this.configFile) + path.sep + 'jspm.browser.js';
  this.configFileNode = prefixedGetValue.call(this, ['configFiles', 'jspm:node'], 'string') || path.dirname(this.configFile) + path.sep + 'jspm.node.js';

  if (config.loader)
    config.loader.file.rename(this.configFile);
};

PackageConfig.prototype.setPrefix = function(jspmPrefix) {
  // removes the "jspm" property in the package.json
  // flattening it down the to base-level
  if (this.jspmPrefix && this.file.has(['jspm']) && !jspmPrefix) {
    var jspmProperties = this.file.getProperties(['jspm']);
    var baseProperties = this.file.getProperties([]);

    var depsPrefixed = this.depsPrefixed;
    if (depsPrefixed) {
      this.file.remove(['dependencies']);
      this.file.remove(['peerDependencies']);
      this.file.remove(['devDependencies']);
    }

    var self = this;

    jspmProperties.forEach(function(prop) {
      self.file.remove([prop.key]);
      baseProperties.push(prop);
    });

    this.file.remove(['jspm']);

    this.file.changed = true;
    this.jspmPrefix = false;
  }
  else if (!this.jspmPrefix && jspmPrefix) {
    this.jspmPrefix = true;
    this.depsBase = ['jspm'];

    if (this.file.getValue(['jspm']))
      this.file.remove(['jspm']);
  }
};

PackageConfig.prototype.write = function() {
  // sync public properties with underlying file representation
  var registry = prefixedGetValue.call(this, ['registry'], 'string');
  function writeDependencies(dependencies) {
    var outDependencies = {};

    Object.keys(dependencies).forEach(function(depName) {
      var dep = dependencies[depName];

      if (!dep)
        return;

      var depValue;

      if (dep.registry == registry) {
        if (depName == dep.package)
          depValue = dep.version || '*';
        else
          depValue = dep.exactPackage;
      }
      else {
        depValue = dep.exactName;
      }

      outDependencies[depName] = depValue;
    });

    return outDependencies;
  }

  if (this.name) {
    prefixedSetValue.call(this, ['name'], this.name, this.jspmAware && 'app');
  }
  else {
    this.file.remove(['name']);
    this.file.remove(['jspm', 'name']);
  }

  var depsBase = this.depsPrefixed ? ['jspm'] : [];

  if (this.main)
    prefixedSetValue.call(this, ['main'], this.main);

  this.file.setObject(depsBase.concat('dependencies'), writeDependencies(this.dependencies), !this.file.has(['dependencies']) && !this.file.has(['jspm', 'dependencies']));
  this.file.setObject(depsBase.concat('peerDependencies'), writeDependencies(this.peerDependencies), !this.file.has(['peerDependencies']) && !this.file.has(['jspm', 'peerDependencies']));
  this.file.setObject(depsBase.concat('devDependencies'), writeDependencies(this.devDependencies), !this.file.has(['devDependencies']) && !this.file.has(['jspm', 'devDependencies']));

  var self = this;
  Object.keys(this.overrides).forEach(function(o) {
    if (!hasProperties(self.overrides[o]))
      delete self.overrides[o];
  });
  prefixedSetObject.call(this, ['overrides'], this.overrides, true);

  var baseURL = toRelativePath.call(this, this.baseURL);
  var baseURLPath = baseURL + (baseURL ? '/' : '');

  prefixedSetValue.call(this, ['directories', 'baseURL'], baseURL || '.', '.');
  prefixedSetValue.call(this, ['directories', 'packages'], toRelativePath.call(this, this.packages), baseURLPath + 'jspm_packages');
  if (this.hasLib)
    prefixedSetValue.call(this, ['directories', 'lib'], toRelativePath.call(this, this.lib) || '.');
  prefixedSetValue.call(this, ['directories', 'dist'], toRelativePath.call(this, this.dist), baseURLPath + 'dist');

  prefixedSetValue.call(this, ['configFiles', 'jspm'], toRelativePath.call(this, this.configFile), baseURLPath + 'jspm.config.js');

  var configDir = toRelativePath.call(this, path.dirname(this.configFile));
  configDir = configDir + (configDir ? '/' : '');

  if (this.configFileDev)
    prefixedSetValue.call(this, ['configFiles', 'jspm:dev'], toRelativePath.call(this, this.configFileDev), configDir + 'jspm.dev.js');
  else
    this.file.remove(['jspm', 'configFiles', 'jspm:dev']) && this.file.remove(['configFiles', 'jspm:dev']);

  if (this.configFileBrowser)
    prefixedSetValue.call(this, ['configFiles', 'jspm:browser'], toRelativePath.call(this, this.configFileBrowser), configDir + 'jspm.browser.js');
  else
    this.file.remove(['jspm', 'configFiles', 'jspm:browser']) && this.file.remove(['configFiles', 'jspm:browser']);

  if (this.configFileNode)
    prefixedSetValue.call(this, ['configFiles', 'jspm:node'], toRelativePath.call(this, this.configFileNode), configDir + 'jspm.node.js');
  else
    this.file.remove(['jspm', 'configFiles', 'jspm:node']) && this.file.remove(['configFiles', 'jspm:node']);

  // always ensure we save as jspm aware
  if (!this.file.has(['jspm']) && !this.file.has(['registry'])) {
    if (this.jspmPrefix)
      this.file.setObject(['jspm'], {});
    else
      this.file.setValue(['jspm'], true);
  }

  return this.file.write();
};

function prefixedSetObject(memberArray, object, clearIfEmpty) {
  var prefixed = ['jspm'].concat(memberArray);

  var newPrefixed = this.jspmPrefix && !this.jspmAware;

  if (!newPrefixed && this.file.has(prefixed))
    this.file.setObject(prefixed, object, clearIfEmpty);
  else if (!newPrefixed && this.file.has(memberArray))
    this.file.setObject(memberArray, object, clearIfEmpty);
  else if (this.jspmPrefix)
    this.file.setObject(prefixed, object, clearIfEmpty);
  else
    this.file.setObject(memberArray, object, clearIfEmpty);
}

function prefixedSetValue(memberArray, value, defaultValue) {
  var prefixed = ['jspm'].concat(memberArray);

  var newPrefixed = this.jspmPrefix && !this.jspmAware;

  // if already specified, continue to specify
  if (!newPrefixed && this.file.has(prefixed))
    this.file.setValue(prefixed, value);
  else if (!newPrefixed && this.file.has(memberArray))
    this.file.setValue(memberArray, value);

  // otherwise only specify if not default
  else if (this.jspmPrefix && value !== defaultValue)
    this.file.setValue(prefixed, value);
  else if (value !== defaultValue)
    this.file.setValue(memberArray, value);
}

function prefixedGetValue(memberArray, type) {
  var value;
  if (this.jspmPrefix)
    value = this.file.getValue(['jspm'].concat(memberArray), type);
  if (typeof value == 'undefined')
    value = this.file.getValue(memberArray, type);
  return value;
}

function prefixedGetObject(memberArray, nested) {
  return this.jspmPrefix && this.file.getObject(['jspm'].concat(memberArray), nested) || this.file.getObject(memberArray, nested);
}

function toRelativePath(absPath) {
  return path.relative(this.dir, absPath).replace(/\\/g, '/');
}<|endoftext|>


<commit_before>'use strict';
/* global describe it beforeEach afterEach */

/*
 * Unit tests for proxying failures to an upstream content service.
 */

const before = require('./helpers/before');

const chai = require('chai');
const dirtyChai = require('dirty-chai');
chai.use(dirtyChai);

const nock = require('nock');
const request = require('supertest');
const storage = require('../src/storage');
const server = require('../src/server');
const resetHelper = require('./helpers/reset');

describe('upstream', () => {
  beforeEach(resetHelper);
  beforeEach(before.configureWith({
    PROXY_UPSTREAM: 'https://upstream'
  }));

  // Prepopulate local storage with content.
  beforeEach((done) => storage.storeContent('local', { body: 'local' }, done));

  it('returns local content the same', (done) => {
    request(server.create())
      .get('/content/local')
      .set('Accept', 'application/json')
      .expect(200)
      .expect('Content-Type', 'application/json')
      .expect({ assets: {}, envelope: { body: 'local' } }, done);
  });

  it('returns assets merged from local and upstream');

  it('queries the upstream content service when content is not found locally', (done) => {
    nock('https://upstream')
      .get('/content/remote').reply(200, { assets: {}, envelope: { body: 'remote' } });

    request(server.create())
      .get('/content/remote')
      .set('Accept', 'application/json')
      .expect(200)
      .expect('Content-Type', 'application/json')
      .expect({ assets: {}, envelope: { body: 'remote' } }, done);
  });

  it('propagates lookup failures from the upstream content service', (done) => {
    nock('https://upstream')
      .get('/content/remote').reply(404);

    request(server.create())
      .get('/content/remote')
      .set('Accept', 'application/json')
      .expect(404, done);
  });

  it('reports non-404 failures from upstream as 502s');

  afterEach(before.reconfigure);
});
<commit_msg>Unit test for non-404 errors from upstream.<commit_after>'use strict';
/* global describe it beforeEach afterEach */

/*
 * Unit tests for proxying failures to an upstream content service.
 */

const before = require('./helpers/before');

const chai = require('chai');
const dirtyChai = require('dirty-chai');
chai.use(dirtyChai);

const nock = require('nock');
const request = require('supertest');
const storage = require('../src/storage');
const server = require('../src/server');
const resetHelper = require('./helpers/reset');

describe('upstream', () => {
  beforeEach(resetHelper);
  beforeEach(before.configureWith({
    PROXY_UPSTREAM: 'https://upstream'
  }));

  // Prepopulate local storage with content.
  beforeEach((done) => storage.storeContent('local', { body: 'local' }, done));

  it('returns local content the same', (done) => {
    request(server.create())
      .get('/content/local')
      .set('Accept', 'application/json')
      .expect(200)
      .expect('Content-Type', 'application/json')
      .expect({ assets: {}, envelope: { body: 'local' } }, done);
  });

  it('returns assets merged from local and upstream');

  it('queries the upstream content service when content is not found locally', (done) => {
    nock('https://upstream')
      .get('/content/remote').reply(200, { assets: {}, envelope: { body: 'remote' } });

    request(server.create())
      .get('/content/remote')
      .set('Accept', 'application/json')
      .expect(200)
      .expect('Content-Type', 'application/json')
      .expect({ assets: {}, envelope: { body: 'remote' } }, done);
  });

  it('propagates lookup failures from the upstream content service', (done) => {
    nock('https://upstream')
      .get('/content/remote').reply(404);

    request(server.create())
      .get('/content/remote')
      .set('Accept', 'application/json')
      .expect(404, done);
  });

  it('reports non-404 failures from upstream as 502s', (done) => {
    nock('https://upstream')
      .get('/content/remote').reply(500, { message: 'wtf' });

    request(server.create())
      .get('/content/remote')
      .set('Accept', 'application/json')
      .expect(502, done);
  });

  afterEach(before.reconfigure);
});
<|endoftext|>


<commit_before>'use strict';

var compact    = require('es5-ext/lib/Array/prototype/compact')
  , i          = require('es5-ext/lib/Function/i')
  , partial    = require('es5-ext/lib/Function/prototype/partial')
  , mapToArray = require('es5-ext/lib/Object/map-to-array')
  , callable   = require('es5-ext/lib/Object/valid-callable')
  , value      = require('es5-ext/lib/Object/valid-value')
  , numPad     = require('es5-ext/lib/Number/prototype/pad')
  , pad        = require('es5-ext/lib/String/prototype/pad')
  , memoize    = require('memoizee')
  , clc        = require('cli-color')
  , readFile   = require('next/lib/fs/read-file')
  , normalize  = require('./_normalize-source')

  , isArray = Array.isArray, ceil = Math.ceil
  , log = process.stdout.write.bind(process.stdout)
  , nextTick = process.nextTick
  , reportFile, isStatus

  , eolRe = /(?:\r\n|[\n\r\u2028\u2029])/
  , lname = clc.bold, lgray = clc.gray, lerr = clc.yellow, lok = clc.green
	, lopts, lstatOk = i, lstatFail = clc.bold.red, lstatErr = clc.red
  , lcount = clc.xterm(232), lline = clc.xterm(240);

lopts = function (options) {
	options = compact.call(mapToArray(options, function (name, value) {
		if (value == true) {
			return name;
		} else if (value === false) {
			return null;
		} else if (isArray(value)) {
			return value.join(', ');
		} else {
			return value;
		}
	}));
	return lgray('(' + (options.length ? options.join('|') : 'no options')  + ')');
};

reportFile = function (name, report) {
	var str = '', countPad, srcPad;
	isStatus = false;
	str += (name ? (lname(name) + ' ') : '') + lopts(report.options);
	if (report.length) {
		str += '\n';
		countPad = partial.call(pad, ' ', String(report.length).length);
		srcPad = partial.call(numPad, String(report.srcLines.length).length);
		report.forEach(function (data, index) {
			str += lcount('#' + countPad.call(index + 1)) + ' ' + lerr(data.message)
				+ '\n' + lline(srcPad.call(data.line) + ':')
				+ report.srcLines[data.line - 1] + '\n';
		});
	} else {
		str += ' ' + lok('OK') + '\n';
	}
	log(str + '\n');
};

module.exports = function (report, options) {
	var root, reports, process, promise, reportStatus;
	callable(report) && value(options);

	process = function (report, name) {
		if (report.length) {
			if (!report.src) {
				return readFile(report.path, { loose: true })(function (src) {
					if (src) {
						report.src = normalize(String(src));
						return process(report, name);
					}
				});
			} else {
				report.srcLines = report.src.split(eolRe);
				reportFile(name, report);
				reportStatus(reports);
			}
		}
		return report;
	};

	reportStatus = memoize(function () {
		nextTick(function () {
			var ok;
			reports.slice(reports.parsed).forEach(function (report) {
				if (report.length) {
					++reports.failed;
					reports.errors += report.length;
				}
			});
			reports.parsed = reports.length;
			ok = (reports.length - reports.failed);
			log(lstatOk(ok + ' OK ['
				+ ((ok / reports.length) * 100).toFixed(2)
				+ '%]') + '  ' + lstatFail(reports.failed + ' Failed') + ' '
				+ lstatErr('[' + reports.errors + ' Errors]') + '\n\n');
			isStatus = true;
			reportStatus.clear();
		});
	});

	root = report.root;
	if (options.progress) {
		reports = [];
		reports.parsed = 0;
		reports.errors = 0;
		reports.failed = 0;
		report.on('change', function (event) {
			reports.push(process(event.report, event.name));
		});
		promise = report(function (report) {
			if (isArray(report)) {
				reports.push(process(report));
			}
			return reports;
		});
	} else {
		promise = report(function (data) {
			reports = isArray(data) ? [process(data)] : mapToArray(data, process);
			reports.parsed = 0;
			reports.errors = 0;
			reports.failed = 0;
			return reports;
		});
	}
	return promise(function (data) {
		if (!data.length) {
			console.log("No files to process");
		}
	});
};
<commit_msg>Better style<commit_after>'use strict';

var compact    = require('es5-ext/lib/Array/prototype/compact')
  , i          = require('es5-ext/lib/Function/i')
  , partial    = require('es5-ext/lib/Function/prototype/partial')
  , mapToArray = require('es5-ext/lib/Object/map-to-array')
  , callable   = require('es5-ext/lib/Object/valid-callable')
  , value      = require('es5-ext/lib/Object/valid-value')
  , numPad     = require('es5-ext/lib/Number/prototype/pad')
  , pad        = require('es5-ext/lib/String/prototype/pad')
  , memoize    = require('memoizee')
  , clc        = require('cli-color')
  , readFile   = require('next/lib/fs/read-file')
  , normalize  = require('./_normalize-source')

  , isArray = Array.isArray, ceil = Math.ceil
  , log = process.stdout.write.bind(process.stdout)
  , nextTick = process.nextTick
  , reportFile, isStatus

  , eolRe = /(?:\r\n|[\n\r\u2028\u2029])/
  , lname = clc.bold, lgray = clc.gray, lerr = clc.yellow, lok = clc.green
	, lopts, lstatOk = i, lstatFail = clc.bold.red, lstatErr = clc.red
  , lcount = clc.xterm(232), lline = clc.xterm(240), lcode = clc.xterm(250)
  , lchar = clc.xterm(250).bgXterm(235)

lopts = function (options) {
	options = compact.call(mapToArray(options, function (name, value) {
		if (value == true) {
			return name;
		} else if (value === false) {
			return null;
		} else if (isArray(value)) {
			return value.join(', ');
		} else {
			return value;
		}
	}));
	return lgray('(' + (options.length ? options.join('|') : 'no options')  + ')');
};

reportFile = function (name, report) {
	var str = '', countPad, srcPad;
	isStatus = false;
	str += (name ? (lname(name) + ' ') : '') + lopts(report.options);
	if (report.length) {
		str += '\n';
		countPad = partial.call(pad, ' ', String(report.length).length);
		srcPad = partial.call(numPad, String(report.srcLines.length).length);
		report.forEach(function (data, index) {
			var line = report.srcLines[data.line - 1].replace(/\t/g, '    ')
			  , at = data.character - 1;
			str += lcount('#' + countPad.call(index + 1)) + ' ' + lerr(data.message)
				+ '\n' + lline(srcPad.call(data.line) + ' ')
				+ lcode(line.slice(0, at)) + lchar(line[at]) + lcode(line.slice(at + 1))
				+ '\n';
		});
	} else {
		str += ' ' + lok('OK') + '\n';
	}
	log(str + '\n');
};

module.exports = function (report, options) {
	var root, reports, process, promise, reportStatus;
	callable(report) && value(options);

	process = function (report, name) {
		if (report.length) {
			if (!report.src) {
				return readFile(report.path, { loose: true })(function (src) {
					if (src) {
						report.src = normalize(String(src));
						return process(report, name);
					}
				});
			} else {
				report.srcLines = report.src.split(eolRe);
				reportFile(name, report);
				reportStatus(reports);
			}
		}
		return report;
	};

	reportStatus = memoize(function () {
		nextTick(function () {
			var ok;
			reports.slice(reports.parsed).forEach(function (report) {
				if (report.length) {
					++reports.failed;
					reports.errors += report.length;
				}
			});
			reports.parsed = reports.length;
			ok = (reports.length - reports.failed);
			log(lstatOk(ok + ' OK ['
				+ ((ok / reports.length) * 100).toFixed(2)
				+ '%]') + '  ' + lstatFail(reports.failed + ' Failed') + ' '
				+ lstatErr('[' + reports.errors + ' Errors]') + '\n\n');
			isStatus = true;
			reportStatus.clear();
		});
	});

	root = report.root;
	if (options.progress) {
		reports = [];
		reports.parsed = 0;
		reports.errors = 0;
		reports.failed = 0;
		report.on('change', function (event) {
			reports.push(process(event.report, event.name));
		});
		promise = report(function (report) {
			if (isArray(report)) {
				reports.push(process(report));
			}
			return reports;
		});
	} else {
		promise = report(function (data) {
			reports = isArray(data) ? [process(data)] : mapToArray(data, process);
			reports.parsed = 0;
			reports.errors = 0;
			reports.failed = 0;
			return reports;
		});
	}
	return promise(function (data) {
		if (!data.length) {
			console.log("No files to process");
		}
	});
};
<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')
const path = require('path')

const rimraf = require('rimraf')
const chalk = require('chalk')

const console = require('../helpers/color-console')
const sfs = require('../helpers/sfs')
const {installWatcher, installDevelopmentWatcher} = require('../helpers/watcher')

const {build, createAndGetBuildFolder} = require('./builder')
const loader = require('./loader')

const {assetsToCopy} = require('../assets')
const config = require('../config')

// -------------------------------------------------------------
// Module.
// -------------------------------------------------------------

function generate (entryPoint) {
  console.log(`Starting directory: ${chalk.green(entryPoint)}`)

  cleanBuildFolder()

  const pages = findData(entryPoint)

  if (countDataFiles(pages) === 0) {
    console.log('')
    console.warn('No data files found!')
    return
  }

  generateHTML(pages)
  exportAssets()

  console.log('')
  console.log('Done! 👌')

  if (config.commands.build.watch) {
    const port = config.commands.build.port
    const address = chalk.green(`http://localhost:${port}/`)
    showHeader(`Watching and serving files from ${address}`)
    startWatcher(entryPoint, () => generateHTML(findData(entryPoint)))
  }
}

function cleanBuildFolder () {
  if (!config.commands.build.cleanBuildFolder) return

  showHeader('Cleaning build folder')
  rimraf.sync(createAndGetBuildFolder())
}

function findData (entryPoint) {
  showHeader('Finding data')

  const pages = {products: []}

  // Inspect given path for data files and get all correct ones.
  let files = sfs.findAllFiles(entryPoint, { maxDepth: 1, ignoredFolders: ['build', 'node_modules'] })

  files.filter(isDataFile).forEach(file => {
    try {
      let presskit = loader.loadDataFile(file)
      if (!presskit) return

      console.log(`- ${presskit.type}: "${presskit.title}" ${chalk.dim(file)}`)

      // presskit() compatibility support:
      // If we find a "game" file at the top-level, it's probably a company.
      if (path.dirname(file) === entryPoint && presskit.type !== 'company') {
        console.warn('This top-level `data.xml` root tag should be `<company>`, not `<game>`! ')
        console.warn('If this is a legacy presskit(), please check the migration guide:')
        console.log(chalk.blue('https://github.com/pixelnest/presskit.html#migration-guide'))
        console.log('')

        presskit.type = 'company'
      }

      if (presskit.type === 'company') {
        if (pages.company) {
          console.warn('Multiple companies detected. This is not supported yet, only the last will be used!')
        }

        pages.company = { path: entryPoint, presskit: presskit }
      } else {
        pages.products.push({ path: file, presskit: presskit })
      }
    } catch (err) {
      console.error(`There was an error during the parsing of \`${file}\`. Check that your XML document is valid.`)
      console.error('You can use a validator like this: ' + chalk.blue('http://codebeautify.org/xmlvalidator'))
      process.exit()
    }
  })

  return pages
}

function generateHTML (pages) {
  showHeader('Generating HTML')

  const productsList = []

  let analytics = ''
  if (pages.company && pages.company.presskit.analytics) {
    analytics = pages.company.presskit.analytics
  }

  for (const product of pages.products) {
    const outputPath = build(
      product.path,
      product.presskit,
      {
        company: pages.company.presskit,
        analytics
      }
    )

    productsList.push({path: outputPath, title: product.presskit.title})
  }

  // Company should be the last one, listing all the products
  if (pages.company) {
    // Notice that we provide a ref to all the products here.
    build(
      pages.company.path,
      pages.company.presskit,
      {
        products: productsList,
        analytics
      }
    )
  }
}

function exportAssets () {
  showHeader('Exporting assets')

  // Copy assets (CSS and stuff)
  copyMandatoryFiles()
}

// Print a console UI header text.
function showHeader (text) {
  console.log('')
  console.log(chalk.magenta(text + '…'))
}

// Add css and any mandatory files specified to the build directory
function copyMandatoryFiles () {
  let buildDir = createAndGetBuildFolder()

  for (let f of assetsToCopy) {
    let filepath = path.resolve(f)
    let filename = path.basename(filepath)
    let dir = path.basename(path.dirname(filepath))

    let targetDir = path.join(buildDir, dir)
    sfs.createDir(targetDir)

    let targetPath = path.join(targetDir, filename)

    console.log('- ' + targetPath)
    fs.writeFileSync(targetPath, fs.readFileSync(filepath))
  }
}

// Count the number of products/company in the presskit.
function countDataFiles (pages) {
  let count = 0
  count += (pages.company ? 1 : 0)
  count += pages.products.length

  return count
}

// Is a file qualifying to be a data file? ie. `data.xml`.
// We don't check the content here, just the name.
function isDataFile (filename) {
  var ext = path.extname(filename)
  filename = path.basename(filename, ext)

  return filename === 'data' && ext === '.xml'
}

// Start watching files and assets.
function startWatcher (entryPoint, callback) {
  if (config.commands.build.dev) {
    // Delete the assets (CSS/etc.) before.
    // They might not be there, but we must ensure that they are properly
    // deleted.
    //
    // This is necessary, otherwise, remaining copied CSS files will have
    // an higher priority than the ones provided by the server (from
    // the `assets/` folder).
    rimraf(path.join(createAndGetBuildFolder(), 'css'), () => {
      installDevelopmentWatcher(entryPoint, callback)
    })
  } else {
    installWatcher(entryPoint, callback)
  }
}

// -------------------------------------------------------------
// Exports.
// -------------------------------------------------------------

module.exports = {
  generate
}
<commit_msg>Abort if no company found<commit_after>'use strict'

const fs = require('fs')
const path = require('path')

const rimraf = require('rimraf')
const chalk = require('chalk')

const console = require('../helpers/color-console')
const sfs = require('../helpers/sfs')
const {installWatcher, installDevelopmentWatcher} = require('../helpers/watcher')

const {build, createAndGetBuildFolder} = require('./builder')
const loader = require('./loader')

const {assetsToCopy} = require('../assets')
const config = require('../config')

// -------------------------------------------------------------
// Module.
// -------------------------------------------------------------

function generate (entryPoint) {
  console.log(`Starting directory: ${chalk.green(entryPoint)}`)

  cleanBuildFolder()

  const pages = findData(entryPoint)

  if (countDataFiles(pages) === 0) {
    console.log('')
    console.warn('No data files found!')
    return
  }

  if (!pages.company) {
    console.log('')
    console.error('No company data file found!')
    return
  }

  generateHTML(pages)
  exportAssets()

  console.log('')
  console.log('Done! 👌')

  if (config.commands.build.watch) {
    const port = config.commands.build.port
    const address = chalk.green(`http://localhost:${port}/`)
    showHeader(`Watching and serving files from ${address}`)
    startWatcher(entryPoint, () => generateHTML(findData(entryPoint)))
  }
}

function cleanBuildFolder () {
  if (!config.commands.build.cleanBuildFolder) return

  showHeader('Cleaning build folder')
  rimraf.sync(createAndGetBuildFolder())
}

function findData (entryPoint) {
  showHeader('Finding data')

  const pages = {products: []}

  // Inspect given path for data files and get all correct ones.
  let files = sfs.findAllFiles(entryPoint, { maxDepth: 1, ignoredFolders: ['build', 'node_modules'] })

  files.filter(isDataFile).forEach(file => {
    try {
      let presskit = loader.loadDataFile(file)
      if (!presskit) return

      console.log(`- ${presskit.type}: "${presskit.title}" ${chalk.dim(file)}`)

      // presskit() compatibility support:
      // If we find a "game" file at the top-level, it's probably a company.
      if (path.dirname(file) === entryPoint && presskit.type !== 'company') {
        console.warn('This top-level `data.xml` root tag should be `<company>`, not `<game>`! ')
        console.warn('If this is a legacy presskit(), please check the migration guide:')
        console.log(chalk.blue('https://github.com/pixelnest/presskit.html#migration-guide'))
        console.log('')

        presskit.type = 'company'
      }

      if (presskit.type === 'company') {
        if (pages.company) {
          console.warn('Multiple companies detected. This is not supported yet, only the last will be used!')
        }

        pages.company = { path: entryPoint, presskit: presskit }
      } else {
        pages.products.push({ path: file, presskit: presskit })
      }
    } catch (err) {
      console.error(`There was an error during the parsing of \`${file}\`. Check that your XML document is valid.`)
      console.error('You can use a validator like this: ' + chalk.blue('http://codebeautify.org/xmlvalidator'))
      process.exit()
    }
  })

  return pages
}

function generateHTML (pages) {
  showHeader('Generating HTML')

  const productsList = []

  let analytics = ''
  if (pages.company && pages.company.presskit.analytics) {
    analytics = pages.company.presskit.analytics
  }

  for (const product of pages.products) {
    const outputPath = build(
      product.path,
      product.presskit,
      {
        company: pages.company.presskit,
        analytics
      }
    )

    productsList.push({path: outputPath, title: product.presskit.title})
  }

  // Company should be the last one, listing all the products
  if (pages.company) {
    // Notice that we provide a ref to all the products here.
    build(
      pages.company.path,
      pages.company.presskit,
      {
        products: productsList,
        analytics
      }
    )
  }
}

function exportAssets () {
  showHeader('Exporting assets')

  // Copy assets (CSS and stuff)
  copyMandatoryFiles()
}

// Print a console UI header text.
function showHeader (text) {
  console.log('')
  console.log(chalk.magenta(text + '…'))
}

// Add css and any mandatory files specified to the build directory
function copyMandatoryFiles () {
  let buildDir = createAndGetBuildFolder()

  for (let f of assetsToCopy) {
    let filepath = path.resolve(f)
    let filename = path.basename(filepath)
    let dir = path.basename(path.dirname(filepath))

    let targetDir = path.join(buildDir, dir)
    sfs.createDir(targetDir)

    let targetPath = path.join(targetDir, filename)

    console.log('- ' + targetPath)
    fs.writeFileSync(targetPath, fs.readFileSync(filepath))
  }
}

// Count the number of products/company in the presskit.
function countDataFiles (pages) {
  let count = 0
  count += (pages.company ? 1 : 0)
  count += pages.products.length

  return count
}

// Is a file qualifying to be a data file? ie. `data.xml`.
// We don't check the content here, just the name.
function isDataFile (filename) {
  var ext = path.extname(filename)
  filename = path.basename(filename, ext)

  return filename === 'data' && ext === '.xml'
}

// Start watching files and assets.
function startWatcher (entryPoint, callback) {
  if (config.commands.build.dev) {
    // Delete the assets (CSS/etc.) before.
    // They might not be there, but we must ensure that they are properly
    // deleted.
    //
    // This is necessary, otherwise, remaining copied CSS files will have
    // an higher priority than the ones provided by the server (from
    // the `assets/` folder).
    rimraf(path.join(createAndGetBuildFolder(), 'css'), () => {
      installDevelopmentWatcher(entryPoint, callback)
    })
  } else {
    installWatcher(entryPoint, callback)
  }
}

// -------------------------------------------------------------
// Exports.
// -------------------------------------------------------------

module.exports = {
  generate
}
<|endoftext|>


<commit_before>module.exports = function(api, users){
    api.listen({name: 'modules', displayname: 'Modules'},'load modules', 'admin', function(from, interface){
        api.sendMessage('Loading new modules', interface, from);
        api.getModules();
    });

    api.listen({name: 'core', displayname: 'Core'},'yes', 'standard', function(from, interface, message){
        var yesNoQuestion = api.returnLastYesNoQuestion(from);
        if (yesNoQuestion) {
            if (typeof yesNoQuestion.yesCallback === 'function') {
                yesNoQuestion.yesCallback();
            }
            api.removeLastYesNoQuestion(from);
        }
    });

    api.listen({name: 'core', displayname: 'Core'}, 'no', 'standard', function(from, interface, message){
        var yesNoQuestion = api.returnLastYesNoQuestion(from);
        if (yesNoQuestion) {
            if (typeof yesNoQuestion.noCallback === 'function') {
                yesNoQuestion.noCallback();
            }
            api.removeLastYesNoQuestion(from);
        }
    });

    api.listen({name: 'core', displayname: 'Core'}, 'next question', 'standard', function(from, interface, message){
        var yesNoQuestion = api.returnLastYesNoQuestion(from);
        if (yesNoQuestion) {
            api.sendMessage(yesNoQuestion.question, interface, from);
        } else {
            api.sendMessage('No more questions to ask!', interface, from);
        }
    });

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles (ignore|standard) ([^\\s]+?) (.+?)',
        'trusted',
        function(from, interface, message){
            users.findOneAsync({$and: [{name: message[2]}, {interface: message[1]}]}).done(function(doc){
                if (doc) {
                    users.updateAsync({$and: [{name: message[2]}, {interface: message[1]}]}, {$set: {role: message[0]}})
                        .then(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                } else {
                    users.insertAsync({"name":message[2],"interface":message[1],"role":message[0]})
                        .then(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                }
            })
        }
    );

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles (trusted|admin) ([^\\s]+?) (.+?)',
        'admin',
        function(from, interface, message){
            users.findOneAsync({$and: [{name: message[2]}, {interface: message[1]}]}).done(function(doc){
                if (doc) {
                    users.updateAsync({$and: [{name: message[2]}, {interface: message[1]}]}, {$set: {role: message[0]}})
                        .done(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                } else {
                    users.insertAsync({"name":message[2],"interface":message[1],"role":message[0]})
                        .done(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                }
            })
        }
    );

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles request (.+?)',
        'ignore',
        function(from, interface, message){
            api.permissionRequests[from] = {role: message[0], interface: interface};
            api.sendMessage('You have requested ' + message[0] + ' permissions', interface, from);

        }
    );

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles list requests',
        'trusted',
        function(from, interface, message, user){
            api.users.findOneAsync({$and: [{name: user}, {interface: interface}]}).done(function(doc){
                var userRole = doc.role;
                var message = '';
                var roleList;
                if (userRole === 'admin') {
                    roleList = ['admin', 'trusted', 'standard', 'ignore'];
                } else {
                    roleList = ['standard', 'ignore'];
                }

                for (var key in api.permissionRequests) {
                    if (roleList.indexOf(api.permissionRequests[key].role) > -1) {
                        message += key + ' on interface ' + api.permissionRequests[key].interface + ' requests ' + api.permissionRequests[key].role + '\n';
                    }
                }

                api.sendMessage(message, interface, from);
            });
        }
    );

    api.listen(
        {name: 'core', displayname: 'Core'},
        'help( (.*?)|)',
        'standard',
        function(from, interface, message, user){
            api.returnHelp(user, interface, message[1]).then(function(helpMessage){
                api.sendMessage(helpMessage, interface, from);
            })
        }
    );
}
<commit_msg>Added names to params on core listeners<commit_after>module.exports = function(api, users){
    api.listen({name: 'modules', displayname: 'Modules'},'load modules', 'admin', function(from, interface){
        api.sendMessage('Loading new modules', interface, from);
        api.getModules();
    });

    api.listen({name: 'core', displayname: 'Core'},'yes', 'standard', function(from, interface, message){
        var yesNoQuestion = api.returnLastYesNoQuestion(from);
        if (yesNoQuestion) {
            if (typeof yesNoQuestion.yesCallback === 'function') {
                yesNoQuestion.yesCallback();
            }
            api.removeLastYesNoQuestion(from);
        }
    });

    api.listen({name: 'core', displayname: 'Core'}, 'no', 'standard', function(from, interface, message){
        var yesNoQuestion = api.returnLastYesNoQuestion(from);
        if (yesNoQuestion) {
            if (typeof yesNoQuestion.noCallback === 'function') {
                yesNoQuestion.noCallback();
            }
            api.removeLastYesNoQuestion(from);
        }
    });

    api.listen({name: 'core', displayname: 'Core'}, 'next question', 'standard', function(from, interface, message){
        var yesNoQuestion = api.returnLastYesNoQuestion(from);
        if (yesNoQuestion) {
            api.sendMessage(yesNoQuestion.question, interface, from);
        } else {
            api.sendMessage('No more questions to ask!', interface, from);
        }
    });

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles (ignore|standard) (:<interface>[^\\s]+?) (:<name>.+?)',
        'trusted',
        function(from, interface, message){
            users.findOneAsync({$and: [{name: message[2]}, {interface: message[1]}]}).done(function(doc){
                if (doc) {
                    users.updateAsync({$and: [{name: message[2]}, {interface: message[1]}]}, {$set: {role: message[0]}})
                        .then(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                } else {
                    users.insertAsync({"name":message[2],"interface":message[1],"role":message[0]})
                        .then(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                }
            })
        }
    );

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles (trusted|admin) (:<interface>[^\\s]+?) (:<name>.+?)',
        'admin',
        function(from, interface, message){
            users.findOneAsync({$and: [{name: message[2]}, {interface: message[1]}]}).done(function(doc){
                if (doc) {
                    users.updateAsync({$and: [{name: message[2]}, {interface: message[1]}]}, {$set: {role: message[0]}})
                        .done(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                } else {
                    users.insertAsync({"name":message[2],"interface":message[1],"role":message[0]})
                        .done(function(){
                            api.sendMessage(message[2] + ' set as ' + message[0] + ' on interface ' + message[1], interface, from);
                        })
                }
            })
        }
    );

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles request (:<role>.+?)',
        'ignore',
        function(from, interface, message){
            api.permissionRequests[from] = {role: message[0], interface: interface};
            api.sendMessage('You have requested ' + message[0] + ' permissions', interface, from);

        }
    );

    api.listen(
        {name: 'roles', displayname: 'Roles'},
        'roles list requests',
        'trusted',
        function(from, interface, message, user){
            api.users.findOneAsync({$and: [{name: user}, {interface: interface}]}).done(function(doc){
                var userRole = doc.role;
                var message = '';
                var roleList;
                if (userRole === 'admin') {
                    roleList = ['admin', 'trusted', 'standard', 'ignore'];
                } else {
                    roleList = ['standard', 'ignore'];
                }

                for (var key in api.permissionRequests) {
                    if (roleList.indexOf(api.permissionRequests[key].role) > -1) {
                        message += key + ' on interface ' + api.permissionRequests[key].interface + ' requests ' + api.permissionRequests[key].role + '\n';
                    }
                }

                api.sendMessage(message, interface, from);
            });
        }
    );

    api.listen(
        {name: 'core', displayname: 'Core'},
        'help( (:<optional module>.*?)|)',
        'standard',
        function(from, interface, message, user){
            api.returnHelp(user, interface, message[1]).then(function(helpMessage){
                api.sendMessage(helpMessage, interface, from);
            })
        }
    );
}
<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')

var pmPath = path.join(__dirname, '../node_modules/plug-modules/plug-modules.js')

module.exports = createMapping

// stubs needed by plug.dj's app code at boot time
var stubs = {
  localStorage: {
    getItem: function () {},
    setItem: function () {},
    clear: function () {}
  },
  gapi: {
    client: {
      setApiKey: function () {},
      load: function () {}
    }
  }
}

// Create a name mapping from plug.dj's obfuscated require.js module names to
// readable names by running plug-modules in a headless browser-like
// environment (aka jsdom).
// You need to be logged in to run plug-modules, so pass in a cookie jar with
// a valid session cookie.
function createMapping(jar, cb) {
  var jsdom = require('jsdom')
  jsdom.env({
    url: 'https://plug.dj/dashboard',
    headers: {
      Cookie: jar.getCookieString('https://plug.dj/')
    },
    features: {
      FetchExternalResources: [ 'script' ],
      ProcessExternalResources: [ 'script' ]
    },
    src: [ // prevent getMapping.js autorun
           'window._REPLUG_AUTO = true'
           // will generate the mapping file
         , fs.readFileSync('./getMapping.js', 'utf-8') ],
    done: function (e, window) {
      if (e) return cb(e)
      // stub out some objects that plug needs at boot time
      window.localStorage = stubs.localStorage
      window.gapi = stubs.gapi

      // wait for the app javascript to load, then run plug-modules
      var intv = setInterval(waitForRequireJs, 20)
      function waitForRequireJs() {
        if (window.requirejs && window.requirejs.defined('app')) {
          clearInterval(intv)

          var plugModules = fs.readFileSync(pmPath, 'utf-8')
          // ensure that plugModules defines itself as "plug-modules"
          plugModules = plugModules.replace('define([', 'define("plug-modules",[')
          // insert plug-modules
          window.eval(plugModules)

          window.requirejs([ 'plug-modules' ], function (pm) {
            var mapping = window.getMapping(pm, true)
            window.close()
            cb(null, mapping)
          })
        }
      }
    }
  })
}<commit_msg>create-mapping: check for lang/Lang definition instead of app<commit_after>var fs = require('fs')
var path = require('path')

var pmPath = path.join(__dirname, '../node_modules/plug-modules/plug-modules.js')

module.exports = createMapping

// stubs needed by plug.dj's app code at boot time
var stubs = {
  localStorage: {
    getItem: function () {},
    setItem: function () {},
    clear: function () {}
  },
  gapi: {
    client: {
      setApiKey: function () {},
      load: function () {}
    }
  }
}

// Create a name mapping from plug.dj's obfuscated require.js module names to
// readable names by running plug-modules in a headless browser-like
// environment (aka jsdom).
// You need to be logged in to run plug-modules, so pass in a cookie jar with
// a valid session cookie.
function createMapping(jar, cb) {
  var jsdom = require('jsdom')
  jsdom.env({
    url: 'https://plug.dj/dashboard',
    headers: {
      Cookie: jar.getCookieString('https://plug.dj/')
    },
    features: {
      FetchExternalResources: [ 'script' ],
      ProcessExternalResources: [ 'script' ]
    },
    src: [ // prevent getMapping.js autorun
           'window._REPLUG_AUTO = true'
           // will generate the mapping file
         , fs.readFileSync('./getMapping.js', 'utf-8') ],
    done: function (e, window) {
      if (e) return cb(e)
      // stub out some objects that plug needs at boot time
      window.localStorage = stubs.localStorage
      window.gapi = stubs.gapi

      // wait for the app javascript to load, then run plug-modules
      var intv = setInterval(waitForRequireJs, 20)
      function waitForRequireJs() {
        if (window.requirejs && window.requirejs.defined('lang/Lang')) {
          clearInterval(intv)

          var plugModules = fs.readFileSync(pmPath, 'utf-8')
          // ensure that plugModules defines itself as "plug-modules"
          plugModules = plugModules.replace('define([', 'define("plug-modules",[')
          // insert plug-modules
          window.eval(plugModules)

          window.requirejs([ 'plug-modules' ], function (pm) {
            var mapping = window.getMapping(pm, true)
            window.close()
            cb(null, mapping)
          })
        }
      }
    }
  })
}<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var Promise = require('bluebird')

var pmPath = path.join(__dirname, '../node_modules/plug-modules/plug-modules.js')

module.exports = createMapping

// stubs needed by plug.dj's app code at boot time
var stubs = {
  localStorage: {
    getItem: function () {},
    setItem: function () {},
    clear: function () {}
  },
  gapi: {
    client: {
      setApiKey: function () {},
      load: function () {}
    }
  }
}

function jsdomEnv(opts) {
  return new Promise(function (resolve, reject) {
    opts.done = function (e, window) {
      if (e) reject(e)
      else   resolve(window)
    }
    require('jsdom').env(opts)
  })
}

function waitForRequireJs(window) {
  return new Promise(function (resolve, reject) {
    // wait for the app javascript to load, then run plug-modules
    var intv = setInterval(waitForRequireJs, 20)
    function waitForRequireJs() {
      if (window.requirejs && window.requirejs.defined('lang/Lang')) {
        clearInterval(intv)
        resolve()
      }
    }
  })
}

// Create a name mapping from plug.dj's obfuscated require.js module names to
// readable names by running plug-modules in a headless browser-like
// environment (aka jsdom).
// You need to be logged in to run plug-modules, so pass in a cookie jar with
// a valid session cookie.
function createMapping(jar, cb) {
  return jsdomEnv({
    url: 'https://plug.dj/plug-socket-test',
    headers: {
      Cookie: jar.getCookieString('https://plug.dj/')
    },
    features: {
      FetchExternalResources: [ 'script' ],
      ProcessExternalResources: [ 'script' ]
    },
    src: [ // prevent getMapping.js autorun
           'window._REPLUG_AUTO = true'
           // will generate the mapping file
         , fs.readFileSync('./getMapping.js', 'utf-8') ]
  })
    .tap(function (window) {
      // stub out some objects that plug needs at boot time
      window.localStorage = stubs.localStorage
      window.gapi = stubs.gapi
      return waitForRequireJs(window)
    })
    .then(function (window) {
      var reqAsync = function (id) {
        return new Promise(window.requirejs.bind(null, id))
      }

      return fs.readFileAsync(pmPath, 'utf-8')
        .then(function (plugModules) {
          // ensure that plugModules defines itself as "plug-modules"
          return plugModules.replace('define([', 'define("plug-modules",[')
        })
        // insert plug-modules
        .then(function (src) { return window.eval(src) })
        .then(function ()    { return reqAsync([ 'plug-modules' ]) })
        .then(function (pm)  { return window.getMapping(pm, true) })
        .tap (function ()    { window.close() })
    })
}<commit_msg>create-mapping: fix getMapping file path<commit_after>var fs = require('fs')
var path = require('path')
var Promise = require('bluebird')

var pmPath = path.join(__dirname, '../node_modules/plug-modules/plug-modules.js')

module.exports = createMapping

// stubs needed by plug.dj's app code at boot time
var stubs = {
  localStorage: {
    getItem: function () {},
    setItem: function () {},
    clear: function () {}
  },
  gapi: {
    client: {
      setApiKey: function () {},
      load: function () {}
    }
  }
}

function jsdomEnv(opts) {
  return new Promise(function (resolve, reject) {
    opts.done = function (e, window) {
      if (e) reject(e)
      else   resolve(window)
    }
    require('jsdom').env(opts)
  })
}

function waitForRequireJs(window) {
  return new Promise(function (resolve, reject) {
    // wait for the app javascript to load, then run plug-modules
    var intv = setInterval(waitForRequireJs, 20)
    function waitForRequireJs() {
      if (window.requirejs && window.requirejs.defined('lang/Lang')) {
        clearInterval(intv)
        resolve()
      }
    }
  })
}

// Create a name mapping from plug.dj's obfuscated require.js module names to
// readable names by running plug-modules in a headless browser-like
// environment (aka jsdom).
// You need to be logged in to run plug-modules, so pass in a cookie jar with
// a valid session cookie.
function createMapping(jar, cb) {
  return jsdomEnv({
    url: 'https://plug.dj/plug-socket-test',
    headers: {
      Cookie: jar.getCookieString('https://plug.dj/')
    },
    features: {
      FetchExternalResources: [ 'script' ],
      ProcessExternalResources: [ 'script' ]
    },
    src: [ // prevent getMapping.js autorun
           'window._REPLUG_AUTO = true'
           // will generate the mapping file
         , fs.readFileSync(path.join(__dirname, '../getMapping.js'), 'utf-8') ]
  })
    .tap(function (window) {
      // stub out some objects that plug needs at boot time
      window.localStorage = stubs.localStorage
      window.gapi = stubs.gapi
      return waitForRequireJs(window)
    })
    .then(function (window) {
      var reqAsync = function (id) {
        return new Promise(window.requirejs.bind(null, id))
      }

      return fs.readFileAsync(pmPath, 'utf-8')
        .then(function (plugModules) {
          // ensure that plugModules defines itself as "plug-modules"
          return plugModules.replace('define([', 'define("plug-modules",[')
        })
        // insert plug-modules
        .then(function (src) { return window.eval(src) })
        .then(function ()    { return reqAsync([ 'plug-modules' ]) })
        .then(function (pm)  { return window.getMapping(pm, true) })
        .tap (function ()    { window.close() })
    })
}<|endoftext|>


<commit_before>import path from 'path';
import fs from 'fs';

import types, { supportedTemplates, supportedFrameworks } from './project_types';
import { getBowerJson, getPackageJson } from './helpers';

const hasDependency = (packageJson, name) => {
  return !!packageJson.dependencies?.[name] || !!packageJson.devDependencies?.[name];
};

const hasPeerDependency = (packageJson, name) => {
  return !!packageJson.peerDependencies?.[name];
};

const isFramework = (packageJson, framework) => {
  const matches = {
    dependencies: [false],
    peerDependencies: [false],
    files: [false],
  };

  const { preset, files, dependencies, peerDependencies, matcherFunction } = framework;

  if (Array.isArray(dependencies) && dependencies.length > 0) {
    matches.dependencies = dependencies.map((name) => hasDependency(packageJson, name));
  }

  if (Array.isArray(peerDependencies) && peerDependencies.length > 0) {
    matches.peerDependencies = peerDependencies.map((name) => hasPeerDependency(packageJson, name));
  }

  if (Array.isArray(files) && files.length > 0) {
    matches.files = files.map((name) => fs.existsSync(path.join(process.cwd(), name)));
  }

  return matcherFunction(matches) ? preset : null;
};

export function detectFramework(packageJson = {}) {
  const result = supportedTemplates.find((framework) => {
    return isFramework(packageJson, framework) !== null;
  });

  return result ? result.preset : types.UNDETECTED;
}

export function isStorybookInstalled(dependencies, force) {
  if (!dependencies) {
    return false;
  }

  if (!force && dependencies.devDependencies) {
    if (
      supportedFrameworks.reduce(
        (storybookPresent, framework) =>
          storybookPresent || dependencies.devDependencies[`@storybook/${framework}`],
        false
      )
    ) {
      return types.ALREADY_HAS_STORYBOOK;
    }

    if (
      dependencies.devDependencies['@kadira/storybook'] ||
      dependencies.devDependencies['@kadira/react-native-storybook']
    ) {
      return types.UPDATE_PACKAGE_ORGANIZATIONS;
    }
  }
  return false;
}

export function detect(options = {}) {
  if (options.html) {
    return types.HTML;
  }

  const packageJson = getPackageJson();
  const bowerJson = getBowerJson();

  if (!packageJson && !bowerJson) {
    return types.UNDETECTED;
  }

  const storyBookInstalled = isStorybookInstalled(packageJson, options.force);
  if (storyBookInstalled) {
    return storyBookInstalled;
  }

  return detectFramework(packageJson || bowerJson);
}
<commit_msg>fix(cli): move html check down in detection<commit_after>import path from 'path';
import fs from 'fs';

import types, { supportedTemplates, supportedFrameworks } from './project_types';
import { getBowerJson, getPackageJson } from './helpers';

const hasDependency = (packageJson, name) => {
  return !!packageJson.dependencies?.[name] || !!packageJson.devDependencies?.[name];
};

const hasPeerDependency = (packageJson, name) => {
  return !!packageJson.peerDependencies?.[name];
};

const isFramework = (packageJson, framework) => {
  const matches = {
    dependencies: [false],
    peerDependencies: [false],
    files: [false],
  };

  const { preset, files, dependencies, peerDependencies, matcherFunction } = framework;

  if (Array.isArray(dependencies) && dependencies.length > 0) {
    matches.dependencies = dependencies.map((name) => hasDependency(packageJson, name));
  }

  if (Array.isArray(peerDependencies) && peerDependencies.length > 0) {
    matches.peerDependencies = peerDependencies.map((name) => hasPeerDependency(packageJson, name));
  }

  if (Array.isArray(files) && files.length > 0) {
    matches.files = files.map((name) => fs.existsSync(path.join(process.cwd(), name)));
  }

  return matcherFunction(matches) ? preset : null;
};

export function detectFramework(packageJson = {}) {
  const result = supportedTemplates.find((framework) => {
    return isFramework(packageJson, framework) !== null;
  });

  return result ? result.preset : types.UNDETECTED;
}

export function isStorybookInstalled(dependencies, force) {
  if (!dependencies) {
    return false;
  }

  if (!force && dependencies.devDependencies) {
    if (
      supportedFrameworks.reduce(
        (storybookPresent, framework) =>
          storybookPresent || dependencies.devDependencies[`@storybook/${framework}`],
        false
      )
    ) {
      return types.ALREADY_HAS_STORYBOOK;
    }

    if (
      dependencies.devDependencies['@kadira/storybook'] ||
      dependencies.devDependencies['@kadira/react-native-storybook']
    ) {
      return types.UPDATE_PACKAGE_ORGANIZATIONS;
    }
  }
  return false;
}

export function detect(options = {}) {
  const packageJson = getPackageJson();
  const bowerJson = getBowerJson();

  if (!packageJson && !bowerJson) {
    return types.UNDETECTED;
  }

  const storyBookInstalled = isStorybookInstalled(packageJson, options.force);
  if (storyBookInstalled) {
    return storyBookInstalled;
  }

  if (options.html) {
    return types.HTML;
  }

  return detectFramework(packageJson || bowerJson);
}
<|endoftext|>


<commit_before>var epoke = new Date();
var startupThreshold = 5000; // ms from epoke is startup messages
var startupFired = false;
var inBackground = false;
var haveBeenPaused = false;

Push.setBadge = function(count) {
  // Helper
  var pushNotification = window.plugins.pushNotification;

  // If the set application badge is available
  if (typeof pushNotification.setApplicationIconBadgeNumber == 'function') {
    // Set the badge
    pushNotification.setApplicationIconBadgeNumber(function(result) {
      // Success callback
    }, function(err) {
      // Error callback
      Push.emit('error', { type: 'badge', error: err });
    }, count);

  }
};

onNotification = function(notification) {
  // Emit alert event - this requires the app to be in forground
  if (notification.message && notification.foreground)
    Push.emit('alert', notification);

  // Emit sound event
  if (notification.sound) Push.emit('sound', notification);

  // Emit badge event
  if (notification.badge) Push.emit('badge', notification);

  // If within thres
  if (epoke - new Date() < startupThreshold && !startupFired) {
    startupFired = true;
    // Fire startup event
    Push.emit('startup', notification);
  } else {
    Push.emit('message', notification);
  }
};

// handle APNS notifications for iOS
onNotificationAPN = function(e) {

  // XXX: Investigate if we need more defaults
  var unifiedMessage = {
    message: e.alert,
    sound: e.sound,
    badge: e.badge,
    coldstart: !haveBeenPaused,
    background: inBackground,
    foreground: !inBackground,
    type: 'apn.cordova'
  };

  // Trigger notification
  onNotification(unifiedMessage);
};

// handle GCM notifications for Android and Fire OS
onNotificationGCM = function(e) {

  switch( e.event ) {
    case 'registered':
      if ( e.regid.length > 0 ) {
        Push.emit('token', { gcm: ''+e.regid } );
      }
    break;

    case 'message':

      var sound = e.soundname || e.payload.sound;

      // XXX: Investigate if we need more defaults
      var unifiedMessage = {
        message: e.payload.message || e.msg || '',
        sound: sound && ('/android_asset/www/' + sound),
        badge: e.payload.msgcnt,
        coldstart: e.coldstart,
        background: !e.foreground,
        foreground: e.foreground,
        type: 'gcm.cordova'
      };

      // Trigger notification
      onNotification(unifiedMessage);
    break;

    case 'error':
      // e.msg
      Push.emit('error', { type: 'gcm.cordova', error: e });
    break;
  }
};

var rigDefaultEventListeners = function(options) {
  // Set default badge behaviour
  if (options.badge) Push.addListener('badge', function(notification) {
    Push.setBadge(notification.badge);
  });

  // Set default sound behaviour
  if (options.sound) Push.addListener('sound', function(notification) {
    var snd = new Media(notification.sound);
    snd.play();
  });

  // Set default alert behaviour
  if (options.alert) Push.addListener('alert', function(notification) {

    if (navigator && navigator.notification && navigator.notification.alert) {
      // If native notifications installed
      navigator.notification.alert(notification.message);
    } else {
      // Use regular notification
      alert(notification.message);
    }
  });

  // We add a vibrate listener
  if (options.vibrate) Push.addListener('message', function(notification) {
    // Vibrate if possible
    if (navigator && navigator.notification && navigator.notification.vibrate) {
      // If vibrate installed
      navigator.notification.vibrate(500);
    }
  });
};

Push.init = function(options) {
  var self = this;

  // Clean up options, make sure the projectNumber
  if (options.gcm && !options.gcm.projectNumber)
    throw new Error('Push.initPush gcm got no projectNumber');

  // Client-side security warnings
  checkClientSecurity(options);

  // Set default options - these are needed for apn?
  options = _.extend({
    badge: (options.badge !== false),
    sound: (options.sound !== false),
    alert: (options.alert !== false),
    vibrate: (options.vibrate !== false)
  }, options);

  // Rig default event listeners for badge/sound/alert/vibrate
  rigDefaultEventListeners(options);

  // Add debug info
  if (Push.debug) console.log('Push.init', options);

  // Start token updates
  initPushUpdates(options.appName);

    // Initialize on ready
  Meteor.startup(function() {
    // Set epoke from
    epoke = new Date();

    // Update flag if app is inBackground
    document.addEventListener("pause", function() {
      inBackground = true;
      haveBeenPaused = true;
    }, false);

    // Update flag when app is resumed
    document.addEventListener("resume", function() {
      inBackground = false;
      // Allow for startup messages
      startupFired = false;
      // Set new epoke
      epoke = new Date();
    }, false);

    var pushNotification = window.plugins.pushNotification;

    if (device.platform == 'android' || device.platform == 'Android') {
      try {

        if (options.gcm && options.gcm.projectNumber) {
          pushNotification.register(function(result) {
            // Emit registered
            self.emit('register', result);
          }, function(error) {
            // Emit error
            self.emit('error', { type: 'gcm.cordova', error: error });
          }, {
            'senderID': ''+options.gcm.projectNumber,
            'ecb': 'onNotificationGCM'
          });
        } else {
          // throw new Error('senderID not set in options, required on android');
          console.warn('WARNING: Push.init, No gcm.projectNumber set on android');
        }

      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'gcm.cordova', error: err.message });
      }
    } else {

      try {

        pushNotification.register(function(token) {
          // Got apn / ios token
          self.emit('token', { apn: token });
        }, function(error) {
          // Emit error
          self.emit('error', { type: 'apn.cordova', error: error });
        }, {
          'badge': ''+options.badge,
          'sound': ''+options.sound,
          'alert': ''+options.alert,
          'ecb': 'onNotificationAPN'
        }); // required!
      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'apn.cordova', error: err.message });
      }
    }

  }, true);

}; // EO Push
<commit_msg>clean up foreground code and keep coldstart<commit_after>var coldstart = true;

Push.setBadge = function(count) {
  // Helper
  var pushNotification = window.plugins.pushNotification;

  // If the set application badge is available
  if (typeof pushNotification.setApplicationIconBadgeNumber == 'function') {
    // Set the badge
    pushNotification.setApplicationIconBadgeNumber(function(result) {
      // Success callback
    }, function(err) {
      // Error callback
      Push.emit('error', { type: 'badge', error: err });
    }, count);

  }
};

onNotification = function(notification) {
  // Emit alert event - this requires the app to be in forground
  if (notification.message && notification.foreground)
    Push.emit('alert', notification);

  // Emit sound event
  if (notification.sound) Push.emit('sound', notification);

  // Emit badge event
  if (notification.badge) Push.emit('badge', notification);

  // If within thres
  if (notification.background) {
    Push.emit('startup', notification);
  } else {
    Push.emit('message', notification);
  }
};

// handle APNS notifications for iOS
onNotificationAPN = function(e) {

  // XXX: Investigate if we need more defaults
  var unifiedMessage = {
    message: e.alert,
    sound: e.sound,
    badge: e.badge,
    coldstart: coldstart,
    background: !e.foreground,
    foreground: !!e.foreground,
    type: 'apn.cordova',
  };

  // Trigger notification
  onNotification(unifiedMessage);
};

// handle GCM notifications for Android and Fire OS
onNotificationGCM = function(e) {

  switch( e.event ) {
    case 'registered':
      if ( e.regid.length > 0 ) {
        Push.emit('token', { gcm: ''+e.regid } );
      }
    break;

    case 'message':

      var sound = e.soundname || e.payload.sound;

      // XXX: Investigate if we need more defaults
      var unifiedMessage = {
        message: e.payload.message || e.msg || '',
        sound: sound && ('/android_asset/www/' + sound),
        badge: e.payload.msgcnt,
        coldstart: e.coldstart,
        background: !e.foreground,
        foreground: !!e.foreground,
        type: 'gcm.cordova',
      };

      // Trigger notification
      onNotification(unifiedMessage);
    break;

    case 'error':
      // e.msg
      Push.emit('error', { type: 'gcm.cordova', error: e });
    break;
  }
};

var rigDefaultEventListeners = function(options) {
  // Set default badge behaviour
  if (options.badge) Push.addListener('badge', function(notification) {
    Push.setBadge(notification.badge);
  });

  // Set default sound behaviour
  if (options.sound) Push.addListener('sound', function(notification) {
    var snd = new Media(notification.sound);
    snd.play();
  });

  // Set default alert behaviour
  if (options.alert) Push.addListener('alert', function(notification) {

    if (navigator && navigator.notification && navigator.notification.alert) {
      // If native notifications installed
      navigator.notification.alert(notification.message);
    } else {
      // Use regular notification
      alert(notification.message);
    }
  });

  // We add a vibrate listener
  if (options.vibrate) Push.addListener('message', function(notification) {
    // Vibrate if possible
    if (navigator && navigator.notification && navigator.notification.vibrate) {
      // If vibrate installed
      navigator.notification.vibrate(500);
    }
  });
};

Push.init = function(options) {
  var self = this;

  // Clean up options, make sure the projectNumber
  if (options.gcm && !options.gcm.projectNumber)
    throw new Error('Push.initPush gcm got no projectNumber');

  // Client-side security warnings
  checkClientSecurity(options);

  // Set default options - these are needed for apn?
  options = _.extend({
    badge: (options.badge !== false),
    sound: (options.sound !== false),
    alert: (options.alert !== false),
    vibrate: (options.vibrate !== false)
  }, options);

  // Rig default event listeners for badge/sound/alert/vibrate
  rigDefaultEventListeners(options);

  // Add debug info
  if (Push.debug) console.log('Push.init', options);

  // Start token updates
  initPushUpdates(options.appName);

    // Initialize on ready
  Meteor.startup(function() {

    // Update flag if app coldstart
    document.addEventListener("pause", function() {
      coldstart = false;
    }, false);

    var pushNotification = window.plugins.pushNotification;

    if (device.platform == 'android' || device.platform == 'Android') {
      try {

        if (options.gcm && options.gcm.projectNumber) {
          pushNotification.register(function(result) {
            // Emit registered
            self.emit('register', result);
          }, function(error) {
            // Emit error
            self.emit('error', { type: 'gcm.cordova', error: error });
          }, {
            'senderID': ''+options.gcm.projectNumber,
            'ecb': 'onNotificationGCM'
          });
        } else {
          // throw new Error('senderID not set in options, required on android');
          console.warn('WARNING: Push.init, No gcm.projectNumber set on android');
        }

      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'gcm.cordova', error: err.message });
      }
    } else {

      try {

        pushNotification.register(function(token) {
          // Got apn / ios token
          self.emit('token', { apn: token });
        }, function(error) {
          // Emit error
          self.emit('error', { type: 'apn.cordova', error: error });
        }, {
          'badge': ''+options.badge,
          'sound': ''+options.sound,
          'alert': ''+options.alert,
          'ecb': 'onNotificationAPN'
        }); // required!
      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'apn.cordova', error: err.message });
      }
    }

  }, true);

}; // EO Push
<|endoftext|>


<commit_before>module.exports = Tracker

var EventEmitter = require('events').EventEmitter
var inherits = require('inherits')

inherits(Tracker, EventEmitter)

function Tracker (client, announceUrl) {
  var self = this
  EventEmitter.call(self)

  self.client = client
  self.announceUrl = announceUrl
  self.interval = null
  self.destroyed = false
}

Tracker.prototype.setInterval = function (intervalMs) {
  var self = this
  if (self.interval) return
  if (intervalMs == null) intervalMs = self.DEFAULT_ANNOUNCE_INTERVAL

  clearInterval(self.interval)

  if (intervalMs) {
    var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
    self.interval = setInterval(update, intervalMs)
    if (self.interval.unref) self.interval.unref()
  }
}
<commit_msg>calling tracker.setInterval() should override current interval<commit_after>module.exports = Tracker

var EventEmitter = require('events').EventEmitter
var inherits = require('inherits')

inherits(Tracker, EventEmitter)

function Tracker (client, announceUrl) {
  var self = this
  EventEmitter.call(self)
  self.client = client
  self.announceUrl = announceUrl

  self.interval = null
  self.destroyed = false
}

Tracker.prototype.setInterval = function (intervalMs) {
  var self = this
  if (intervalMs == null) intervalMs = self.DEFAULT_ANNOUNCE_INTERVAL

  clearInterval(self.interval)

  if (intervalMs) {
    var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
    self.interval = setInterval(update, intervalMs)
    if (self.interval.unref) self.interval.unref()
  }
}
<|endoftext|>


<commit_before>'use strict';

var ListenerMixin = require('./ListenerMixin');
var Collection = require('ampersand-collection');
var React = require('react');

module.exports = function(config) {
  if (config == null) {
    throw new Error('config parameter is required');
  }
  if (config.model == null) {
    throw new Error('model attribute is required');
  }
  if (config.itemView == null) {
    throw new Error('itemView attribute is required');
  }

  var sync = this.getSync(config.model);
  var ctor = this.createCollection(config.model);

  // items = array of item views
  // collection = ampersand collection
  var CollectionViewMixin = {
    mixins: [ListenerMixin],
    propTypes: {
      collection: React.PropTypes.instanceOf(Collection),
    },

    getDefaultProps: function(){
      return {
        collection: this.collection
      };
    },
    renderItems: function() {
      this.items = this.props.collection.map(function(m) {
        return this.itemView({
          model: m,
          key: m.cid
        });
      }, this);

      this.forceUpdate();
    },
    componentWillMount: function() {
      // first mount, create items array
      if (this.items == null) {
        this.items = [];
      }

      // collection passed in
      if (this.props.collection != null) {
        this.renderItems();
      } else {
        // collection needs to be constructed
        this.props.collection = new ctor();
        this.props.collection.sync = sync;
        this.props.collection.fetch({
          success: this.renderItems,
          error: function(err) {
            // TODO: real error management on views
            console.log('fetch error', err);
          }
        });
      }
      this.listenTo(this.props.collection, 'add change remove', this.renderItems);
    }
  };

  return this.view(config, [CollectionViewMixin]);
};
<commit_msg>collectionView: specify collection<commit_after>'use strict';

var ListenerMixin = require('./ListenerMixin');
var Collection = require('ampersand-collection');
var React = require('react');

module.exports = function(config) {
  if (config == null) {
    throw new Error('config parameter is required');
  }
  if (config.model == null) {
    throw new Error('model attribute is required');
  }
  if (config.itemView == null) {
    throw new Error('itemView attribute is required');
  }

  var sync = this.getSync(config.model);
  var ctor = this.createCollection(config.model);

  // items = array of item views
  // collection = ampersand collection
  var CollectionViewMixin = {
    mixins: [ListenerMixin],
    propTypes: {
      collection: React.PropTypes.instanceOf(Collection),
    },

    getDefaultProps: function(){
      return {
        collection: config.collection
      };
    },
    renderItems: function() {
      this.items = this.props.collection.map(function(m) {
        return this.itemView({
          model: m,
          key: m.cid
        });
      }, this);

      this.forceUpdate();
    },
    componentWillMount: function() {
      // first mount, create items array
      if (this.items == null) {
        this.items = [];
      }

      // collection passed in
      if (this.props.collection != null) {
        this.renderItems();
      } else {
        // collection needs to be constructed
        this.props.collection = new ctor();
        this.props.collection.sync = sync;
        this.props.collection.fetch({
          success: this.renderItems,
          error: function(err) {
            // TODO: real error management on views
            console.log('fetch error', err);
          }
        });
      }
      this.listenTo(this.props.collection, 'add change remove', this.renderItems);
    }
  };

  return this.view(config, [CollectionViewMixin]);
};
<|endoftext|>


<commit_before>'use strict'

const serveStatic = require('serve-static')
const connect = require('connect')
const livereload = require('connect-livereload')
const lrserver = require('livereload')
const open = require('open')
const chalk = require('chalk')
const util = require('../util/index')

var exists = util.exists
var resolve = util.resolve

module.exports = function (path, openInBrowser, port, livereloadPort) {
  path = resolve(path || '.')
  var indexFile = resolve(path, 'index.html')

  if (!exists(indexFile)) {
    const msg = '\nNo docs found, please run ' + chalk.green('docsify init') + ' first.\n'
    console.log(msg)
    process.exit(0)
  }

  var server = connect()

  server.use(livereload())
  server.use(serveStatic(path))
  server.listen(port)
  lrserver.createServer({
    exts: ['md'],
    exclusions: ['node_modules/'],
    port: livereloadPort
  }).watch(path)

  if (openInBrowser) {
    open(`http://localhost:${port}`)
  }

  const msg = '\nServing ' + chalk.green(`${path}`) + ' now.\n' +
              'Listening at ' + chalk.green(`http://localhost:${port}`) + '\n'
  console.log(msg)
}
<commit_msg>fix: livereload port issue, fixed #26<commit_after>'use strict'

const serveStatic = require('serve-static')
const connect = require('connect')
const livereload = require('connect-livereload')
const lrserver = require('livereload')
const open = require('open')
const chalk = require('chalk')
const util = require('../util/index')

var exists = util.exists
var resolve = util.resolve

module.exports = function (path, openInBrowser, port, livereloadPort) {
  path = resolve(path || '.')
  var indexFile = resolve(path, 'index.html')

  if (!exists(indexFile)) {
    const msg = '\nNo docs found, please run ' + chalk.green('docsify init') + ' first.\n'
    console.log(msg)
    process.exit(0)
  }

  var server = connect()
  server.use(livereload({
    port: livereloadPort
  }))
  server.use(serveStatic(path))
  server.listen(port)
  lrserver.createServer({
    exts: ['md'],
    exclusions: ['node_modules/'],
    port: livereloadPort
  }).watch(path)

  if (openInBrowser) {
    open(`http://localhost:${port}`)
  }

  const msg = '\nServing ' + chalk.green(`${path}`) + ' now.\n' +
              'Listening at ' + chalk.green(`http://localhost:${port}`) + '\n'
  console.log(msg)
}
<|endoftext|>