<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const assert = require('assert');
const fs = require('fs');
const path = require('path');
const Promise = require('promise');
const ProgressBar = require('progress');
const BundlesLayout = require('../BundlesLayout');
const Cache = require('../DependencyResolver/Cache');
const Transformer = require('../JSTransformer');
const Resolver = require('../Resolver');
const Bundle = require('./Bundle');
const HMRBundle = require('./HMRBundle');
const PrepackBundle = require('./PrepackBundle');
const Activity = require('../Activity');
const ModuleTransport = require('../lib/ModuleTransport');
const declareOpts = require('../lib/declareOpts');
const imageSize = require('image-size');
const version = require('../../../../package.json').version;

const sizeOf = Promise.denodeify(imageSize);
const readFile = Promise.denodeify(fs.readFile);

const validateOpts = declareOpts({
  projectRoots: {
    type: 'array',
    required: true,
  },
  blacklistRE: {
    type: 'object', // typeof regex is object
  },
  moduleFormat: {
    type: 'string',
    default: 'haste',
  },
  polyfillModuleNames: {
    type: 'array',
    default: [],
  },
  cacheVersion: {
    type: 'string',
    default: '1.0',
  },
  resetCache: {
    type: 'boolean',
    default: false,
  },
  transformModulePath: {
    type:'string',
    required: false,
  },
  nonPersistent: {
    type: 'boolean',
    default: false,
  },
  assetRoots: {
    type: 'array',
    required: false,
  },
  assetExts: {
    type: 'array',
    default: ['png'],
  },
  fileWatcher: {
    type: 'object',
    required: true,
  },
  assetServer: {
    type: 'object',
    required: true,
  },
  transformTimeoutInterval: {
    type: 'number',
    required: false,
  },
  disableInternalTransforms: {
    type: 'boolean',
    default: false,
  },
});

class Bundler {

  constructor(options) {
    const opts = this._opts = validateOpts(options);

    opts.projectRoots.forEach(verifyRootExists);

    let mtime;
    try {
      ({mtime} = fs.statSync(opts.transformModulePath));
      mtime = String(mtime.getTime());
    } catch (error) {
      mtime = '';
    }

    this._cache = new Cache({
      resetCache: opts.resetCache,
      cacheKey: [
        'react-packager-cache',
        version,
        opts.cacheVersion,
        opts.projectRoots.join(',').split(path.sep).join('-'),
        mtime
      ].join('$'),
    });

    this._resolver = new Resolver({
      projectRoots: opts.projectRoots,
      blacklistRE: opts.blacklistRE,
      polyfillModuleNames: opts.polyfillModuleNames,
      moduleFormat: opts.moduleFormat,
      assetRoots: opts.assetRoots,
      fileWatcher: opts.fileWatcher,
      assetExts: opts.assetExts,
      cache: this._cache,
    });

    this._bundlesLayout = new BundlesLayout({
      dependencyResolver: this._resolver,
      resetCache: opts.resetCache,
      cacheVersion: opts.cacheVersion,
      projectRoots: opts.projectRoots,
    });

    this._transformer = new Transformer({
      projectRoots: opts.projectRoots,
      blacklistRE: opts.blacklistRE,
      cache: this._cache,
      transformModulePath: opts.transformModulePath,
      disableInternalTransforms: opts.disableInternalTransforms,
    });

    this._projectRoots = opts.projectRoots;
    this._assetServer = opts.assetServer;

    if (opts.getTransformOptionsModulePath) {
      this._transformOptionsModule = require(
        opts.getTransformOptionsModulePath
      );
    }
  }

  kill() {
    this._transformer.kill();
    return this._cache.end();
  }

  getLayout(main, isDev) {
    return this._bundlesLayout.generateLayout(main, isDev);
  }

  bundle(options) {
    return this._bundle({
      bundle: new Bundle(options.sourceMapUrl),
      includeSystemDependencies: true,
      ...options,
    });
  }

  _sourceHMRURL(platform, path) {
    return this._hmrURL(
      'http://localhost:8081', // TODO: (martinb) avoid hardcoding
      platform,
      'bundle',
      path,
    );
  }

  _sourceMappingHMRURL(platform, path) {
    // Chrome expects `sourceURL` when eval'ing code
    return this._hmrURL(
      '\/\/# sourceURL=',
      platform,
      'map',
      path,
    );
  }

  _hmrURL(prefix, platform, extensionOverride, path) {
    const matchingRoot = this._projectRoots.find(root => path.startsWith(root));

    if (!matchingRoot) {
      throw new Error('No matching project root for ', path);
    }

    const extensionStart = path.lastIndexOf('.');
    let resource = path.substring(
      matchingRoot.length,
      extensionStart !== -1 ? extensionStart : undefined,
    );

    const extension = extensionStart !== -1
      ? path.substring(extensionStart + 1)
      : null;

    return (
      prefix + resource +
      '.' + extensionOverride + '?' +
      'platform=' + platform + '&runModule=false&entryModuleOnly=true&hot=true'
    );
  }

  bundleForHMR(options) {
    return this._bundle({
      bundle: new HMRBundle({
        sourceURLFn: this._sourceHMRURL.bind(this, options.platform),
        sourceMappingURLFn: this._sourceMappingHMRURL.bind(
          this,
          options.platform,
        ),
      }),
      hot: true,
      ...options,
    });
  }

  _bundle({
    bundle,
    modules,
    entryFile,
    runModule: runMainModule,
    runBeforeMainModule,
    dev: isDev,
    includeSystemDependencies,
    platform,
    unbundle: isUnbundle,
    hot: hot,
    entryModuleOnly,
  }) {
    const findEventId = Activity.startEvent('find dependencies');
    let transformEventId;

    return this.getDependencies(entryFile, isDev, platform).then((response) => {
      Activity.endEvent(findEventId);
      bundle.setMainModuleId(response.mainModuleId);
      bundle.setMainModuleName(response.mainModuleId);
      transformEventId = Activity.startEvent('transform');

      let dependencies;
      if (entryModuleOnly) {
        dependencies = response.dependencies.filter(module =>
          module.path.endsWith(entryFile)
        );
      } else {
        const moduleSystemDeps = includeSystemDependencies
          ? this._resolver.getModuleSystemDependencies(
            { dev: isDev, platform, isUnbundle }
          )
          : [];

        const modulesToProcess = modules || response.dependencies;
        const dependencies = moduleSystemDeps.concat(modulesToProcess);

        bundle.setNumPrependedModules && bundle.setNumPrependedModules(
          response.numPrependedDependencies + moduleSystemDeps.length
        );
      }

      let bar;
      if (process.stdout.isTTY) {
        bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
          complete: '=',
          incomplete: ' ',
          width: 40,
          total: dependencies.length,
        });
      }

      return Promise.all(
        dependencies.map(
          module => {
            return this._transformModule(
              bundle,
              response,
              module,
              platform,
              isDev,
              hot,
            ).then(transformed => {
              if (bar) {
                bar.tick();
              }

              return {
                module,
                transformed,
              };
            });
          }
        )
      ).then(transformedModules => Promise.all(
        transformedModules.map(({module, transformed}) => {
          return bundle.addModule(
            this._resolver,
            response,
            module,
            transformed,
          );
        })
      ));
    }).then(() => {
      Activity.endEvent(transformEventId);
      bundle.finalize({runBeforeMainModule, runMainModule});
      return bundle;
    });
  }

  prepackBundle({
    entryFile,
    runModule: runMainModule,
    runBeforeMainModule,
    sourceMapUrl,
    dev: isDev,
    platform,
  }) {
    const bundle = new PrepackBundle(sourceMapUrl);
    const findEventId = Activity.startEvent('find dependencies');
    let transformEventId;
    let mainModuleId;

    return this.getDependencies(entryFile, isDev, platform).then((response) => {
      Activity.endEvent(findEventId);
      transformEventId = Activity.startEvent('transform');

      let bar;
      if (process.stdout.isTTY) {
        bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
          complete: '=',
          incomplete: ' ',
          width: 40,
          total: response.dependencies.length,
        });
      }

      mainModuleId = response.mainModuleId;

      return Promise.all(
        response.dependencies.map(
          module => this._transformModule(
            bundle,
            response,
            module,
            platform,
            isDev,
          ).then(transformed => {
            if (bar) {
              bar.tick();
            }

            var deps = Object.create(null);
            var pairs = response.getResolvedDependencyPairs(module);
            if (pairs) {
              pairs.forEach(pair => {
                deps[pair[0]] = pair[1].path;
              });
            }

            return module.getName().then(name => {
              bundle.addModule(name, transformed, deps, module.isPolyfill());
            });
          })
        )
      );
    }).then(() => {
      Activity.endEvent(transformEventId);
      bundle.finalize({runBeforeMainModule, runMainModule, mainModuleId });
      return bundle;
    });
  }

  _transformModuleForHMR(module, platform) {
    if (module.isAsset()) {
      return this._generateAssetObjAndCode(module, platform).then(
        ({asset, code}) => {
          return {
            code,
          };
        }
      );
    } else {
      // TODO(martinb): pass non null main (t9527509)
      return this._getTransformOptions(
        {main: null, dev: true, platform: 'ios'}, // TODO(martinb): avoid hard-coding platform
        {hot: true},
      ).then(options => {
        return this._transformer.loadFileAndTransform(module.path, options);
      });
    }
  }

  invalidateFile(filePath) {
    if (this._transformOptionsModule) {
      this._transformOptionsModule.onFileChange &&
        this._transformOptionsModule.onFileChange();
    }

    this._transformer.invalidateFile(filePath);
  }

  getShallowDependencies(entryFile) {
    return this._resolver.getShallowDependencies(entryFile);
  }

  stat(filePath) {
    return this._resolver.stat(filePath);
  }

  getModuleForPath(entryFile) {
    return this._resolver.getModuleForPath(entryFile);
  }

  getDependencies(main, isDev, platform) {
    return this._resolver.getDependencies(main, { dev: isDev, platform });
  }

  getOrderedDependencyPaths({ entryFile, dev, platform }) {
    return this.getDependencies(entryFile, dev, platform).then(
      ({ dependencies }) => {
        const ret = [];
        const promises = [];
        const placeHolder = {};
        dependencies.forEach(dep => {
          if (dep.isAsset()) {
            const relPath = getPathRelativeToRoot(
              this._projectRoots,
              dep.path
            );
            promises.push(
              this._assetServer.getAssetData(relPath, platform)
            );
            ret.push(placeHolder);
          } else {
            ret.push(dep.path);
          }
        });

        return Promise.all(promises).then(assetsData => {
          assetsData.forEach(({ files }) => {
            const index = ret.indexOf(placeHolder);
            ret.splice(index, 1, ...files);
          });
          return ret;
        });
      }
    );
  }

  _transformModule(bundle, response, module, platform = null, dev = true, hot = false) {
    if (module.isAsset_DEPRECATED()) {
      return this._generateAssetModule_DEPRECATED(bundle, module);
    } else if (module.isAsset()) {
      return this._generateAssetModule(bundle, module, platform);
    } else if (module.isJSON()) {
      return generateJSONModule(module);
    } else {
      return this._getTransformOptions(
        {
          bundleEntry: bundle.getMainModuleName(),
          platform: platform,
          dev: dev,
          modulePath: module.path,
        },
        {hot: hot},
      ).then(options => {
        return this._transformer.loadFileAndTransform(
          path.resolve(module.path),
          options,
        );
      });
    }
  }

  getGraphDebugInfo() {
    return this._resolver.getDebugInfo();
  }

  _generateAssetModule_DEPRECATED(bundle, module) {
    return Promise.all([
      sizeOf(module.path),
      module.getName(),
    ]).then(([dimensions, id]) => {
      const img = {
        __packager_asset: true,
        path: module.path,
        uri: id.replace(/^[^!]+!/, ''),
        width: dimensions.width / module.resolution,
        height: dimensions.height / module.resolution,
        deprecated: true,
      };

      bundle.addAsset(img);

      const code = 'module.exports = ' + JSON.stringify(img) + ';';

      return new ModuleTransport({
        code: code,
        sourceCode: code,
        sourcePath: module.path,
        virtual: true,
      });
    });
  }

  _generateAssetObjAndCode(module, platform = null) {
    const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
    var assetUrlPath = path.join('/assets', path.dirname(relPath));

    // On Windows, change backslashes to slashes to get proper URL path from file path.
    if (path.sep === '\\') {
      assetUrlPath = assetUrlPath.replace(/\\/g, '/');
    }

    return Promise.all([
      sizeOf(module.path),
      this._assetServer.getAssetData(relPath, platform),
    ]).then(function(res) {
      const dimensions = res[0];
      const assetData = res[1];
      const asset = {
        __packager_asset: true,
        fileSystemLocation: path.dirname(module.path),
        httpServerLocation: assetUrlPath,
        width: dimensions.width / module.resolution,
        height: dimensions.height / module.resolution,
        scales: assetData.scales,
        files: assetData.files,
        hash: assetData.hash,
        name: assetData.name,
        type: assetData.type,
      };

      const ASSET_TEMPLATE = 'module.exports = require("AssetRegistry").registerAsset(%json);';
      const code = ASSET_TEMPLATE.replace('%json', JSON.stringify(asset));

      return {asset, code};
    });
  }

  _generateAssetModule(bundle, module, platform = null) {
    return this._generateAssetObjAndCode(module, platform).then(({asset, code}) => {
      bundle.addAsset(asset);
      return new ModuleTransport({
        code: code,
        sourceCode: code,
        sourcePath: module.path,
        virtual: true,
      });
    });
  }

  _getTransformOptions(config, options) {
    const transformerOptions = this._transformOptionsModule
      ? this._transformOptionsModule.get(Object.assign(
          {
            bundler: this,
            platform: options.platform,
            dev: options.dev,
          },
          config,
        ))
      : Promise.resolve(null);

    return transformerOptions.then(overrides => {
      return {...options, ...overrides};
    });
  }
}

function generateJSONModule(module) {
  return readFile(module.path).then(function(data) {
    const code = 'module.exports = ' + data.toString('utf8') + ';';

    return new ModuleTransport({
      code: code,
      sourceCode: code,
      sourcePath: module.path,
      virtual: true,
    });
  });
}

function getPathRelativeToRoot(roots, absPath) {
  for (let i = 0; i < roots.length; i++) {
    const relPath = path.relative(roots[i], absPath);
    if (relPath[0] !== '.') {
      return relPath;
    }
  }

  throw new Error(
    'Expected root module to be relative to one of the project roots'
  );
}

function verifyRootExists(root) {
  // Verify that the root exists.
  assert(fs.statSync(root).isDirectory(), 'Root has to be a valid directory');
}

class DummyCache {
  get(filepath, field, loaderCb) {
    return loaderCb();
  }

  end(){}
  invalidate(filepath){}
}
module.exports = Bundler;
<commit_msg>Fixing typo in Bundler<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const assert = require('assert');
const fs = require('fs');
const path = require('path');
const Promise = require('promise');
const ProgressBar = require('progress');
const BundlesLayout = require('../BundlesLayout');
const Cache = require('../DependencyResolver/Cache');
const Transformer = require('../JSTransformer');
const Resolver = require('../Resolver');
const Bundle = require('./Bundle');
const HMRBundle = require('./HMRBundle');
const PrepackBundle = require('./PrepackBundle');
const Activity = require('../Activity');
const ModuleTransport = require('../lib/ModuleTransport');
const declareOpts = require('../lib/declareOpts');
const imageSize = require('image-size');
const version = require('../../../../package.json').version;

const sizeOf = Promise.denodeify(imageSize);
const readFile = Promise.denodeify(fs.readFile);

const validateOpts = declareOpts({
  projectRoots: {
    type: 'array',
    required: true,
  },
  blacklistRE: {
    type: 'object', // typeof regex is object
  },
  moduleFormat: {
    type: 'string',
    default: 'haste',
  },
  polyfillModuleNames: {
    type: 'array',
    default: [],
  },
  cacheVersion: {
    type: 'string',
    default: '1.0',
  },
  resetCache: {
    type: 'boolean',
    default: false,
  },
  transformModulePath: {
    type:'string',
    required: false,
  },
  nonPersistent: {
    type: 'boolean',
    default: false,
  },
  assetRoots: {
    type: 'array',
    required: false,
  },
  assetExts: {
    type: 'array',
    default: ['png'],
  },
  fileWatcher: {
    type: 'object',
    required: true,
  },
  assetServer: {
    type: 'object',
    required: true,
  },
  transformTimeoutInterval: {
    type: 'number',
    required: false,
  },
  disableInternalTransforms: {
    type: 'boolean',
    default: false,
  },
});

class Bundler {

  constructor(options) {
    const opts = this._opts = validateOpts(options);

    opts.projectRoots.forEach(verifyRootExists);

    let mtime;
    try {
      ({mtime} = fs.statSync(opts.transformModulePath));
      mtime = String(mtime.getTime());
    } catch (error) {
      mtime = '';
    }

    this._cache = new Cache({
      resetCache: opts.resetCache,
      cacheKey: [
        'react-packager-cache',
        version,
        opts.cacheVersion,
        opts.projectRoots.join(',').split(path.sep).join('-'),
        mtime
      ].join('$'),
    });

    this._resolver = new Resolver({
      projectRoots: opts.projectRoots,
      blacklistRE: opts.blacklistRE,
      polyfillModuleNames: opts.polyfillModuleNames,
      moduleFormat: opts.moduleFormat,
      assetRoots: opts.assetRoots,
      fileWatcher: opts.fileWatcher,
      assetExts: opts.assetExts,
      cache: this._cache,
    });

    this._bundlesLayout = new BundlesLayout({
      dependencyResolver: this._resolver,
      resetCache: opts.resetCache,
      cacheVersion: opts.cacheVersion,
      projectRoots: opts.projectRoots,
    });

    this._transformer = new Transformer({
      projectRoots: opts.projectRoots,
      blacklistRE: opts.blacklistRE,
      cache: this._cache,
      transformModulePath: opts.transformModulePath,
      disableInternalTransforms: opts.disableInternalTransforms,
    });

    this._projectRoots = opts.projectRoots;
    this._assetServer = opts.assetServer;

    if (opts.getTransformOptionsModulePath) {
      this._transformOptionsModule = require(
        opts.getTransformOptionsModulePath
      );
    }
  }

  kill() {
    this._transformer.kill();
    return this._cache.end();
  }

  getLayout(main, isDev) {
    return this._bundlesLayout.generateLayout(main, isDev);
  }

  bundle(options) {
    return this._bundle({
      bundle: new Bundle(options.sourceMapUrl),
      includeSystemDependencies: true,
      ...options,
    });
  }

  _sourceHMRURL(platform, path) {
    return this._hmrURL(
      'http://localhost:8081', // TODO: (martinb) avoid hardcoding
      platform,
      'bundle',
      path,
    );
  }

  _sourceMappingHMRURL(platform, path) {
    // Chrome expects `sourceURL` when eval'ing code
    return this._hmrURL(
      '\/\/# sourceURL=',
      platform,
      'map',
      path,
    );
  }

  _hmrURL(prefix, platform, extensionOverride, path) {
    const matchingRoot = this._projectRoots.find(root => path.startsWith(root));

    if (!matchingRoot) {
      throw new Error('No matching project root for ', path);
    }

    const extensionStart = path.lastIndexOf('.');
    let resource = path.substring(
      matchingRoot.length,
      extensionStart !== -1 ? extensionStart : undefined,
    );

    const extension = extensionStart !== -1
      ? path.substring(extensionStart + 1)
      : null;

    return (
      prefix + resource +
      '.' + extensionOverride + '?' +
      'platform=' + platform + '&runModule=false&entryModuleOnly=true&hot=true'
    );
  }

  bundleForHMR(options) {
    return this._bundle({
      bundle: new HMRBundle({
        sourceURLFn: this._sourceHMRURL.bind(this, options.platform),
        sourceMappingURLFn: this._sourceMappingHMRURL.bind(
          this,
          options.platform,
        ),
      }),
      hot: true,
      ...options,
    });
  }

  _bundle({
    bundle,
    modules,
    entryFile,
    runModule: runMainModule,
    runBeforeMainModule,
    dev: isDev,
    includeSystemDependencies,
    platform,
    unbundle: isUnbundle,
    hot: hot,
    entryModuleOnly,
  }) {
    const findEventId = Activity.startEvent('find dependencies');
    let transformEventId;

    return this.getDependencies(entryFile, isDev, platform).then((response) => {
      Activity.endEvent(findEventId);
      bundle.setMainModuleId(response.mainModuleId);
      bundle.setMainModuleName(response.mainModuleId);
      transformEventId = Activity.startEvent('transform');

      let dependencies;
      if (entryModuleOnly) {
        dependencies = response.dependencies.filter(module =>
          module.path.endsWith(entryFile)
        );
      } else {
        const moduleSystemDeps = includeSystemDependencies
          ? this._resolver.getModuleSystemDependencies(
            { dev: isDev, platform, isUnbundle }
          )
          : [];

        const modulesToProcess = modules || response.dependencies;
        dependencies = moduleSystemDeps.concat(modulesToProcess);

        bundle.setNumPrependedModules && bundle.setNumPrependedModules(
          response.numPrependedDependencies + moduleSystemDeps.length
        );
      }

      let bar;
      if (process.stdout.isTTY) {
        bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
          complete: '=',
          incomplete: ' ',
          width: 40,
          total: dependencies.length,
        });
      }

      return Promise.all(
        dependencies.map(
          module => {
            return this._transformModule(
              bundle,
              response,
              module,
              platform,
              isDev,
              hot,
            ).then(transformed => {
              if (bar) {
                bar.tick();
              }

              return {
                module,
                transformed,
              };
            });
          }
        )
      ).then(transformedModules => Promise.all(
        transformedModules.map(({module, transformed}) => {
          return bundle.addModule(
            this._resolver,
            response,
            module,
            transformed,
          );
        })
      ));
    }).then(() => {
      Activity.endEvent(transformEventId);
      bundle.finalize({runBeforeMainModule, runMainModule});
      return bundle;
    });
  }

  prepackBundle({
    entryFile,
    runModule: runMainModule,
    runBeforeMainModule,
    sourceMapUrl,
    dev: isDev,
    platform,
  }) {
    const bundle = new PrepackBundle(sourceMapUrl);
    const findEventId = Activity.startEvent('find dependencies');
    let transformEventId;
    let mainModuleId;

    return this.getDependencies(entryFile, isDev, platform).then((response) => {
      Activity.endEvent(findEventId);
      transformEventId = Activity.startEvent('transform');

      let bar;
      if (process.stdout.isTTY) {
        bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
          complete: '=',
          incomplete: ' ',
          width: 40,
          total: response.dependencies.length,
        });
      }

      mainModuleId = response.mainModuleId;

      return Promise.all(
        response.dependencies.map(
          module => this._transformModule(
            bundle,
            response,
            module,
            platform,
            isDev,
          ).then(transformed => {
            if (bar) {
              bar.tick();
            }

            var deps = Object.create(null);
            var pairs = response.getResolvedDependencyPairs(module);
            if (pairs) {
              pairs.forEach(pair => {
                deps[pair[0]] = pair[1].path;
              });
            }

            return module.getName().then(name => {
              bundle.addModule(name, transformed, deps, module.isPolyfill());
            });
          })
        )
      );
    }).then(() => {
      Activity.endEvent(transformEventId);
      bundle.finalize({runBeforeMainModule, runMainModule, mainModuleId });
      return bundle;
    });
  }

  _transformModuleForHMR(module, platform) {
    if (module.isAsset()) {
      return this._generateAssetObjAndCode(module, platform).then(
        ({asset, code}) => {
          return {
            code,
          };
        }
      );
    } else {
      // TODO(martinb): pass non null main (t9527509)
      return this._getTransformOptions(
        {main: null, dev: true, platform: 'ios'}, // TODO(martinb): avoid hard-coding platform
        {hot: true},
      ).then(options => {
        return this._transformer.loadFileAndTransform(module.path, options);
      });
    }
  }

  invalidateFile(filePath) {
    if (this._transformOptionsModule) {
      this._transformOptionsModule.onFileChange &&
        this._transformOptionsModule.onFileChange();
    }

    this._transformer.invalidateFile(filePath);
  }

  getShallowDependencies(entryFile) {
    return this._resolver.getShallowDependencies(entryFile);
  }

  stat(filePath) {
    return this._resolver.stat(filePath);
  }

  getModuleForPath(entryFile) {
    return this._resolver.getModuleForPath(entryFile);
  }

  getDependencies(main, isDev, platform) {
    return this._resolver.getDependencies(main, { dev: isDev, platform });
  }

  getOrderedDependencyPaths({ entryFile, dev, platform }) {
    return this.getDependencies(entryFile, dev, platform).then(
      ({ dependencies }) => {
        const ret = [];
        const promises = [];
        const placeHolder = {};
        dependencies.forEach(dep => {
          if (dep.isAsset()) {
            const relPath = getPathRelativeToRoot(
              this._projectRoots,
              dep.path
            );
            promises.push(
              this._assetServer.getAssetData(relPath, platform)
            );
            ret.push(placeHolder);
          } else {
            ret.push(dep.path);
          }
        });

        return Promise.all(promises).then(assetsData => {
          assetsData.forEach(({ files }) => {
            const index = ret.indexOf(placeHolder);
            ret.splice(index, 1, ...files);
          });
          return ret;
        });
      }
    );
  }

  _transformModule(bundle, response, module, platform = null, dev = true, hot = false) {
    if (module.isAsset_DEPRECATED()) {
      return this._generateAssetModule_DEPRECATED(bundle, module);
    } else if (module.isAsset()) {
      return this._generateAssetModule(bundle, module, platform);
    } else if (module.isJSON()) {
      return generateJSONModule(module);
    } else {
      return this._getTransformOptions(
        {
          bundleEntry: bundle.getMainModuleName(),
          platform: platform,
          dev: dev,
          modulePath: module.path,
        },
        {hot: hot},
      ).then(options => {
        return this._transformer.loadFileAndTransform(
          path.resolve(module.path),
          options,
        );
      });
    }
  }

  getGraphDebugInfo() {
    return this._resolver.getDebugInfo();
  }

  _generateAssetModule_DEPRECATED(bundle, module) {
    return Promise.all([
      sizeOf(module.path),
      module.getName(),
    ]).then(([dimensions, id]) => {
      const img = {
        __packager_asset: true,
        path: module.path,
        uri: id.replace(/^[^!]+!/, ''),
        width: dimensions.width / module.resolution,
        height: dimensions.height / module.resolution,
        deprecated: true,
      };

      bundle.addAsset(img);

      const code = 'module.exports = ' + JSON.stringify(img) + ';';

      return new ModuleTransport({
        code: code,
        sourceCode: code,
        sourcePath: module.path,
        virtual: true,
      });
    });
  }

  _generateAssetObjAndCode(module, platform = null) {
    const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
    var assetUrlPath = path.join('/assets', path.dirname(relPath));

    // On Windows, change backslashes to slashes to get proper URL path from file path.
    if (path.sep === '\\') {
      assetUrlPath = assetUrlPath.replace(/\\/g, '/');
    }

    return Promise.all([
      sizeOf(module.path),
      this._assetServer.getAssetData(relPath, platform),
    ]).then(function(res) {
      const dimensions = res[0];
      const assetData = res[1];
      const asset = {
        __packager_asset: true,
        fileSystemLocation: path.dirname(module.path),
        httpServerLocation: assetUrlPath,
        width: dimensions.width / module.resolution,
        height: dimensions.height / module.resolution,
        scales: assetData.scales,
        files: assetData.files,
        hash: assetData.hash,
        name: assetData.name,
        type: assetData.type,
      };

      const ASSET_TEMPLATE = 'module.exports = require("AssetRegistry").registerAsset(%json);';
      const code = ASSET_TEMPLATE.replace('%json', JSON.stringify(asset));

      return {asset, code};
    });
  }

  _generateAssetModule(bundle, module, platform = null) {
    return this._generateAssetObjAndCode(module, platform).then(({asset, code}) => {
      bundle.addAsset(asset);
      return new ModuleTransport({
        code: code,
        sourceCode: code,
        sourcePath: module.path,
        virtual: true,
      });
    });
  }

  _getTransformOptions(config, options) {
    const transformerOptions = this._transformOptionsModule
      ? this._transformOptionsModule.get(Object.assign(
          {
            bundler: this,
            platform: options.platform,
            dev: options.dev,
          },
          config,
        ))
      : Promise.resolve(null);

    return transformerOptions.then(overrides => {
      return {...options, ...overrides};
    });
  }
}

function generateJSONModule(module) {
  return readFile(module.path).then(function(data) {
    const code = 'module.exports = ' + data.toString('utf8') + ';';

    return new ModuleTransport({
      code: code,
      sourceCode: code,
      sourcePath: module.path,
      virtual: true,
    });
  });
}

function getPathRelativeToRoot(roots, absPath) {
  for (let i = 0; i < roots.length; i++) {
    const relPath = path.relative(roots[i], absPath);
    if (relPath[0] !== '.') {
      return relPath;
    }
  }

  throw new Error(
    'Expected root module to be relative to one of the project roots'
  );
}

function verifyRootExists(root) {
  // Verify that the root exists.
  assert(fs.statSync(root).isDirectory(), 'Root has to be a valid directory');
}

class DummyCache {
  get(filepath, field, loaderCb) {
    return loaderCb();
  }

  end(){}
  invalidate(filepath){}
}
module.exports = Bundler;
<|endoftext|>


<commit_before>var uuid = require('node-uuid');
var now = require("performance-now")

function Stopwatch( autostart) {
    if (autostart) this.start();
}

Stopwatch.prototype.start = function() {
    this.startTime = now();
    // console.log('starting stopwatch %s at %s ', self.name, self.startTime);
};

Stopwatch.prototype.stop = function() {
    this.stopTime = now();
};

Stopwatch.prototype.read = function() {
    var self = this;
    var startTime = self.startTime;
    var nowTime;
    var delta;

    if (startTime) {
        if (self.stopTime) {
            nowTime = self.stopTime;
        } else {
            nowTime = now();
        }

        delta = calculateDelta(startTime, nowTime);
    } else {
        nowTime = undefined;
        delta = NaN;
    }

    // console.log('reading stopwatch %s at %s for delta reading of %s ', self.name, nowTime, delta);
    return delta;

    function calculateDelta(start, end) {
        return end - start;
    }
};

module.exports = Stopwatch;<commit_msg>formatting<commit_after>var uuid = require('node-uuid');
var now = require("performance-now");

function Stopwatch( autostart) {
    if (autostart) this.start();
}

Stopwatch.prototype.start = function() {
    this.startTime = now();
    // console.log('starting stopwatch %s at %s ', self.name, self.startTime);
};

Stopwatch.prototype.stop = function() {
    this.stopTime = now();
};

Stopwatch.prototype.read = function() {
    var self = this;
    var startTime = self.startTime;
    var nowTime;
    var delta;

    if (startTime) {
        if (self.stopTime) {
            nowTime = self.stopTime;
        } else {
            nowTime = now();
        }

        delta = calculateDelta(startTime, nowTime);
    } else {
        nowTime = undefined;
        delta = NaN;
    }

    // console.log('reading stopwatch %s at %s for delta reading of %s ', self.name, nowTime, delta);
    return delta;

    function calculateDelta(start, end) {
        return end - start;
    }
};

module.exports = Stopwatch;<|endoftext|>


<commit_before>import * as Kit from "./Kit"
import * as R from "ramda"
import {Tag,enter,leave,tok} from "./core"
import * as assert from "assert"

export const Root = {$:"MatchRoot",kind:"ctrl"}
export const Placeholder = {$:"MatchPlaceholder",kind:"ctrl"}

export const inject = R.curry(function match(pat, si) {
  pat = Kit.toArray(Kit.toks(Tag.top,pat))
  const start = pat[0].type
  const plen = pat.length
  return R.pipe(
    function* match(si) {
      const s = Kit.lookahead(si)
      const activePos = []
      const activeTok = []
      const activePh = []
      assert.ok(plen > 1)
      let level = 0
      for(let i of s) {
        if (i.enter) {
          level++
        }
        let aplen = activePos.length
        for(let p = 0; p < aplen; ++p) {
          let x = activePos[p]
          const v = activeTok[p]
          const ph = activePh[p]
          if (x !== plen && x !== -1 && activePh[p] == null) {
            const j = pat[x++]
            if (x < plen && j.pos != i.pos && j.enter === i.enter) {
              activePos[p] = -1
              v.match = false
              continue
            }
            if (j.enter) {
              switch(j.type) {
              case Tag.ExpressionStatement:
                const k = pat[x]
                if (k.type === Tag.Identifier) {
                  let block = false
                  if (k.value.node.name[0] === "$") {
                    const ph = activePh[p]
                          = {v,level,name:k.value.node.name.substr(1)}
                    yield enter(i.pos,Placeholder,ph)
                    x++
                    assert.equal(pat[x].value,k.value)
                    x++
                    assert.equal(pat[x].value,j.value)
                    x++
                    activePos[p] = x
                    continue
                  }
                }
                break
              case Tag.Identifier:
                let block = false
                if (j.value.node.name[0] === "$") {
                  const ph = activePh[p]
                        = {v,level,name:j.value.node.name.substr(1)}
                  yield enter(i.pos,Placeholder,ph)
                  assert.equal(pat[x].value,j.value)
                  x++
                  activePos[p] = x
                  continue
                }
              }
            }
            if (j.type !== i.type) {
              activePos[p] = -1
              v.match = false
              continue
            }
            activePos[p] = x
          }
        }
        if (i.enter) {
          if (i.type === start) {
            const v = {match:null}
            yield tok(i.pos,Root,{s:true,v})
            activePos.push(1)
            activeTok.push(v)
          }
        }
        yield i
        if (i.leave) {
          let aplen = activePos.length
          for(let p = aplen - 1; p >= 0; --p) {
            let ph = activePh[p]
            if (ph != null) {
              if (ph.level === level) {
                yield leave(i.pos,Placeholder,ph)
                ph = activePh[p] = null
              }
            }
            if (ph == null) {
              let x = activePos[p]
              if (x === plen) {
                activePos[p] = -1
                const v = activeTok[p]
                v.match = true
                while(activePos[0] === -1) {
                  activePos.shift()
                  activePh.shift()
                  activeTok.shift()
                }
                yield tok(i.pos,Root,{s:false,v})
              }
            }
          }
          level--
        }
      }
    },
    Array.from,
    function* matchFilter(s) {
      for(let i of s) {
        switch(i.type) {
        case Root:
          if (!i.value.v.match)
            continue
          i = i.value.s
            ? enter(i.pos,i.type,i.value.v)
            : leave(i.pos,i.type,i.value.v)
          break
        case Placeholder:
          if (!i.value.v.match)
            continue
        }
        yield i
      }
    }/*,
    function matchFin(si) {
      const s = auto(si)
      function* walk() {
        for(const i of s.sub()) {
          if (i.type === Placeholder) {
            if (i.value.name === "B") {
              if (i.enter) {
                const lab = s.label()
                const j = s.cur()
                if (j.type === Tag.BlockStatement) {
                  yield s.peel()
                  yield* s.peelTo(Tag.body)
                  yield s.enter(Tag.push,i.type,i.value)
                } else {
                  yield s.enter(i.pos,Tag.BlockStatement)
                  yield s.enter(Tag.body,Tag.Array)
                  yield s.enter(Tag.push,i.type,i.value)
                  yield s.peel(setPos(s.take(),Tag.push))
                }
                yield* walk()
                yield* lab()
              }
              continue
            }
          }
          yield i
        }
      }
      return walk()
    }*/
  )(si)
})
<commit_msg>export match commit<commit_after>import * as Kit from "./Kit"
import * as R from "ramda"
import {Tag,enter,leave,tok,makeTag} from "./core"
import * as assert from "assert"

export const Root = makeTag("MatchRoot","ctrl")
export const Placeholder = makeTag("MatchPlaceholder","ctrl")

export const commit = R.pipe(
  Array.from,
  function*(s) {
    const buf = []
    for(let i of s) {
      switch(i.type) {
      case Root:
        if (!i.value.v.match)
          continue
        i = i.value.s
          ? enter(i.pos,i.type,i.value.v)
          : leave(i.pos,i.type,i.value.v)
        break
      case Placeholder:
        if (!i.value.v.match)
          continue
      }
      yield i
    }
  })

export const inject = R.curry(function match(pat, si) {
  pat = Kit.toArray(Kit.toks(Tag.top,pat))
  const start = pat[0].type
  const plen = pat.length
  return R.pipe(
    function* match(si) {
      const s = Kit.lookahead(si)
      const activePos = []
      const activeTok = []
      const activePh = []
      assert.ok(plen > 1)
      let level = 0
      for(let i of s) {
        if (i.enter) {
          level++
        }
        let aplen = activePos.length
        for(let p = 0; p < aplen; ++p) {
          let x = activePos[p]
          const v = activeTok[p]
          const ph = activePh[p]
          if (x !== plen && x !== -1 && activePh[p] == null) {
            const j = pat[x++]
            if (x < plen && j.pos != i.pos && j.enter === i.enter) {
              activePos[p] = -1
              v.match = false
              continue
            }
            if (j.enter) {
              switch(j.type) {
              case Tag.ExpressionStatement:
                const k = pat[x]
                if (k.type === Tag.Identifier) {
                  let block = false
                  if (k.value.node.name[0] === "$") {
                    const ph = activePh[p]
                          = {v,level,name:k.value.node.name.substr(1)}
                    yield enter(i.pos,Placeholder,ph)
                    x++
                    assert.equal(pat[x].value,k.value)
                    x++
                    assert.equal(pat[x].value,j.value)
                    x++
                    activePos[p] = x
                    continue
                  }
                }
                break
              case Tag.Identifier:
                let block = false
                if (j.value.node.name[0] === "$") {
                  const ph = activePh[p]
                        = {v,level,name:j.value.node.name.substr(1)}
                  yield enter(i.pos,Placeholder,ph)
                  assert.equal(pat[x].value,j.value)
                  x++
                  activePos[p] = x
                  continue
                }
              }
            }
            if (j.type !== i.type) {
              activePos[p] = -1
              v.match = false
              continue
            }
            activePos[p] = x
          }
        }
        if (i.enter) {
          if (i.type === start) {
            const v = {match:null}
            yield tok(i.pos,Root,{s:true,v})
            activePos.push(1)
            activeTok.push(v)
          }
        }
        yield i
        if (i.leave) {
          let aplen = activePos.length
          for(let p = aplen - 1; p >= 0; --p) {
            let ph = activePh[p]
            if (ph != null) {
              if (ph.level === level) {
                yield leave(i.pos,Placeholder,ph)
                ph = activePh[p] = null
              }
            }
            if (ph == null) {
              let x = activePos[p]
              if (x === plen) {
                activePos[p] = -1
                const v = activeTok[p]
                v.match = true
                while(activePos[0] === -1) {
                  activePos.shift()
                  activePh.shift()
                  activeTok.shift()
                }
                yield tok(i.pos,Root,{s:false,v})
              }
            }
          }
          level--
        }
      }
    },
    commit
  )(si)
})
<|endoftext|>


<commit_before>import warning from 'warning'
import { isStr, pipe } from './utils'
import { normalizePath } from './utils-path'
import { prefixSpec } from './spec'

function findPath(specs, pathKey) {
  let result
  specs.find(spec => !!(result = spec.find(pathKey)))
  return result
}

function addPrefix(prefix, path) {
  return isStr(prefix) && path.indexOf(prefix) !== 0 ? `${prefix}${path}` : path
}

function linkFromPathKey(specs, prefix, pathKey, values = [], usePrefix = true) {
  let link, path = findPath(specs, pathKey)
  if (usePrefix && path) link = addPrefix(prefix, path.makeLink(values))
  return link || ''
}

function matcher(specs, checks, msg) {
  let spec, result, { p } = msg
  spec = specs.find(spec => !!(result = spec.match(checks, p)))
  let success = spec && spec.success(result)
  result = Object.assign({}, msg, result)
  return { result, success, spec }
}

function resolve({ result, success, spec }) {
  warning(!(spec && !success), 'Path resolves with a partial match: %s', result && result.p)
  return spec ? spec.resolve(result, success) : false
}

function matchPrefix(matcher) {
  let { prefix, match, checks } = matcher, result = matcher
  if (prefix) {
    let pspec = prefixSpec(prefix, match)
    result.match = pspec.match.bind(pspec, checks)
  }
  return result
}

function prematch(prespec, msg) {
  let { prefix, p } = msg
  p = pipe(normalizePath(prefix), prespec, normalizePath())(p)
  return p === msg.p ? msg : Object.assign({}, msg, { p })
}

export function match(specs, checks = {}, prefix, prespec) {
  if (!Array.isArray(specs)) specs = [].concat(specs)
  let match = pipe(prematch.bind(null, prespec), matcher.bind(null, specs, checks))
  return matchPrefix({ match, resolve, prefix, specs, checks })
}
<commit_msg>new makePathFromQS fn for prespec<commit_after>import warning from 'warning'
import { isStr, pipe } from './utils'
import { normalizePath } from './utils-path'
import { prefixSpec } from './spec'

function findPath(specs, pathKey) {
  let result
  specs.find(spec => !!(result = spec.find(pathKey)))
  return result
}

function addPrefix(prefix, path) {
  return isStr(prefix) && path.indexOf(prefix) !== 0 ? `${prefix}${path}` : path
}

function linkFromPathKey(specs, prefix, pathKey, values = [], usePrefix = true) {
  let link, path = findPath(specs, pathKey)
  if (usePrefix && path) link = addPrefix(prefix, path.makeLink(values))
  return link || ''
}

function matcher(specs, checks, msg) {
  let spec, result, { p } = msg
  spec = specs.find(spec => !!(result = spec.match(checks, p)))
  let success = spec && spec.success(result)
  result = Object.assign({}, msg, result)
  return { result, success, spec }
}

function resolve({ result, success, spec }) {
  warning(!(spec && !success), 'Path resolves with a partial match: %s', result && result.p)
  return spec ? spec.resolve(result, success) : false
}

function matchPrefix(matcher) {
  let { prefix, match, checks } = matcher, result = matcher
  if (prefix) {
    let pspec = prefixSpec(prefix, match)
    result.match = pspec.match.bind(pspec, checks)
  }
  return result
}

function makePathFromQS(qs, ids, path='', delim=',') {
  let values = ids.map(id => {
    let rx = new RegExp(`${escapeRx(id)}=([^&#]+)`, 'i')
    return q.split(rx).slice(1).filter(s => !/^[&#]/.test(s)).join(delim)
  })
  return substitute([path, ...values], new Array(ids.length).fill('/'))
}

function prematch(prespec, msg) {
  let { prefix, p, qs, path } = msg
  let makePath = makePathFromQS.bind(null, q)
  p = pipe(normalizePath(prefix), prespec.bind(null, makePath, path), normalizePath())(p)
  return p === msg.p ? msg : Object.assign({}, msg, { p })
}

export function match(specs, checks = {}, prefix, prespec) {
  if (!Array.isArray(specs)) specs = [].concat(specs)
  let match = pipe(prematch.bind(null, prespec), matcher.bind(null, specs, checks))
  return matchPrefix({ match, resolve, prefix, specs, checks })
}
<|endoftext|>


<commit_before>import {inject, customElement, bindable} from 'aurelia-framework';
import $ from 'jquery';

@customElement('modal')
@inject(Element)
export class Modal {
  @bindable showing = false;
  constructor(element) {
    this.element = element;
  }
  attached(){
    $(this.modal).modal({show: false})
    .on('show.bs.modal', () => {
      this.showing = true;
    })
    .on('hide.bs.modal', () => {
      this.showing = false;
    });
  }
  showingChanged(newValue){
    if (newValue) {
      $(this.modal).modal('show')
    } else {
      $(this.modal).modal('hide')
    }
  }
}
<commit_msg>fix(modal): Fixed issue #18 by importing bootstrap instead of jquery as $ in modal.js<commit_after>import {inject, customElement, bindable} from 'aurelia-framework';
import $ from 'bootstrap';

@customElement('modal')
@inject(Element)
export class Modal {
  @bindable showing = false;
  constructor(element) {
    this.element = element;
  }
  attached(){
    $(this.modal).modal({show: false})
    .on('show.bs.modal', () => {
      this.showing = true;
    })
    .on('hide.bs.modal', () => {
      this.showing = false;
    });
  }
  showingChanged(newValue){
    if (newValue) {
      $(this.modal).modal('show')
    } else {
      $(this.modal).modal('hide')
    }
  }
}
<|endoftext|>


<commit_before>import * as t from "transduce"

// Functional helpers

const sum = (a, b) => a + b

export const chromaticKeys = ["Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G"]

export const chordsToRows = (chords, key, nbBarsByRow) => t.into(
  [],
  t.partitionAll(nbBarsByRow),
  chordsToBars(chords, key),
)

export const partsToRows = (chart, nbBarsByRow) => t.into(
  {},
  t.map(([partName, chords]) => [partName, chordsToRows(chords, chart.key, nbBarsByRow)]),
  chart.parts,
)

export function chordsToBars(chords, key) {
  // Return a new list of chords having a max duration of 1, and grouping chords having a duration < 1 bar
  // into the same bar.
  // Duplicate a chord if its duration is greater than a bar, as many times as needed.
  // The returned list is a list of lists.
  let bars = []
  let barChords = []
  chords.forEach((chord, idx) => {
    const chord1 = {
      ...chord,
      referenceIndex: idx,
      rendered: renderChord(chord, key),
    }
    if (chord.duration > 1) {
      let remainingDuration = chord.duration
      while (remainingDuration > 0) {
        chord1.duration = 1
        bars.push([chord1])
        remainingDuration -= 1
      }
      if (remainingDuration > 0) {
        chord1.duration = remainingDuration
        barChords.push(chord1)
      }
    } else {
      barChords.push(chord1)
    }
    if (barChords.length) {
      const barChordsDurationSum = t.transduce(t.map(barChord => barChord.duration), t.completing(sum), 0, barChords)
      if (barChordsDurationSum >= 1) {
        bars.push(barChords)
        barChords = []
      }
    }
  })
  return bars
}

export function renderChord(chord, key) {
  const chartKeyIndex = chromaticKeys.indexOf(key)
  let chordStr = chromaticKeys[(chartKeyIndex + chord.degree) % chromaticKeys.length]
  if (chord.alterations) {
    chordStr += chord.alterations.join()
  }
  return chordStr
}
<commit_msg>Refactor model with transducers<commit_after>import * as tr from "transduce"

// Functional helpers

const sum = (a, b) => a + b

export const chromaticKeys = ["Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G"]

// Return a new list of chords having a max duration of 1, and grouping chords having a duration < 1 bar
// into the same bar.
// Duplicate a chord if its duration is greater than a bar, as many times as needed.
// The returned list is a list of lists.
export const chordsToBars = (key) => {
  let barChords = []
  return tr.transducer((xfStep, value, chord) => {
    const chord1 = {
      ...chord,
      rendered: renderChord(chord, key),
    }
    if (chord.duration > 1) {
      let remainingDuration = chord.duration
      while (remainingDuration > 0) {
        xfStep(value, [chord1])
        remainingDuration -= 1
      }
      if (remainingDuration > 0) {
        chord1.duration = remainingDuration
        barChords.push(chord1)
      }
    } else {
      barChords.push(chord1)
    }
    if (barChords.length) {
      const barChordsDurationSum = tr.transduce(tr.map(barChord => barChord.duration), tr.completing(sum), 0, barChords)
      if (barChordsDurationSum >= 1) {
        xfStep(value, barChords)
        barChords = []
      }
    }
    return value
  })
}

export const chordsToRows = (chords, key, nbBarsByRow) => tr.into(
  [],
  tr.compose(
    chordsToBars(key),
    tr.partitionAll(nbBarsByRow),
  ),
  chords,
)

export const partsToRows = (chart, nbBarsByRow) => tr.into(
  {},
  tr.map(([partName, chords]) => [partName, chordsToRows(chords, chart.key, nbBarsByRow)]),
  chart.parts,
)

export function renderChord(chord, key) {
  const chartKeyIndex = chromaticKeys.indexOf(key)
  let chordStr = chromaticKeys[(chartKeyIndex + chord.degree) % chromaticKeys.length]
  if (chord.alterations) {
    chordStr += chord.alterations.join()
  }
  return chordStr
}
<|endoftext|>


<commit_before>import Rx from 'rx';

function initializeToken() {
  return {
    token: '',
    tokenFormValue: ''
  };
}

function updateAndSaveToken(actions) {
  const { saveToken$, updateToken$ } = actions;
  return Rx.Observable.merge(
    saveToken$
    .map(() => state => {
      state.token = state.tokenFormValue;
      state.tokenFormValue = '';
      return state;
    }),
    updateToken$
    .map(token => state => {
      state.tokenFormValue = token;
      return state;
    })
  );
}

function indexOf(issues, issue) {
  const indexes = issues
  .map((i, index) => [i, index])
  .filter(([i, _]) => i.url === issue.url)
  .map(([_, index]) => index);
  return indexes.length > 0 ? indexes[0] : -1;
}

function merge(issues, issue) {
  const index = indexOf(issues, issue);
  if (index >= 0) {
    issues[index] = issue;
  } else {
    issues.push(issue);
  }
  return addChildren(addParent(issues));
}

function addParent(issues) {
  return issues.map(issue => {
    const m = (issue.body || '').match(/^(?:([^\/]+)\/([^#]+))?#(\d+)/);
    if (!m) return Object.assign({}, issue, { parent: null });
    const [_, u, r, n] = m;
    return Object.assign({}, issue, {
      parent: {
        user: u || issue.user,
        repo: r || issue.repo,
        number: parseInt(n, 10)
      }
    });
  });
}

function addChildren(issues) {
  return issues.map(issue => {
    const { user, repo, number } = issue;
    const children = issues.filter(i => {
      const p = i.parent;
      return p && p.user === user && p.repo === repo && p.number === number;
    });
    return Object.assign({}, issue, { children });
  });
}

export default function(actions) {
  const {
    addRepo$,
    fetchIssues$,
    updateIssue$,
    updateRepo$,
    updateUser$
  } = actions;
  const state = {
    issues: [],
    repos: [],
    requests: [],
    repo: null,
    user: null,
    ...initializeToken()
  };
  const reposMaxLength = 10;
  const actions$ = Rx.Observable.merge(
    fetchIssues$
    .map((_, i) => state => {
      const newRequests = state.repos.map(({ user, repo }, j) => {
        const id = i * reposMaxLength + j;
        const url = `https://api.github.com/repos/${user}/${repo}/issues`;
        const headers = { 'User-Agent': 'gh-tree' };
        return { id, method: 'GET', url, headers };
      });
      state.requests = state.requests.concat(newRequests);
      return state;
    }),
    addRepo$
    .map(repo => state => {
      const { user, repo } = state;
      if (state.repos.length > reposMaxLength) return state;
      const duplicated = state.repos.filter(i => {
        return i.user === user && i.repo === repo;
      }).length > 0;
      if (duplicated) return state;
      state.repos.push({ user, repo });
      return state;
    }),
    updateAndSaveToken(actions),
    updateIssue$
    .map(issue => state => {
      state.issues = merge(state.issues, issue);
      return state;
    }),
    updateRepo$
    .map(repo => state => {
      state.repo = repo;
      return state;
    }),
    updateUser$
    .map(user => state => {
      state.user = user;
      return state;
    })
  );
  const state$ = Rx.Observable.just(state)
    .merge(actions$)
    .scan((state, action) => action(state))
    .share();
  return state$;
}
<commit_msg>change token state<commit_after>import Rx from 'rx';

function initializeToken() {
  return {
    // TODO
    settings: {
      token: ''
    },
    token: {
      value: ''
    }
  };
}

function updateAndSaveToken(actions) {
  const { token } = actions; // namespace
  const { save$, update$ } = token; // actions
  return Rx.Observable.merge(
    save$
    .map(() => state => {
      const { token } = state;
      state.settings.token = token.value;
      token.value = '';
      return state;
    }),
    update$
    .map(value => state => {
      const { token } = state;
      token.value = value;
      return state;
    })
  );
}

function indexOf(issues, issue) {
  const indexes = issues
  .map((i, index) => [i, index])
  .filter(([i, _]) => i.url === issue.url)
  .map(([_, index]) => index);
  return indexes.length > 0 ? indexes[0] : -1;
}

function merge(issues, issue) {
  const index = indexOf(issues, issue);
  if (index >= 0) {
    issues[index] = issue;
  } else {
    issues.push(issue);
  }
  return addChildren(addParent(issues));
}

function addParent(issues) {
  return issues.map(issue => {
    const m = (issue.body || '').match(/^(?:([^\/]+)\/([^#]+))?#(\d+)/);
    if (!m) return Object.assign({}, issue, { parent: null });
    const [_, u, r, n] = m;
    return Object.assign({}, issue, {
      parent: {
        user: u || issue.user,
        repo: r || issue.repo,
        number: parseInt(n, 10)
      }
    });
  });
}

function addChildren(issues) {
  return issues.map(issue => {
    const { user, repo, number } = issue;
    const children = issues.filter(i => {
      const p = i.parent;
      return p && p.user === user && p.repo === repo && p.number === number;
    });
    return Object.assign({}, issue, { children });
  });
}

export default function(actions) {
  const {
    addRepo$,
    fetchIssues$,
    updateIssue$,
    updateRepo$,
    updateUser$
  } = actions;
  const state = {
    issues: [],
    repos: [],
    requests: [],
    repo: null,
    user: null,
    ...initializeToken()
  };
  const reposMaxLength = 10;
  const actions$ = Rx.Observable.merge(
    fetchIssues$
    .map((_, i) => state => {
      const newRequests = state.repos.map(({ user, repo }, j) => {
        const id = i * reposMaxLength + j;
        const url = `https://api.github.com/repos/${user}/${repo}/issues`;
        const headers = { 'User-Agent': 'gh-tree' };
        return { id, method: 'GET', url, headers };
      });
      state.requests = state.requests.concat(newRequests);
      return state;
    }),
    addRepo$
    .map(repo => state => {
      const { user, repo } = state;
      if (state.repos.length > reposMaxLength) return state;
      const duplicated = state.repos.filter(i => {
        return i.user === user && i.repo === repo;
      }).length > 0;
      if (duplicated) return state;
      state.repos.push({ user, repo });
      return state;
    }),
    updateAndSaveToken(actions),
    updateIssue$
    .map(issue => state => {
      state.issues = merge(state.issues, issue);
      return state;
    }),
    updateRepo$
    .map(repo => state => {
      state.repo = repo;
      return state;
    }),
    updateUser$
    .map(user => state => {
      state.user = user;
      return state;
    })
  );
  const state$ = Rx.Observable.just(state)
    .merge(actions$)
    .scan((state, action) => action(state))
    .share();
  return state$;
}
<|endoftext|>


<commit_before>	// @constructor
	return {
		// Classes
		array           : array,
		callback        : {},
		client          : {
			// Properties
			android : client.android,
			blackberry : client.blackberry,
			chrome  : client.chrome,
			firefox : client.firefox,
			ie      : client.ie,
			ios     : client.ios,
			linux   : client.linux,
			mobile  : client.mobile,
			opera   : client.opera,
			osx     : client.osx,
			playbook: client.playbook,
			safari  : client.safari,
			tablet  : client.tablet,
			size    : {height: 0, width: 0},
			version : 0,
			webos   : client.webos,
			windows : client.windows,

			// Methods
			del     : function (uri, success, failure, headers) { return client.request(uri, "DELETE", success, failure, null, headers); },
			get     : function (uri, success, failure, headers) { return client.request(uri, "GET", success, failure, null, headers); },
			headers : function (uri, success, failure) { return client.request(uri, "HEAD", success, failure); },
			post    : function (uri, success, failure, args, headers) { return client.request(uri, "POST", success, failure, args, headers); },
			put     : function (uri, success, failure, args, headers) { return client.request(uri, "PUT", success, failure, args, headers); },
			jsonp   : function (uri, success, failure, callback) { return client.jsonp(uri, success, failure, callback); },
			options : function (uri, success, failure) { return client.request(uri, "OPTIONS", success, failure); },
			permissions : client.permissions
		},
		cookie          : cookie,
		data            : data,
		element         : element,
		json            : json,
		label           : label,
		loading         : {
			create  : utility.loading,
			url     : null
		},
		message         : message,
		mouse           : mouse,
		number          : number,
		observer        : {
			log     : observer.log,
			add     : observer.add,
			fire    : observer.fire,
			list    : observer.list,
			once    : observer.once,
			remove  : observer.remove
		},
		state           : {
			_current    : null,
			header      : null,
			previous    : null
		},
		string          : string,
		validate        : validate,
		xml             : xml,

		// Methods & Properties
		$               : utility.$,
		alias           : utility.alias,
		aliased         : "$",
		allows          : client.allows,
		append          : function (type, args, obj) {
			if (obj instanceof Element) obj.genId();
			return element.create(type, args, obj, "last");
		},
		bootstrap       : bootstrap,
		clear           : element.clear,
		clone           : utility.clone,
		coerce          : utility.coerce,
		compile         : utility.compile,
		create          : element.create,
		css             : element.css,
		decode          : json.decode,
		defer           : utility.defer,
		define          : utility.define,
		del             : function (uri, success, failure, headers) { return client.request(uri, "DELETE", success, failure, null, headers); },
		destroy         : element.destroy,
		encode          : json.encode,
		error           : utility.error,
		expire          : cache.clean,
		expires         : 120000,
		extend          : utility.extend,
		fire            : function (obj, event, arg) {
			var all = typeof arg !== "undefined",
			    o, e, a;

			o = all ? obj   : this;
			e = all ? event : obj;
			a = all ? arg   : event;

			if (typeof o === "undefined" || o === $) o = abaaso;
			return observer.fire(o, e, a);
		},
		genId           : utility.genId,
 		get             : function (uri, success, failure, headers) { return client.request(uri, "GET", success, failure, null, headers); },
		guid            : utility.guid,
		headers         : function (uri, success, failure) { return client.request(uri, "HEAD", success, failure); },
		hidden          : element.hidden,
		id              : "abaaso",
		init            : function () {
			// Stopping multiple executions
			delete abaaso.init;

			// Firing events to setup
			return $.fire("init").un("init").fire("ready").un("ready");
		},
		iterate         : utility.iterate,
		jsonp           : function (uri, success, failure, callback) { return client.jsonp(uri, success, failure, callback); },
		listeners       : function (event) {
			var obj = this;

			if (typeof obj === "undefined" || obj === $) obj = abaaso;
			return observer.list(obj, event);
		},
		log             : utility.log,
		merge           : utility.merge,
		module          : utility.module,
		object          : utility.object,
		on              : function (obj, event, listener, id, scope, state) {
			var all = typeof listener === "function",
			    o, e, l, i, s, st;

			o  = all ? obj      : this;
			e  = all ? event    : obj;
			l  = all ? listener : event;
			i  = all ? id       : listener;
			s  = all ? scope    : id;
			st = all ? state    : scope;

			if (typeof o === "undefined" || o === $) o = abaaso;
			if (typeof s === "undefined") s = o;
			return observer.add(o, e, l, i, s, st);
		},
		once            : function (obj, event, listener, id, scope, state) {
			var all = typeof listener === "function",
			    o, e, l, i, s, st;

			o  = all ? obj      : this;
			e  = all ? event    : obj;
			l  = all ? listener : event;
			i  = all ? id       : listener;
			s  = all ? scope    : id;
			st = all ? state    : scope;

			if (typeof o === "undefined" || o === $) o = abaaso;
			if (typeof s === "undefined") s = o;
			return observer.once(o, e, l, i, s, st);
		},
		options         : function (uri, success, failure) { return client.request(uri, "OPTIONS", success, failure); },
		permissions     : client.permissions,
		position        : element.position,
		post            : function (uri, success, failure, args, headers) { return client.request(uri, "POST", success, failure, args, headers); },
		prepend         : function (type, args, obj) {
			if (obj instanceof Element) obj.genId();
			return element.create(type, args, obj, "first");
		},
		property        : utility.property,
		put             : function (uri, success, failure, args, headers) { return client.request(uri, "PUT", success, failure, args, headers); },
		queryString     : utility.queryString,
		ready           : false,
		reflect         : utility.reflect,
		repeat          : utility.repeat,
		route           : {
			enabled : false,
			del     : route.del,
			hash    : route.hash,
			init    : route.init,
			list    : route.list,
			load    : route.load,
			set     : route.set
		},
		stylesheet      : function (arg, media) { return element.create("link", {rel: "stylesheet", type: "text/css", href: arg, media: media || "print, screen"}, $("head")[0]); },
		script          : function (arg, target, pos) { return element.create("script", {type: "application/javascript", src: arg}, target || $("head")[0], pos); },
		stop            : utility.stop,
		store           : function (arg, args) { return data.register.call(data, arg, args); },
		tpl             : utility.tpl,
		un              : function (obj, event, id, state) {
			var all = typeof id !== "undefined",
			    o, e, i, s;

			o = all ? obj   : this;
			e = all ? event : obj;
			i = all ? id    : event;
			s = all ? state : id;

			if (typeof o === "undefined" || o === $) o = abaaso;
			return observer.remove(o, e, i, s);
		},
		update          : element.update,
		version         : "{{VERSION}}",
		walk            : utility.walk
	};
})();

// Conditional bootstrap incase of multiple loading
if (typeof abaaso.bootstrap === "function") abaaso.bootstrap();

// Node, AMD & window supported
switch (true) {
	case typeof exports !== "undefined":
		module.exports = abaaso;
		break;
	case typeof define === "function":
		define(function () { return abaaso; });
		break;
	default:
		global.abaaso = abaaso;
}
})(this);
<commit_msg>Updating alignment in outro.js<commit_after>// @constructor
return {
	// Classes
	array           : array,
	callback        : {},
	client          : {
		// Properties
		android : client.android,
		blackberry : client.blackberry,
		chrome  : client.chrome,
		firefox : client.firefox,
		ie      : client.ie,
		ios     : client.ios,
		linux   : client.linux,
		mobile  : client.mobile,
		opera   : client.opera,
		osx     : client.osx,
		playbook: client.playbook,
		safari  : client.safari,
		tablet  : client.tablet,
		size    : {height: 0, width: 0},
		version : 0,
		webos   : client.webos,
		windows : client.windows,

		// Methods
		del     : function (uri, success, failure, headers) { return client.request(uri, "DELETE", success, failure, null, headers); },
		get     : function (uri, success, failure, headers) { return client.request(uri, "GET", success, failure, null, headers); },
		headers : function (uri, success, failure) { return client.request(uri, "HEAD", success, failure); },
		post    : function (uri, success, failure, args, headers) { return client.request(uri, "POST", success, failure, args, headers); },
		put     : function (uri, success, failure, args, headers) { return client.request(uri, "PUT", success, failure, args, headers); },
		jsonp   : function (uri, success, failure, callback) { return client.jsonp(uri, success, failure, callback); },
		options : function (uri, success, failure) { return client.request(uri, "OPTIONS", success, failure); },
		permissions : client.permissions
	},
	cookie          : cookie,
	data            : data,
	element         : element,
	json            : json,
	label           : label,
	loading         : {
		create  : utility.loading,
		url     : null
	},
	message         : message,
	mouse           : mouse,
	number          : number,
	observer        : {
		log     : observer.log,
		add     : observer.add,
		fire    : observer.fire,
		list    : observer.list,
		once    : observer.once,
		remove  : observer.remove
	},
	state           : {
		_current    : null,
		header      : null,
		previous    : null
	},
	string          : string,
	validate        : validate,
	xml             : xml,

	// Methods & Properties
	$               : utility.$,
	alias           : utility.alias,
	aliased         : "$",
	allows          : client.allows,
	append          : function (type, args, obj) {
		if (obj instanceof Element) obj.genId();
		return element.create(type, args, obj, "last");
	},
	bootstrap       : bootstrap,
	clear           : element.clear,
	clone           : utility.clone,
	coerce          : utility.coerce,
	compile         : utility.compile,
	create          : element.create,
	css             : element.css,
	decode          : json.decode,
	defer           : utility.defer,
	define          : utility.define,
	del             : function (uri, success, failure, headers) { return client.request(uri, "DELETE", success, failure, null, headers); },
	destroy         : element.destroy,
	encode          : json.encode,
	error           : utility.error,
	expire          : cache.clean,
	expires         : 120000,
	extend          : utility.extend,
	fire            : function (obj, event, arg) {
		var all = typeof arg !== "undefined",
		    o, e, a;

		o = all ? obj   : this;
		e = all ? event : obj;
		a = all ? arg   : event;

		if (typeof o === "undefined" || o === $) o = abaaso;
		return observer.fire(o, e, a);
	},
	genId           : utility.genId,
		get             : function (uri, success, failure, headers) { return client.request(uri, "GET", success, failure, null, headers); },
	guid            : utility.guid,
	headers         : function (uri, success, failure) { return client.request(uri, "HEAD", success, failure); },
	hidden          : element.hidden,
	id              : "abaaso",
	init            : function () {
		// Stopping multiple executions
		delete abaaso.init;

		// Firing events to setup
		return $.fire("init").un("init").fire("ready").un("ready");
	},
	iterate         : utility.iterate,
	jsonp           : function (uri, success, failure, callback) { return client.jsonp(uri, success, failure, callback); },
	listeners       : function (event) {
		var obj = this;

		if (typeof obj === "undefined" || obj === $) obj = abaaso;
		return observer.list(obj, event);
	},
	log             : utility.log,
	merge           : utility.merge,
	module          : utility.module,
	object          : utility.object,
	on              : function (obj, event, listener, id, scope, state) {
		var all = typeof listener === "function",
		    o, e, l, i, s, st;

		o  = all ? obj      : this;
		e  = all ? event    : obj;
		l  = all ? listener : event;
		i  = all ? id       : listener;
		s  = all ? scope    : id;
		st = all ? state    : scope;

		if (typeof o === "undefined" || o === $) o = abaaso;
		if (typeof s === "undefined") s = o;
		return observer.add(o, e, l, i, s, st);
	},
	once            : function (obj, event, listener, id, scope, state) {
		var all = typeof listener === "function",
		    o, e, l, i, s, st;

		o  = all ? obj      : this;
		e  = all ? event    : obj;
		l  = all ? listener : event;
		i  = all ? id       : listener;
		s  = all ? scope    : id;
		st = all ? state    : scope;

		if (typeof o === "undefined" || o === $) o = abaaso;
		if (typeof s === "undefined") s = o;
		return observer.once(o, e, l, i, s, st);
	},
	options         : function (uri, success, failure) { return client.request(uri, "OPTIONS", success, failure); },
	permissions     : client.permissions,
	position        : element.position,
	post            : function (uri, success, failure, args, headers) { return client.request(uri, "POST", success, failure, args, headers); },
	prepend         : function (type, args, obj) {
		if (obj instanceof Element) obj.genId();
		return element.create(type, args, obj, "first");
	},
	property        : utility.property,
	put             : function (uri, success, failure, args, headers) { return client.request(uri, "PUT", success, failure, args, headers); },
	queryString     : utility.queryString,
	ready           : false,
	reflect         : utility.reflect,
	repeat          : utility.repeat,
	route           : {
		enabled : false,
		del     : route.del,
		hash    : route.hash,
		init    : route.init,
		list    : route.list,
		load    : route.load,
		set     : route.set
	},
	stylesheet      : function (arg, media) { return element.create("link", {rel: "stylesheet", type: "text/css", href: arg, media: media || "print, screen"}, $("head")[0]); },
	script          : function (arg, target, pos) { return element.create("script", {type: "application/javascript", src: arg}, target || $("head")[0], pos); },
	stop            : utility.stop,
	store           : function (arg, args) { return data.register.call(data, arg, args); },
	tpl             : utility.tpl,
	un              : function (obj, event, id, state) {
		var all = typeof id !== "undefined",
		    o, e, i, s;

		o = all ? obj   : this;
		e = all ? event : obj;
		i = all ? id    : event;
		s = all ? state : id;

		if (typeof o === "undefined" || o === $) o = abaaso;
		return observer.remove(o, e, i, s);
	},
	update          : element.update,
	version         : "{{VERSION}}",
	walk            : utility.walk
};
})();

// Conditional bootstrap incase of multiple loading
if (typeof abaaso.bootstrap === "function") abaaso.bootstrap();

// Node, AMD & window supported
switch (true) {
	case typeof exports !== "undefined":
		module.exports = abaaso;
		break;
	case typeof define === "function":
		define(function () { return abaaso; });
		break;
	default:
		global.abaaso = abaaso;
}
})(this);
<|endoftext|>


<commit_before>/*globals require, module */

'use strict';

var events, JsonError, terminators;

events = require('events');
JsonError = require('JsonError');

terminators = {
    object: '}',
    array: ']'
};

module.exports = parse;

function parse (json) {
    var emitter, index, line, column, scopes, handlers;

    emitter = new events.EventEmitter;
    index = 0;
    line = column = 1;
    scopes = [];
    handlers = {
        array: value,
        object: property
    };

    setImmediate(value);

    return result;

    function value () {
        ignoreWhitespace();

        switch (next()) {
            case '{':
                return setImmediate(object);
            case '[':
                return setImmediate(array);
            case '"':
                return setImmediate(string);
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
                return setImmediate(number);
            default:
                return setImmediate(literal);
        }
    }

    function ignoreWhitespace () {
        while (true) {
            switch (next()) {
                case ' ':
                case '\t':
                case '\r':
                case '\n':
                    continue;
            }

            break;
        }
    }

    function next () {
        if (index === json.length) {
            return end();
        }

        if (character() === '\n') {
            line += 1;
            column = 1;
        } else {
            column += 1;
        }

        return character();
    }

    function character () {
        return json[index];
    }

    function end () {
        while (scopes.length > 0) {
            error('EOF', terminators[scopes.pop()]);
        }

        emitter.emit('end');
    }

    function error (actual, expected) {
        emitter.emit('error', new JsonError(actual, expected, line, column));
    }

    function object () {
        scope('object');
        setImmediate(name);
    }

    function scope (type) {
        emitter.emit(type);
        scopes.push(type);
    }

    function name () {
        parseString('property');

        ignoreWhitespace();
        check(next(), ':');

        setImmediate(value);
    }

    function parseString (event) {
        var string = '';

        ignoreWhitespace();
        check(next(), '"');

        while (character() !== '"') {
            string += next();
        }

        emitter.emit(event, string);
    }

    function check (character, expected) {
        if (character !== expected) {
            error('`' + character + '`', expected);
        }
    }

    function array () {
        scope('array');
        setImmediate(value);
    }

    function string (event) {
        parseString('string');
    }

    function endValue () {
        var scope, character;

        ignoreWhitespace();

        if (scopes.length === 0) {
            setImmediate(value);
            return;
        }

        scope = scopes[scopes.length - 1];
        character = next();

        if (character === ',') {
            setImmediate(handlers[scope]);
            return;
        }

        check(character, terminators[scope]);
        setImmediate(endValue);
    }
}
<commit_msg>Re-order functions.<commit_after>/*globals require, module */

'use strict';

var events, JsonError, terminators;

events = require('events');
JsonError = require('JsonError');

terminators = {
    object: '}',
    array: ']'
};

module.exports = parse;

function parse (json) {
    var emitter, index, line, column, scopes, handlers;

    emitter = new events.EventEmitter;
    index = 0;
    line = column = 1;
    scopes = [];
    handlers = {
        array: value,
        object: property
    };

    setImmediate(value);

    return result;

    function value () {
        ignoreWhitespace();

        switch (next()) {
            case '[':
                return setImmediate(array);
            case '{':
                return setImmediate(object);
            case '"':
                return setImmediate(string);
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
                return setImmediate(number);
            default:
                return setImmediate(literal);
        }
    }

    function ignoreWhitespace () {
        while (true) {
            switch (next()) {
                case ' ':
                case '\t':
                case '\r':
                case '\n':
                    continue;
            }

            break;
        }
    }

    function next () {
        if (index === json.length) {
            return end();
        }

        if (character() === '\n') {
            line += 1;
            column = 1;
        } else {
            column += 1;
        }

        return character();
    }

    function end () {
        while (scopes.length > 0) {
            error('EOF', terminators[scopes.pop()]);
        }

        emitter.emit('end');
    }

    function error (actual, expected) {
        emitter.emit('error', new JsonError(actual, expected, line, column));
    }

    function character () {
        return json[index];
    }

    function array () {
        scope('array');
        setImmediate(value);
    }

    function scope (type) {
        emitter.emit(type);
        scopes.push(type);
    }

    function object () {
        scope('object');
        setImmediate(name);
    }

    function name () {
        parseString('property');

        ignoreWhitespace();
        check(next(), ':');

        setImmediate(value);
    }

    function parseString (event) {
        var string = '';

        ignoreWhitespace();
        check(next(), '"');

        while (character() !== '"') {
            string += next();
        }

        emitter.emit(event, string);
    }

    function check (character, expected) {
        if (character !== expected) {
            error('`' + character + '`', expected);
        }
    }

    function string (event) {
        parseString('string');
    }

    function endValue () {
        var scope, character;

        ignoreWhitespace();

        if (scopes.length === 0) {
            setImmediate(value);
            return;
        }

        scope = scopes[scopes.length - 1];
        character = next();

        if (character === ',') {
            setImmediate(handlers[scope]);
            return;
        }

        check(character, terminators[scope]);
        setImmediate(endValue);
    }
}
<|endoftext|>