<commit_before>const fs = require('fs-extra');
const { join } = require('path');
const path = require('path');
const URL = require('url');
const Git = require('simple-git/promise');
const convertHrtime = require('convert-hrtime');

class Storage {
  constructor() {
    let config = {};
    let git = null;
    let cwd = null;

    Object.assign(this, {
      initRepo,
      cleanRepo,
      getRepoStatus,
      setBaseBranch,
      branchExists,
      commitFilesToBranch,
      createBranch,
      deleteBranch,
      getAllRenovateBranches,
      getBranchCommit,
      getBranchLastCommitTime,
      getCommitMessages,
      getFile,
      getFileList,
      isBranchStale,
      mergeBranch,
    });

    // istanbul ignore next
    async function resetToBranch(branchName) {
      logger.debug(`resetToBranch(${branchName})`);
      await git.raw(['reset', '--hard']);
      await git.checkout(branchName);
      await git.raw(['reset', '--hard', 'origin/' + branchName]);
      await git.raw(['clean', '-fd']);
    }

    // istanbul ignore next
    async function cleanLocalBranches() {
      const existingBranches = (await git.raw(['branch']))
        .split('\n')
        .map(branch => branch.trim())
        .filter(branch => branch.length)
        .filter(branch => !branch.startsWith('* '));
      logger.debug({ existingBranches });
      for (const branchName of existingBranches) {
        await deleteLocalBranch(branchName);
      }
    }

    async function initRepo(args) {
      cleanRepo();
      config = { ...args };
      cwd = config.localDir;
      config.branchExists = {};
      logger.info('Initialising git repository into ' + cwd);
      const gitHead = path.join(cwd, '.git/HEAD');
      let clone = true;
      async function determineBaseBranch() {
        // see https://stackoverflow.com/a/44750379/1438522
        try {
          config.baseBranch =
            config.baseBranch ||
            (await git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']))
              .replace('refs/remotes/origin/', '')
              .trim();
        } catch (err) /* istanbul ignore next */ {
          if (
            err.message.startsWith(
              'fatal: ref refs/remotes/origin/HEAD is not a symbolic ref'
            )
          ) {
            throw new Error('empty');
          }
          throw err;
        }
      }
      // istanbul ignore if
      if (process.env.NODE_ENV !== 'test' && (await fs.exists(gitHead))) {
        try {
          git = Git(cwd).silent(true);
          await git.raw(['remote', 'set-url', 'origin', config.url]);
          const fetchStart = process.hrtime();
          await git.fetch([config.url, '--depth=2', '--no-single-branch']);
          await determineBaseBranch();
          await resetToBranch(config.baseBranch);
          await cleanLocalBranches();
          await git.raw(['remote', 'prune', 'origin']);
          const fetchSeconds =
            Math.round(
              1 + 10 * convertHrtime(process.hrtime(fetchStart)).seconds
            ) / 10;
          logger.info({ fetchSeconds }, 'git fetch completed');
          clone = false;
        } catch (err) {
          logger.error({ err }, 'git fetch error');
        }
      }
      if (clone) {
        await fs.emptyDir(cwd);
        git = Git(cwd).silent(true);
        const cloneStart = process.hrtime();
        try {
          await git.clone(config.url, '.', ['--depth=2', '--no-single-branch']);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'git clone error');
          throw new Error('platform-failure');
        }
        const cloneSeconds =
          Math.round(
            1 + 10 * convertHrtime(process.hrtime(cloneStart)).seconds
          ) / 10;
        logger.info({ cloneSeconds }, 'git clone completed');
      }
      try {
        const latestCommitDate = (await git.log({ n: 1 })).latest.date;
        logger.debug({ latestCommitDate }, 'latest commit');
      } catch (err) /* istanbul ignore next */ {
        if (err.message.includes('does not have any commits yet')) {
          throw new Error('empty');
        }
        logger.warn({ err }, 'Cannot retrieve latest commit date');
      }
      // istanbul ignore if
      if (config.gitPrivateKey) {
        logger.debug('Git private key configured, but not being set');
      } else {
        logger.debug('No git private key present - commits will be unsigned');
        await git.raw(['config', 'commit.gpgsign', 'false']);
      }

      if (global.gitAuthor) {
        logger.info({ gitAuthor: global.gitAuthor }, 'Setting git author');
        try {
          await git.raw(['config', 'user.name', global.gitAuthor.name]);
          await git.raw(['config', 'user.email', global.gitAuthor.email]);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'Error setting git config');
          throw new Error('temporary-error');
        }
      }

      await determineBaseBranch();
    }

    // istanbul ignore next
    function getRepoStatus() {
      return git.status();
    }

    async function createBranch(branchName, sha) {
      logger.debug(`createBranch(${branchName})`);
      await git.reset('hard');
      await git.raw(['clean', '-fd']);
      await git.checkout(['-B', branchName, sha]);
      await git.push(['origin', branchName, '--force']);
      config.branchExists[branchName] = true;
    }

    // Return the commit SHA for a branch
    async function getBranchCommit(branchName) {
      const res = await git.revparse(['origin/' + branchName]);
      return res.trim();
    }

    async function getCommitMessages() {
      logger.debug('getCommitMessages');
      const res = await git.log({
        n: 10,
        format: { message: '%s' },
      });
      return res.all.map(commit => commit.message);
    }

    async function setBaseBranch(branchName) {
      if (branchName) {
        logger.debug(`Setting baseBranch to ${branchName}`);
        config.baseBranch = branchName;
        if (branchName !== 'master') {
          config.baseBranchSha = (await git.raw([
            'rev-parse',
            'origin/' + branchName,
          ])).trim();
        }
      }
    }

    async function getFileList(branchName) {
      const branch = branchName || config.baseBranch;
      const exists = await branchExists(branch);
      if (!exists) {
        return [];
      }
      const files = await git.raw([
        'ls-tree',
        '-r',
        '--name-only',
        'origin/' + branch,
      ]);
      // istanbul ignore if
      if (!files) {
        return [];
      }
      return files.split('\n').filter(Boolean);
    }

    async function branchExists(branchName) {
      // First check cache
      if (config.branchExists[branchName] !== undefined) {
        return config.branchExists[branchName];
      }
      try {
        await git.raw(['show-branch', 'origin/' + branchName]);
        config.branchExists[branchName] = true;
        return true;
      } catch (ex) {
        config.branchExists[branchName] = false;
        return false;
      }
    }

    async function getAllRenovateBranches(branchPrefix) {
      const branches = await git.branch(['--remotes', '--verbose']);
      return branches.all
        .map(localName)
        .filter(branchName => branchName.startsWith(branchPrefix));
    }

    async function isBranchStale(branchName) {
      const branches = await git.branch([
        '--remotes',
        '--verbose',
        '--contains',
        config.baseBranchSha || `origin/${config.baseBranch}`,
      ]);
      return !branches.all.map(localName).includes(branchName);
    }

    async function deleteLocalBranch(branchName) {
      await git.branch(['-D', branchName]);
    }

    async function deleteBranch(branchName) {
      try {
        await git.raw(['push', '--delete', 'origin', branchName]);
        logger.debug({ branchName }, 'Deleted remote branch');
      } catch (err) /* istanbul ignore next */ {
        logger.info({ branchName, err }, 'Error deleting remote branch');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
        } else {
          throw new Error('repository-changed');
        }
      }
      try {
        await deleteLocalBranch(branchName);
        // istanbul ignore next
        logger.debug({ branchName }, 'Deleted local branch');
      } catch (err) {
        logger.debug({ branchName }, 'No local branch to delete');
      }
      config.branchExists[branchName] = false;
    }

    async function mergeBranch(branchName) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + branchName]);
      await git.checkout(config.baseBranch);
      await git.merge([branchName]);
      await git.push('origin', config.baseBranch);
    }

    async function getBranchLastCommitTime(branchName) {
      try {
        const time = await git.show([
          '-s',
          '--format=%ai',
          'origin/' + branchName,
        ]);
        return new Date(Date.parse(time));
      } catch (ex) {
        return new Date();
      }
    }

    async function getFile(filePath, branchName) {
      if (branchName) {
        const exists = await branchExists(branchName);
        if (!exists) {
          logger.info({ branchName }, 'branch no longer exists - aborting');
          throw new Error('repository-changed');
        }
      }
      try {
        const content = await git.show([
          'origin/' + (branchName || config.baseBranch) + ':' + filePath,
        ]);
        return content;
      } catch (ex) {
        return null;
      }
    }

    async function commitFilesToBranch(
      branchName,
      files,
      message,
      parentBranch = config.baseBranch
    ) {
      logger.debug(`Committing files to branch ${branchName}`);
      try {
        await git.reset('hard');
        await git.raw(['clean', '-fd']);
        await git.checkout(['-B', branchName, 'origin/' + parentBranch]);
        const fileNames = [];
        const deleted = [];
        for (const file of files) {
          // istanbul ignore if
          if (file.name === '|delete|') {
            deleted.push(file.contents);
          } else {
            fileNames.push(file.name);
            await fs.outputFile(
              join(cwd, file.name),
              Buffer.from(file.contents)
            );
          }
        }
        // istanbul ignore if
        if (fileNames.length === 1 && fileNames[0] === 'renovate.json') {
          fileNames.unshift('-f');
        }
        if (fileNames.length) await git.add(fileNames);
        if (deleted.length) {
          for (const f of deleted) {
            try {
              await git.rm([f]);
            } catch (err) /* istanbul ignore next */ {
              logger.debug({ err }, 'Cannot delete ' + f);
            }
          }
        }
        await git.commit(message);
        await git.push([
          'origin',
          `${branchName}:${branchName}`,
          '--force',
          '-u',
        ]);
      } catch (err) /* istanbul ignore next */ {
        logger.debug({ err }, 'Error commiting files');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
          throw new Error('disable-gitfs');
        } else if (err.message.includes('[remote rejected]')) {
          throw new Error('repository-changed');
        }
        throw err;
      }
    }

    function cleanRepo() {}
  }
}

function localName(branchName) {
  return branchName.replace(/^origin\//, '');
}

Storage.getUrl = ({ gitFs, auth, hostname, host, repository }) => {
  let protocol = gitFs || 'https';
  // istanbul ignore if
  if (protocol.toString() === 'true') {
    protocol = 'https';
  }
  if (protocol === 'ssh') {
    return `git@${hostname}:${repository}.git`;
  }
  return URL.format({
    protocol,
    auth,
    hostname,
    host,
    pathname: repository + '.git',
  });
};

module.exports = Storage;
<commit_msg>fix(gitFs): fix fetch arguments (#3696)<commit_after>const fs = require('fs-extra');
const { join } = require('path');
const path = require('path');
const URL = require('url');
const Git = require('simple-git/promise');
const convertHrtime = require('convert-hrtime');

class Storage {
  constructor() {
    let config = {};
    let git = null;
    let cwd = null;

    Object.assign(this, {
      initRepo,
      cleanRepo,
      getRepoStatus,
      setBaseBranch,
      branchExists,
      commitFilesToBranch,
      createBranch,
      deleteBranch,
      getAllRenovateBranches,
      getBranchCommit,
      getBranchLastCommitTime,
      getCommitMessages,
      getFile,
      getFileList,
      isBranchStale,
      mergeBranch,
    });

    // istanbul ignore next
    async function resetToBranch(branchName) {
      logger.debug(`resetToBranch(${branchName})`);
      await git.raw(['reset', '--hard']);
      await git.checkout(branchName);
      await git.raw(['reset', '--hard', 'origin/' + branchName]);
      await git.raw(['clean', '-fd']);
    }

    // istanbul ignore next
    async function cleanLocalBranches() {
      const existingBranches = (await git.raw(['branch']))
        .split('\n')
        .map(branch => branch.trim())
        .filter(branch => branch.length)
        .filter(branch => !branch.startsWith('* '));
      logger.debug({ existingBranches });
      for (const branchName of existingBranches) {
        await deleteLocalBranch(branchName);
      }
    }

    async function initRepo(args) {
      cleanRepo();
      config = { ...args };
      cwd = config.localDir;
      config.branchExists = {};
      logger.info('Initialising git repository into ' + cwd);
      const gitHead = path.join(cwd, '.git/HEAD');
      let clone = true;
      async function determineBaseBranch() {
        // see https://stackoverflow.com/a/44750379/1438522
        try {
          config.baseBranch =
            config.baseBranch ||
            (await git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']))
              .replace('refs/remotes/origin/', '')
              .trim();
        } catch (err) /* istanbul ignore next */ {
          if (
            err.message.startsWith(
              'fatal: ref refs/remotes/origin/HEAD is not a symbolic ref'
            )
          ) {
            throw new Error('empty');
          }
          throw err;
        }
      }
      // istanbul ignore if
      if (process.env.NODE_ENV !== 'test' && (await fs.exists(gitHead))) {
        try {
          git = Git(cwd).silent(true);
          await git.raw(['remote', 'set-url', 'origin', config.url]);
          const fetchStart = process.hrtime();
          await git.fetch([config.url, '--depth=2']);
          await determineBaseBranch();
          await resetToBranch(config.baseBranch);
          await cleanLocalBranches();
          await git.raw(['remote', 'prune', 'origin']);
          const fetchSeconds =
            Math.round(
              1 + 10 * convertHrtime(process.hrtime(fetchStart)).seconds
            ) / 10;
          logger.info({ fetchSeconds }, 'git fetch completed');
          clone = false;
        } catch (err) {
          logger.error({ err }, 'git fetch error');
        }
      }
      if (clone) {
        await fs.emptyDir(cwd);
        git = Git(cwd).silent(true);
        const cloneStart = process.hrtime();
        try {
          await git.clone(config.url, '.', ['--depth=2', '--no-single-branch']);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'git clone error');
          throw new Error('platform-failure');
        }
        const cloneSeconds =
          Math.round(
            1 + 10 * convertHrtime(process.hrtime(cloneStart)).seconds
          ) / 10;
        logger.info({ cloneSeconds }, 'git clone completed');
      }
      try {
        const latestCommitDate = (await git.log({ n: 1 })).latest.date;
        logger.debug({ latestCommitDate }, 'latest commit');
      } catch (err) /* istanbul ignore next */ {
        if (err.message.includes('does not have any commits yet')) {
          throw new Error('empty');
        }
        logger.warn({ err }, 'Cannot retrieve latest commit date');
      }
      // istanbul ignore if
      if (config.gitPrivateKey) {
        logger.debug('Git private key configured, but not being set');
      } else {
        logger.debug('No git private key present - commits will be unsigned');
        await git.raw(['config', 'commit.gpgsign', 'false']);
      }

      if (global.gitAuthor) {
        logger.info({ gitAuthor: global.gitAuthor }, 'Setting git author');
        try {
          await git.raw(['config', 'user.name', global.gitAuthor.name]);
          await git.raw(['config', 'user.email', global.gitAuthor.email]);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'Error setting git config');
          throw new Error('temporary-error');
        }
      }

      await determineBaseBranch();
    }

    // istanbul ignore next
    function getRepoStatus() {
      return git.status();
    }

    async function createBranch(branchName, sha) {
      logger.debug(`createBranch(${branchName})`);
      await git.reset('hard');
      await git.raw(['clean', '-fd']);
      await git.checkout(['-B', branchName, sha]);
      await git.push(['origin', branchName, '--force']);
      config.branchExists[branchName] = true;
    }

    // Return the commit SHA for a branch
    async function getBranchCommit(branchName) {
      const res = await git.revparse(['origin/' + branchName]);
      return res.trim();
    }

    async function getCommitMessages() {
      logger.debug('getCommitMessages');
      const res = await git.log({
        n: 10,
        format: { message: '%s' },
      });
      return res.all.map(commit => commit.message);
    }

    async function setBaseBranch(branchName) {
      if (branchName) {
        logger.debug(`Setting baseBranch to ${branchName}`);
        config.baseBranch = branchName;
        if (branchName !== 'master') {
          config.baseBranchSha = (await git.raw([
            'rev-parse',
            'origin/' + branchName,
          ])).trim();
        }
      }
    }

    async function getFileList(branchName) {
      const branch = branchName || config.baseBranch;
      const exists = await branchExists(branch);
      if (!exists) {
        return [];
      }
      const files = await git.raw([
        'ls-tree',
        '-r',
        '--name-only',
        'origin/' + branch,
      ]);
      // istanbul ignore if
      if (!files) {
        return [];
      }
      return files.split('\n').filter(Boolean);
    }

    async function branchExists(branchName) {
      // First check cache
      if (config.branchExists[branchName] !== undefined) {
        return config.branchExists[branchName];
      }
      try {
        await git.raw(['show-branch', 'origin/' + branchName]);
        config.branchExists[branchName] = true;
        return true;
      } catch (ex) {
        config.branchExists[branchName] = false;
        return false;
      }
    }

    async function getAllRenovateBranches(branchPrefix) {
      const branches = await git.branch(['--remotes', '--verbose']);
      return branches.all
        .map(localName)
        .filter(branchName => branchName.startsWith(branchPrefix));
    }

    async function isBranchStale(branchName) {
      const branches = await git.branch([
        '--remotes',
        '--verbose',
        '--contains',
        config.baseBranchSha || `origin/${config.baseBranch}`,
      ]);
      return !branches.all.map(localName).includes(branchName);
    }

    async function deleteLocalBranch(branchName) {
      await git.branch(['-D', branchName]);
    }

    async function deleteBranch(branchName) {
      try {
        await git.raw(['push', '--delete', 'origin', branchName]);
        logger.debug({ branchName }, 'Deleted remote branch');
      } catch (err) /* istanbul ignore next */ {
        logger.info({ branchName, err }, 'Error deleting remote branch');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
        } else {
          throw new Error('repository-changed');
        }
      }
      try {
        await deleteLocalBranch(branchName);
        // istanbul ignore next
        logger.debug({ branchName }, 'Deleted local branch');
      } catch (err) {
        logger.debug({ branchName }, 'No local branch to delete');
      }
      config.branchExists[branchName] = false;
    }

    async function mergeBranch(branchName) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + branchName]);
      await git.checkout(config.baseBranch);
      await git.merge([branchName]);
      await git.push('origin', config.baseBranch);
    }

    async function getBranchLastCommitTime(branchName) {
      try {
        const time = await git.show([
          '-s',
          '--format=%ai',
          'origin/' + branchName,
        ]);
        return new Date(Date.parse(time));
      } catch (ex) {
        return new Date();
      }
    }

    async function getFile(filePath, branchName) {
      if (branchName) {
        const exists = await branchExists(branchName);
        if (!exists) {
          logger.info({ branchName }, 'branch no longer exists - aborting');
          throw new Error('repository-changed');
        }
      }
      try {
        const content = await git.show([
          'origin/' + (branchName || config.baseBranch) + ':' + filePath,
        ]);
        return content;
      } catch (ex) {
        return null;
      }
    }

    async function commitFilesToBranch(
      branchName,
      files,
      message,
      parentBranch = config.baseBranch
    ) {
      logger.debug(`Committing files to branch ${branchName}`);
      try {
        await git.reset('hard');
        await git.raw(['clean', '-fd']);
        await git.checkout(['-B', branchName, 'origin/' + parentBranch]);
        const fileNames = [];
        const deleted = [];
        for (const file of files) {
          // istanbul ignore if
          if (file.name === '|delete|') {
            deleted.push(file.contents);
          } else {
            fileNames.push(file.name);
            await fs.outputFile(
              join(cwd, file.name),
              Buffer.from(file.contents)
            );
          }
        }
        // istanbul ignore if
        if (fileNames.length === 1 && fileNames[0] === 'renovate.json') {
          fileNames.unshift('-f');
        }
        if (fileNames.length) await git.add(fileNames);
        if (deleted.length) {
          for (const f of deleted) {
            try {
              await git.rm([f]);
            } catch (err) /* istanbul ignore next */ {
              logger.debug({ err }, 'Cannot delete ' + f);
            }
          }
        }
        await git.commit(message);
        await git.push([
          'origin',
          `${branchName}:${branchName}`,
          '--force',
          '-u',
        ]);
      } catch (err) /* istanbul ignore next */ {
        logger.debug({ err }, 'Error commiting files');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
          throw new Error('disable-gitfs');
        } else if (err.message.includes('[remote rejected]')) {
          throw new Error('repository-changed');
        }
        throw err;
      }
    }

    function cleanRepo() {}
  }
}

function localName(branchName) {
  return branchName.replace(/^origin\//, '');
}

Storage.getUrl = ({ gitFs, auth, hostname, host, repository }) => {
  let protocol = gitFs || 'https';
  // istanbul ignore if
  if (protocol.toString() === 'true') {
    protocol = 'https';
  }
  if (protocol === 'ssh') {
    return `git@${hostname}:${repository}.git`;
  }
  return URL.format({
    protocol,
    auth,
    hostname,
    host,
    pathname: repository + '.git',
  });
};

module.exports = Storage;
<|endoftext|>


<commit_before>const fs = require('fs-extra');
const { join } = require('path');
const path = require('path');
const URL = require('url');
const Git = require('simple-git/promise');
const convertHrtime = require('convert-hrtime');

class Storage {
  constructor() {
    let config = {};
    let git = null;
    let cwd = null;

    Object.assign(this, {
      initRepo,
      cleanRepo,
      getRepoStatus,
      setBaseBranch,
      branchExists,
      commitFilesToBranch,
      createBranch,
      deleteBranch,
      getAllRenovateBranches,
      getBranchCommit,
      getBranchLastCommitTime,
      getCommitMessages,
      getFile,
      getFileList,
      isBranchStale,
      mergeBranch,
    });

    // istanbul ignore next
    async function resetToBranch(branchName) {
      await git.raw(['reset', '--hard']);
      await git.checkout(branchName);
      await git.raw(['reset', '--hard', 'origin/' + branchName]);
      await git.raw(['clean', '-fd']);
    }

    // istanbul ignore next
    async function cleanLocalBranches() {
      const existingBranches = (await git.raw(['branch']))
        .split('\n')
        .map(branch => branch.trim())
        .filter(branch => branch.length)
        .filter(branch => !branch.startsWith('* '));
      logger.debug({ existingBranches });
      for (const branchName of existingBranches) {
        await deleteLocalBranch(branchName);
      }
    }

    async function initRepo(args) {
      cleanRepo();
      config = { ...args };
      cwd = config.localDir;
      logger.info('Initialising git repository into ' + cwd);
      const gitHead = path.join(cwd, '.git/HEAD');
      let clone = true;
      async function determineBaseBranch() {
        // see https://stackoverflow.com/a/44750379/1438522
        try {
          config.baseBranch =
            config.baseBranch ||
            (await git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']))
              .replace('refs/remotes/origin/', '')
              .trim();
        } catch (err) /* istanbul ignore next */ {
          if (
            err.message.startsWith(
              'fatal: ref refs/remotes/origin/HEAD is not a symbolic ref'
            )
          ) {
            throw new Error('empty');
          }
          throw err;
        }
      }
      // istanbul ignore if
      if (process.env.NODE_ENV !== 'test' && (await fs.exists(gitHead))) {
        try {
          git = Git(cwd).silent(true);
          await git.raw(['remote', 'set-url', 'origin', config.url]);
          const fetchStart = process.hrtime();
          await git.fetch(config.url, ['--depth=2', '--no-single-branch']);
          await determineBaseBranch();
          await resetToBranch(config.baseBranch);
          await cleanLocalBranches();
          await git.raw(['remote', 'prune', 'origin']);
          const fetchSeconds =
            Math.round(
              1 + 10 * convertHrtime(process.hrtime(fetchStart)).seconds
            ) / 10;
          logger.info({ fetchSeconds }, 'git fetch completed');
          clone = false;
        } catch (err) {
          logger.error({ err }, 'git fetch error');
        }
      }
      if (clone) {
        await fs.emptyDir(cwd);
        git = Git(cwd).silent(true);
        const cloneStart = process.hrtime();
        try {
          await git.clone(config.url, '.', ['--depth=2', '--no-single-branch']);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'git clone error');
          throw new Error('platform-failure');
        }
        const cloneSeconds =
          Math.round(
            1 + 10 * convertHrtime(process.hrtime(cloneStart)).seconds
          ) / 10;
        logger.info({ cloneSeconds }, 'git clone completed');
      }
      try {
        const latestCommitDate = (await git.log({ n: 1 })).latest.date;
        logger.debug({ latestCommitDate }, 'latest commit');
      } catch (err) /* istanbul ignore next */ {
        if (err.message.includes('does not have any commits yet')) {
          throw new Error('empty');
        }
        logger.warn({ err }, 'Cannot retrieve latest commit date');
      }
      // istanbul ignore if
      if (config.gitPrivateKey) {
        logger.debug('Git private key configured, but not being set');
      } else {
        logger.debug('No git private key present - commits will be unsigned');
        await git.raw(['config', 'commit.gpgsign', 'false']);
      }

      if (global.gitAuthor) {
        logger.info({ gitAuthor: global.gitAuthor }, 'Setting git author');
        try {
          await git.raw(['config', 'user.name', global.gitAuthor.name]);
          await git.raw(['config', 'user.email', global.gitAuthor.email]);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'Error setting git config');
          throw new Error('temporary-error');
        }
      }

      await determineBaseBranch();
    }

    // istanbul ignore next
    function getRepoStatus() {
      return git.status();
    }

    async function createBranch(branchName, sha) {
      await git.reset('hard');
      await git.raw(['clean', '-fd']);
      await git.checkout(['-B', branchName, sha]);
      await git.push(['origin', branchName, '--force']);
    }

    // Return the commit SHA for a branch
    async function getBranchCommit(branchName) {
      const res = await git.revparse(['origin/' + branchName]);
      return res.trim();
    }

    async function getCommitMessages() {
      logger.debug('getCommitMessages');
      const res = await git.log({
        n: 10,
        format: { message: '%s' },
      });
      return res.all.map(commit => commit.message);
    }

    async function setBaseBranch(branchName) {
      if (branchName) {
        logger.debug(`Setting baseBranch to ${branchName}`);
        config.baseBranch = branchName;
        if (branchName !== 'master') {
          config.baseBranchSha = (await git.raw([
            'rev-parse',
            'origin/' + branchName,
          ])).trim();
        }
      }
    }

    async function getFileList(branchName) {
      const branch = branchName || config.baseBranch;
      const exists = await branchExists(branch);
      if (!exists) {
        return [];
      }
      const files = await git.raw([
        'ls-tree',
        '-r',
        '--name-only',
        'origin/' + branch,
      ]);
      // istanbul ignore if
      if (!files) {
        return [];
      }
      return files.split('\n').filter(Boolean);
    }

    async function branchExists(branchName) {
      try {
        await git.raw(['show-branch', 'origin/' + branchName]);
        return true;
      } catch (ex) {
        return false;
      }
    }

    async function getAllRenovateBranches(branchPrefix) {
      const branches = await git.branch(['--remotes', '--verbose']);
      return branches.all
        .map(localName)
        .filter(branchName => branchName.startsWith(branchPrefix));
    }

    async function isBranchStale(branchName) {
      const branches = await git.branch([
        '--remotes',
        '--verbose',
        '--contains',
        config.baseBranchSha || `origin/${config.baseBranch}`,
      ]);
      return !branches.all.map(localName).includes(branchName);
    }

    async function deleteLocalBranch(branchName) {
      await git.branch(['-D', branchName]);
    }

    async function deleteBranch(branchName) {
      try {
        await git.raw(['push', '--delete', 'origin', branchName]);
        logger.debug({ branchName }, 'Deleted remote branch');
      } catch (err) /* istanbul ignore next */ {
        logger.info({ branchName, err }, 'Error deleting remote branch');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
        } else {
          throw new Error('repository-changed');
        }
      }
      try {
        await deleteLocalBranch(branchName);
        // istanbul ignore next
        logger.debug({ branchName }, 'Deleted local branch');
      } catch (err) {
        logger.debug({ branchName }, 'No local branch to delete');
      }
    }

    async function mergeBranch(branchName) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + branchName]);
      await git.checkout(config.baseBranch);
      await git.merge([branchName]);
      await git.push('origin', config.baseBranch);
    }

    async function getBranchLastCommitTime(branchName) {
      try {
        const time = await git.show([
          '-s',
          '--format=%ai',
          'origin/' + branchName,
        ]);
        return new Date(Date.parse(time));
      } catch (ex) {
        return new Date();
      }
    }

    async function getFile(filePath, branchName) {
      if (branchName) {
        const exists = await branchExists(branchName);
        if (!exists) {
          logger.info({ branchName }, 'branch no longer exists - aborting');
          throw new Error('repository-changed');
        }
      }
      try {
        const content = await git.show([
          'origin/' + (branchName || config.baseBranch) + ':' + filePath,
        ]);
        return content;
      } catch (ex) {
        return null;
      }
    }

    async function commitFilesToBranch(
      branchName,
      files,
      message,
      parentBranch = config.baseBranch
    ) {
      try {
        await git.reset('hard');
        await git.raw(['clean', '-fd']);
        await git.checkout(['-B', branchName, 'origin/' + parentBranch]);
        const fileNames = [];
        const deleted = [];
        for (const file of files) {
          // istanbul ignore if
          if (file.name === '|delete|') {
            deleted.push(file.contents);
          } else {
            fileNames.push(file.name);
            await fs.outputFile(
              join(cwd, file.name),
              Buffer.from(file.contents)
            );
          }
        }
        // istanbul ignore if
        if (fileNames.length === 1 && fileNames[0] === 'renovate.json') {
          fileNames.unshift('-f');
        }
        if (fileNames.length) await git.add(fileNames);
        if (deleted.length) await git.rm(deleted);
        await git.commit(message);
        await git.push([
          'origin',
          `${branchName}:${branchName}`,
          '--force',
          '-u',
        ]);
      } catch (err) /* istanbul ignore next */ {
        logger.debug({ err }, 'Error commiting files');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
          throw new Error('disable-gitfs');
        } else if (err.message.includes('[remote rejected]')) {
          throw new Error('repository-changed');
        }
        throw err;
      }
    }

    function cleanRepo() {}
  }
}

function localName(branchName) {
  return branchName.replace(/^origin\//, '');
}

Storage.getUrl = ({ gitFs, auth, hostname, host, repository }) => {
  let protocol = gitFs || 'https';
  // istanbul ignore if
  if (protocol.toString() === 'true') {
    protocol = 'https';
  }
  if (protocol === 'ssh') {
    return `git@${hostname}:${repository}.git`;
  }
  return URL.format({
    protocol,
    auth,
    hostname,
    host,
    pathname: repository + '.git',
  });
};

module.exports = Storage;
<commit_msg>logs: debug more gitFs<commit_after>const fs = require('fs-extra');
const { join } = require('path');
const path = require('path');
const URL = require('url');
const Git = require('simple-git/promise');
const convertHrtime = require('convert-hrtime');

class Storage {
  constructor() {
    let config = {};
    let git = null;
    let cwd = null;

    Object.assign(this, {
      initRepo,
      cleanRepo,
      getRepoStatus,
      setBaseBranch,
      branchExists,
      commitFilesToBranch,
      createBranch,
      deleteBranch,
      getAllRenovateBranches,
      getBranchCommit,
      getBranchLastCommitTime,
      getCommitMessages,
      getFile,
      getFileList,
      isBranchStale,
      mergeBranch,
    });

    // istanbul ignore next
    async function resetToBranch(branchName) {
      logger.debug(`resetToBranch(${branchName})`);
      await git.raw(['reset', '--hard']);
      await git.checkout(branchName);
      await git.raw(['reset', '--hard', 'origin/' + branchName]);
      await git.raw(['clean', '-fd']);
    }

    // istanbul ignore next
    async function cleanLocalBranches() {
      const existingBranches = (await git.raw(['branch']))
        .split('\n')
        .map(branch => branch.trim())
        .filter(branch => branch.length)
        .filter(branch => !branch.startsWith('* '));
      logger.debug({ existingBranches });
      for (const branchName of existingBranches) {
        await deleteLocalBranch(branchName);
      }
    }

    async function initRepo(args) {
      cleanRepo();
      config = { ...args };
      cwd = config.localDir;
      logger.info('Initialising git repository into ' + cwd);
      const gitHead = path.join(cwd, '.git/HEAD');
      let clone = true;
      async function determineBaseBranch() {
        // see https://stackoverflow.com/a/44750379/1438522
        try {
          config.baseBranch =
            config.baseBranch ||
            (await git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']))
              .replace('refs/remotes/origin/', '')
              .trim();
        } catch (err) /* istanbul ignore next */ {
          if (
            err.message.startsWith(
              'fatal: ref refs/remotes/origin/HEAD is not a symbolic ref'
            )
          ) {
            throw new Error('empty');
          }
          throw err;
        }
      }
      // istanbul ignore if
      if (process.env.NODE_ENV !== 'test' && (await fs.exists(gitHead))) {
        try {
          git = Git(cwd).silent(true);
          await git.raw(['remote', 'set-url', 'origin', config.url]);
          const fetchStart = process.hrtime();
          await git.fetch(config.url, ['--depth=2', '--no-single-branch']);
          await determineBaseBranch();
          await resetToBranch(config.baseBranch);
          await cleanLocalBranches();
          await git.raw(['remote', 'prune', 'origin']);
          const fetchSeconds =
            Math.round(
              1 + 10 * convertHrtime(process.hrtime(fetchStart)).seconds
            ) / 10;
          logger.info({ fetchSeconds }, 'git fetch completed');
          clone = false;
        } catch (err) {
          logger.error({ err }, 'git fetch error');
        }
      }
      if (clone) {
        await fs.emptyDir(cwd);
        git = Git(cwd).silent(true);
        const cloneStart = process.hrtime();
        try {
          await git.clone(config.url, '.', ['--depth=2', '--no-single-branch']);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'git clone error');
          throw new Error('platform-failure');
        }
        const cloneSeconds =
          Math.round(
            1 + 10 * convertHrtime(process.hrtime(cloneStart)).seconds
          ) / 10;
        logger.info({ cloneSeconds }, 'git clone completed');
      }
      try {
        const latestCommitDate = (await git.log({ n: 1 })).latest.date;
        logger.debug({ latestCommitDate }, 'latest commit');
      } catch (err) /* istanbul ignore next */ {
        if (err.message.includes('does not have any commits yet')) {
          throw new Error('empty');
        }
        logger.warn({ err }, 'Cannot retrieve latest commit date');
      }
      // istanbul ignore if
      if (config.gitPrivateKey) {
        logger.debug('Git private key configured, but not being set');
      } else {
        logger.debug('No git private key present - commits will be unsigned');
        await git.raw(['config', 'commit.gpgsign', 'false']);
      }

      if (global.gitAuthor) {
        logger.info({ gitAuthor: global.gitAuthor }, 'Setting git author');
        try {
          await git.raw(['config', 'user.name', global.gitAuthor.name]);
          await git.raw(['config', 'user.email', global.gitAuthor.email]);
        } catch (err) /* istanbul ignore next */ {
          logger.debug({ err }, 'Error setting git config');
          throw new Error('temporary-error');
        }
      }

      await determineBaseBranch();
    }

    // istanbul ignore next
    function getRepoStatus() {
      return git.status();
    }

    async function createBranch(branchName, sha) {
      logger.debug(`createBranch(${branchName})`);
      await git.reset('hard');
      await git.raw(['clean', '-fd']);
      await git.checkout(['-B', branchName, sha]);
      await git.push(['origin', branchName, '--force']);
    }

    // Return the commit SHA for a branch
    async function getBranchCommit(branchName) {
      const res = await git.revparse(['origin/' + branchName]);
      return res.trim();
    }

    async function getCommitMessages() {
      logger.debug('getCommitMessages');
      const res = await git.log({
        n: 10,
        format: { message: '%s' },
      });
      return res.all.map(commit => commit.message);
    }

    async function setBaseBranch(branchName) {
      if (branchName) {
        logger.debug(`Setting baseBranch to ${branchName}`);
        config.baseBranch = branchName;
        if (branchName !== 'master') {
          config.baseBranchSha = (await git.raw([
            'rev-parse',
            'origin/' + branchName,
          ])).trim();
        }
      }
    }

    async function getFileList(branchName) {
      const branch = branchName || config.baseBranch;
      const exists = await branchExists(branch);
      if (!exists) {
        return [];
      }
      const files = await git.raw([
        'ls-tree',
        '-r',
        '--name-only',
        'origin/' + branch,
      ]);
      // istanbul ignore if
      if (!files) {
        return [];
      }
      return files.split('\n').filter(Boolean);
    }

    async function branchExists(branchName) {
      try {
        await git.raw(['show-branch', 'origin/' + branchName]);
        return true;
      } catch (ex) {
        return false;
      }
    }

    async function getAllRenovateBranches(branchPrefix) {
      const branches = await git.branch(['--remotes', '--verbose']);
      return branches.all
        .map(localName)
        .filter(branchName => branchName.startsWith(branchPrefix));
    }

    async function isBranchStale(branchName) {
      const branches = await git.branch([
        '--remotes',
        '--verbose',
        '--contains',
        config.baseBranchSha || `origin/${config.baseBranch}`,
      ]);
      return !branches.all.map(localName).includes(branchName);
    }

    async function deleteLocalBranch(branchName) {
      await git.branch(['-D', branchName]);
    }

    async function deleteBranch(branchName) {
      try {
        await git.raw(['push', '--delete', 'origin', branchName]);
        logger.debug({ branchName }, 'Deleted remote branch');
      } catch (err) /* istanbul ignore next */ {
        logger.info({ branchName, err }, 'Error deleting remote branch');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
        } else {
          throw new Error('repository-changed');
        }
      }
      try {
        await deleteLocalBranch(branchName);
        // istanbul ignore next
        logger.debug({ branchName }, 'Deleted local branch');
      } catch (err) {
        logger.debug({ branchName }, 'No local branch to delete');
      }
    }

    async function mergeBranch(branchName) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + branchName]);
      await git.checkout(config.baseBranch);
      await git.merge([branchName]);
      await git.push('origin', config.baseBranch);
    }

    async function getBranchLastCommitTime(branchName) {
      try {
        const time = await git.show([
          '-s',
          '--format=%ai',
          'origin/' + branchName,
        ]);
        return new Date(Date.parse(time));
      } catch (ex) {
        return new Date();
      }
    }

    async function getFile(filePath, branchName) {
      if (branchName) {
        const exists = await branchExists(branchName);
        if (!exists) {
          logger.info({ branchName }, 'branch no longer exists - aborting');
          throw new Error('repository-changed');
        }
      }
      try {
        const content = await git.show([
          'origin/' + (branchName || config.baseBranch) + ':' + filePath,
        ]);
        return content;
      } catch (ex) {
        return null;
      }
    }

    async function commitFilesToBranch(
      branchName,
      files,
      message,
      parentBranch = config.baseBranch
    ) {
      logger.debug(`Committing files to branch ${branchName}`);
      try {
        await git.reset('hard');
        await git.raw(['clean', '-fd']);
        await git.checkout(['-B', branchName, 'origin/' + parentBranch]);
        const fileNames = [];
        const deleted = [];
        for (const file of files) {
          // istanbul ignore if
          if (file.name === '|delete|') {
            deleted.push(file.contents);
          } else {
            fileNames.push(file.name);
            await fs.outputFile(
              join(cwd, file.name),
              Buffer.from(file.contents)
            );
          }
        }
        // istanbul ignore if
        if (fileNames.length === 1 && fileNames[0] === 'renovate.json') {
          fileNames.unshift('-f');
        }
        if (fileNames.length) await git.add(fileNames);
        if (deleted.length) await git.rm(deleted);
        await git.commit(message);
        await git.push([
          'origin',
          `${branchName}:${branchName}`,
          '--force',
          '-u',
        ]);
      } catch (err) /* istanbul ignore next */ {
        logger.debug({ err }, 'Error commiting files');
        if (err.message.includes('.github/main.workflow')) {
          logger.warn(
            'A GitHub bug prevents gitFs + GitHub Actions. Please disable gitFs'
          );
          throw new Error('disable-gitfs');
        } else if (err.message.includes('[remote rejected]')) {
          throw new Error('repository-changed');
        }
        throw err;
      }
    }

    function cleanRepo() {}
  }
}

function localName(branchName) {
  return branchName.replace(/^origin\//, '');
}

Storage.getUrl = ({ gitFs, auth, hostname, host, repository }) => {
  let protocol = gitFs || 'https';
  // istanbul ignore if
  if (protocol.toString() === 'true') {
    protocol = 'https';
  }
  if (protocol === 'ssh') {
    return `git@${hostname}:${repository}.git`;
  }
  return URL.format({
    protocol,
    auth,
    hostname,
    host,
    pathname: repository + '.git',
  });
};

module.exports = Storage;
<|endoftext|>


<commit_before>const regExp = /(?:https?:\/\/(?:www\.)?)?((?:casemates|mediocre|mediocritee|meh|morningsave|pastadrop|sidedeal)\.com)?\/(deals|polls)\/([-\w]+)/;

module.exports = function(md) {
    var defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
        return self.renderToken(tokens, idx, options);
    };

    md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
        var openToken = tokens[idx];
        var hrefIndex = openToken.attrIndex('href');

        // Ensure we have an "href" attribute
        if (hrefIndex !== -1) {
            var href = openToken.attrs[hrefIndex][1];

            // Ensure we have an "href" attribute value
            if (href) {
                var textToken = tokens[idx + 1];

                // Ensure we have a text token and the text matches the URL pattern instead of [text](http://example.com/)
                if (textToken && textToken.content && regExp.test(textToken.content)) {
                    var matches = href.match(regExp);

                    var embedUrl = `/${matches.slice(2).join('/')}/embed`;

                    if (matches[1]) {
                        embedUrl = `https://${matches[1]}${embedUrl}`;
                    }

                    textToken.content = '';
                    tokens[idx + 2].hidden = true;

                    return `<iframe class="${matches[2]}" frameborder="0" scrolling="no" src="${embedUrl}"></iframe>`;
                }
            }
        }

        return defaultRender(tokens, idx, options, env, self);
    };
};<commit_msg>iframes for localhost links on debug<commit_after>let regExp = /(?:https?:\/\/(?:www\.)?)?((?:casemates|mediocre|mediocritee|meh|morningsave|pastadrop|sidedeal|stellacarmina)\.com)?\/(deals|polls)\/([-\w]+)/;
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'staging') {
    // Make iframes for any localhost deal/poll links on debug
    regExp = /(?:https?:\/\/)?((?:127\.0\.0\.1|localhost):\d{4})?\/(deals|polls)\/([-\w]+)/;
}

module.exports = function(md) {
    var defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
        return self.renderToken(tokens, idx, options);
    };

    md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
        var openToken = tokens[idx];
        var hrefIndex = openToken.attrIndex('href');

        // Ensure we have an "href" attribute
        if (hrefIndex !== -1) {
            var href = openToken.attrs[hrefIndex][1];

            // Ensure we have an "href" attribute value
            if (href) {
                var textToken = tokens[idx + 1];

                // Ensure we have a text token and the text matches the URL pattern instead of [text](http://example.com/)
                if (textToken && textToken.content && regExp.test(textToken.content)) {
                    var matches = href.match(regExp);

                    var embedUrl = `/${matches.slice(2).join('/')}/embed`;

                    if (matches[1]) {
                        embedUrl = `https://${matches[1]}${embedUrl}`;
                    }

                    textToken.content = '';
                    tokens[idx + 2].hidden = true;

                    return `<iframe class="${matches[2]}" frameborder="0" scrolling="no" src="${embedUrl}"></iframe>`;
                }
            }
        }

        return defaultRender(tokens, idx, options, env, self);
    };
};<|endoftext|>


<commit_before>// Copyright 2015 Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

var BufferedStream = require('../utils/bufferedStream');

/**
 * @class Scaler
 * @module PNG
 * @submodule PNGCore
 * @param {Chunk} headerChunk Header chunk of data stream
 * @constructor
 */
var Scaler = function (headerChunk) {
	this._headerChunk = headerChunk;
};

/**
 * Scaler factor for 1-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_1_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_1_TO_8_BIT = 255;

/**
 * Scaler factor for 8-to-1-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_1_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_1_BIT = 1 / 255;

/**
 * Scaler factor for 2-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_2_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_2_TO_8_BIT = 255 / 3;

/**
 * Scaler factor for 8-to-2-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_2_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_2_BIT = 3 / 255;

/**
 * Scaler factor for 4-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_4_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_4_TO_8_BIT = 255 / 15;

/**
 * Scaler factor for 8-to-4-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_4_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_4_BIT = 15 / 255;

/**
 * Scaler factor for 8-to-8-bit value conversion - identity
 *
 * @static
 * @property SCALE_FACTOR_8_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_8_BIT = 1;

/**
 * Scaler factor for 16-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_16_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_16_TO_8_BIT = 255 / 65535;

/**
 * Scaler factor for 8-to-16-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_16_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_16_BIT = 65535 / 255;

/**
 * Gets the header chunk
 *
 * @method getHeaderChunk
 * @return {Chunk}
 */
Scaler.prototype.getHeaderChunk = function () {
	return this._headerChunk;
};

/**
 * Encodes color values of an image
 *
 * @method encode
 * @param {Buffer} image
 * @return {Buffer}
 */
Scaler.prototype.encode = function (image) {
	return image;
	//TODO: Writing is currently only 8-bit
};

/**
 * Determines the scaler according to header data
 *
 * @method _determineScaler
 * @return {object}
 * @private
 */
Scaler.prototype._determineScaler = function () {

	var headerChunk = this.getHeaderChunk(),
		isIndexed, bitDepth,

		result = null;

	isIndexed = headerChunk.isColorTypeIndexedColor();
	bitDepth = headerChunk.getBitDepth();

	switch (bitDepth) {
		case 1:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_1_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 2:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_2_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 4:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_4_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 8:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_8_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 16:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_16_TO_8_BIT,
				scaler: function (v) {
					return Math.floor((v * result.scaleFactor) + 0.5);
				}
			};
			break;
	}

	return result;
};

/**
 * Decodes color values
 *
 * @method decode
 * @param {int[]} values
 * @return {Buffer}
 */
Scaler.prototype.decode = function (values) {

	var headerChunk = this.getHeaderChunk(),

		outputStream,

		scalerInfo,
		currentValues,

		samplesPerPixel = 4,
		i, len;

	outputStream = new BufferedStream(null, null, headerChunk.getImageSizeInBytes());

	scalerInfo = this._determineScaler();

	while (values.length >= samplesPerPixel) {

		currentValues = values.splice(0, samplesPerPixel);
		currentValues = currentValues.map(scalerInfo.scaler);

		for(i = 0, len = currentValues.length; i < len; i++) {
			outputStream.writeUInt8(currentValues[i]);
		}
	}

	return outputStream.toBuffer(true);
};

/**
 * Scales a value according to the header
 *
 * @method decodeValue
 * @param {number} value
 * @return {number}
 */
Scaler.prototype.decodeValue = function (value) {

	var bitDepth = this.getHeaderChunk().getBitDepth(),
		result = null;

	switch(bitDepth) {

		case 1:
			result = value * Scaler.SCALE_FACTOR_1_TO_8_BIT;
			break;

		case 2:
			result = value * Scaler.SCALE_FACTOR_2_TO_8_BIT;
			break;

		case 4:
			result = value * Scaler.SCALE_FACTOR_4_TO_8_BIT;
			break;

		case 8:
			result = value * Scaler.SCALE_FACTOR_8_TO_8_BIT;
			break;

		case 16:
			result = value * Scaler.SCALE_FACTOR_16_TO_8_BIT;
			break;
	}

	result = Math.floor(result);

	return result;
};

/**
 * Scales a value according to the header
 *
 * @method encodeValue
 * @param {number} value
 * @return {number}
 */
Scaler.prototype.encodeValue = function (value) {

	var bitDepth = this.getHeaderChunk().getBitDepth(),
		result = null;

	switch(bitDepth) {

		case 1:
			result = value * Scaler.SCALE_FACTOR_8_TO_1_BIT;
			break;

		case 2:
			result = value * Scaler.SCALE_FACTOR_8_TO_2_BIT;
			break;

		case 4:
			result = value * Scaler.SCALE_FACTOR_8_TO_4_BIT;
			break;

		case 8:
			result = value * Scaler.SCALE_FACTOR_8_TO_8_BIT;
			break;

		case 16:
			result = value * Scaler.SCALE_FACTOR_8_TO_16_BIT;
			break;
	}

	result = Math.ceil(result);

	return result;
};

module.exports = Scaler;
<commit_msg>16-bit image cannot be indexed<commit_after>// Copyright 2015 Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

var BufferedStream = require('../utils/bufferedStream');

/**
 * @class Scaler
 * @module PNG
 * @submodule PNGCore
 * @param {Chunk} headerChunk Header chunk of data stream
 * @constructor
 */
var Scaler = function (headerChunk) {
	this._headerChunk = headerChunk;
};

/**
 * Scaler factor for 1-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_1_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_1_TO_8_BIT = 255;

/**
 * Scaler factor for 8-to-1-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_1_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_1_BIT = 1 / 255;

/**
 * Scaler factor for 2-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_2_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_2_TO_8_BIT = 255 / 3;

/**
 * Scaler factor for 8-to-2-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_2_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_2_BIT = 3 / 255;

/**
 * Scaler factor for 4-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_4_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_4_TO_8_BIT = 255 / 15;

/**
 * Scaler factor for 8-to-4-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_4_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_4_BIT = 15 / 255;

/**
 * Scaler factor for 8-to-8-bit value conversion - identity
 *
 * @static
 * @property SCALE_FACTOR_8_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_8_BIT = 1;

/**
 * Scaler factor for 16-to-8-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_16_TO_8_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_16_TO_8_BIT = 255 / 65535;

/**
 * Scaler factor for 8-to-16-bit value conversion
 *
 * @static
 * @property SCALE_FACTOR_8_TO_16_BIT
 * @type {number}
 */
Scaler.SCALE_FACTOR_8_TO_16_BIT = 65535 / 255;

/**
 * Gets the header chunk
 *
 * @method getHeaderChunk
 * @return {Chunk}
 */
Scaler.prototype.getHeaderChunk = function () {
	return this._headerChunk;
};

/**
 * Encodes color values of an image
 *
 * @method encode
 * @param {Buffer} image
 * @return {Buffer}
 */
Scaler.prototype.encode = function (image) {
	return image;
	//TODO: Writing is currently only 8-bit
};

/**
 * Determines the scaler according to header data
 *
 * @method _determineScaler
 * @return {object}
 * @private
 */
Scaler.prototype._determineScaler = function () {

	var headerChunk = this.getHeaderChunk(),
		isIndexed, bitDepth,

		result = null;

	isIndexed = headerChunk.isColorTypeIndexedColor();
	bitDepth = headerChunk.getBitDepth();

	switch (bitDepth) {
		case 1:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_1_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 2:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_2_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 4:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_4_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 8:
			result = {
				scaleFactor: isIndexed ? 1 : Scaler.SCALE_FACTOR_8_TO_8_BIT,
				scaler: function (v) {
					return v * result.scaleFactor;
				}
			};
			break;

		case 16:
			result = {
				scaleFactor: Scaler.SCALE_FACTOR_16_TO_8_BIT,
				scaler: function (v) {
					return Math.floor((v * result.scaleFactor) + 0.5);
				}
			};
			break;
	}

	return result;
};

/**
 * Decodes color values
 *
 * @method decode
 * @param {int[]} values
 * @return {Buffer}
 */
Scaler.prototype.decode = function (values) {

	var headerChunk = this.getHeaderChunk(),

		outputStream,

		scalerInfo,
		currentValues,

		samplesPerPixel = 4,
		i, len;

	outputStream = new BufferedStream(null, null, headerChunk.getImageSizeInBytes());

	scalerInfo = this._determineScaler();

	while (values.length >= samplesPerPixel) {

		currentValues = values.splice(0, samplesPerPixel);
		currentValues = currentValues.map(scalerInfo.scaler);

		for(i = 0, len = currentValues.length; i < len; i++) {
			outputStream.writeUInt8(currentValues[i]);
		}
	}

	return outputStream.toBuffer(true);
};

/**
 * Scales a value according to the header
 *
 * @method decodeValue
 * @param {number} value
 * @return {number}
 */
Scaler.prototype.decodeValue = function (value) {

	var bitDepth = this.getHeaderChunk().getBitDepth(),
		result = null;

	switch(bitDepth) {

		case 1:
			result = value * Scaler.SCALE_FACTOR_1_TO_8_BIT;
			break;

		case 2:
			result = value * Scaler.SCALE_FACTOR_2_TO_8_BIT;
			break;

		case 4:
			result = value * Scaler.SCALE_FACTOR_4_TO_8_BIT;
			break;

		case 8:
			result = value * Scaler.SCALE_FACTOR_8_TO_8_BIT;
			break;

		case 16:
			result = value * Scaler.SCALE_FACTOR_16_TO_8_BIT;
			break;
	}

	result = Math.floor(result);

	return result;
};

/**
 * Scales a value according to the header
 *
 * @method encodeValue
 * @param {number} value
 * @return {number}
 */
Scaler.prototype.encodeValue = function (value) {

	var bitDepth = this.getHeaderChunk().getBitDepth(),
		result = null;

	switch(bitDepth) {

		case 1:
			result = value * Scaler.SCALE_FACTOR_8_TO_1_BIT;
			break;

		case 2:
			result = value * Scaler.SCALE_FACTOR_8_TO_2_BIT;
			break;

		case 4:
			result = value * Scaler.SCALE_FACTOR_8_TO_4_BIT;
			break;

		case 8:
			result = value * Scaler.SCALE_FACTOR_8_TO_8_BIT;
			break;

		case 16:
			result = value * Scaler.SCALE_FACTOR_8_TO_16_BIT;
			break;
	}

	result = Math.ceil(result);

	return result;
};

module.exports = Scaler;
<|endoftext|>


<commit_before>/**
 * @fileoverview Rule to flag declared but unused variables
 * @author Ilya Volodin
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

    var allowUnusedGlobals = context.options[0] === "all" ? false : true;

    var variables     = [],
        variableNames = {};

    function populateVariables(node) {
        var scope = context.getScope(),
            functionName = node && node.id && node.id.name,
            parent = context.getAncestors().pop(),

            // check for function foo(){}.bind(this)
            functionNameUsed = parent && parent.type === "MemberExpression";

        scope.variables.forEach(function(variable) {
            var index;

            //filter out global variables that we add as part of eslint or arguments variable
            if (variable.identifiers.length > 0) {

                //make sure that this variable is not already in the array
                if (!variables.some(function(storedVariable) {
                    return storedVariable.name === variable.name && storedVariable.node === variable.identifiers[0];
                })) {

                    index = variables.push({
                        name: variable.name,
                        node: variable.identifiers[0],
                        used: (variable.name === functionName) && functionNameUsed
                    });
                    if (!Object.prototype.hasOwnProperty.call(variableNames, variable.name)) {
                        variableNames[variable.name] = [index - 1];
                    } else {
                        variableNames[variable.name].push(index - 1);
                    }
                }
            }
        });
    }

    function populateGlobalVariables() {
        if (!allowUnusedGlobals) {
            populateVariables();
        }
    }

    function findVariable(name) {
        var scope = context.getScope();
        var scopeVariable = [];

        function filter(variable) {
            return variable.name === name;
        }

        while (scopeVariable.length === 0) {
            scopeVariable = scope.variables.filter(filter);
            if (scopeVariable.length === 0) {
                if (!scope.upper) {
                    return null;
                }
                scope = scope.upper;
            }
        }

        if (!Object.prototype.hasOwnProperty.call(variableNames, scopeVariable[0].name)) {
            return null;
        }
        return variableNames[scopeVariable[0].name].map(function (index) {
            return variables[index];
        }).filter(function(variable) {
            return variable.name === scopeVariable[0].name && scopeVariable[0].identifiers.some(function(identifier) {
                return variable.node === identifier;
            });
        })[0];
    }

    function isFunction(node) {
        return node && node.type && (node.type === "FunctionDeclaration" || node.type === "FunctionExpression");
    }

    function findFirstAncestorThatIsFunctionExpressionOrDeclaration(ancestors) {
        var currentAncestor;
        while (ancestors.length !== 0 && !isFunction(currentAncestor)) {
            currentAncestor = ancestors.pop();
        }
        return isFunction(currentAncestor) ? currentAncestor : undefined;
    }

    function markIgnorableUnusedVariables(usedVariable, ancestors) {
        /* When variables are declared as parameters in a FunctionExpression or
         * FunctionDeclaration, they can go unused so long as at least one
         * to the right of them is used.
         */

        // Find the FunctionExpressions and FunctionDeclarations in which this used variable
        // may be a parameter
        var ancestorFunctionNode = findFirstAncestorThatIsFunctionExpressionOrDeclaration(ancestors);
        if (ancestorFunctionNode) {
            // Get a list of the param names used in the ancestor Function
            var fnParamNames = ancestorFunctionNode.params.map(function(param){
                return param.name;
            });
            // Check if the used variable exists among those params
            var variableIndex = fnParamNames.indexOf(usedVariable.name);
            // This will be true if this variable appears in the param list of an ancestor Function Expression
            // or FunctionDeclaration.
            if (variableIndex !== -1) {
                // All params left of the used variables are ignorable.
                var ignorableVariables = fnParamNames.slice(0, variableIndex);
                // Mark them as ignorable.
                ignorableVariables.forEach(function(ignorableVariable){
                    variables.forEach(function(variable){
                        if (variable.name === ignorableVariable) {
                            variable.ignorable = true;
                        }
                    });
                });
            }
        }
    }

    return {
        "FunctionDeclaration": populateVariables,
        "FunctionExpression": populateVariables,
        "Program": populateGlobalVariables,
        "Identifier": function(node) {
            var ancestors = context.getAncestors(node);
            var parent = ancestors.pop();
            var grandparent = ancestors.pop();
            /*if it's not an assignment expression find corresponding
              *variable in the array and mark it as used
              */
            if ((parent.type !== "AssignmentExpression" || node !== parent.left) &&
                (parent.type !== "VariableDeclarator" || (parent.init && parent.init === node)) &&
                parent.type !== "FunctionDeclaration" &&
                (parent.type !== "FunctionExpression" ||
                (grandparent !== null && (grandparent.type === "CallExpression" || grandparent.type === "AssignmentExpression")))) {

                var variable = findVariable(node.name);
                if (variable) {
                    variable.used = true;
                    markIgnorableUnusedVariables(variable, ancestors);
                }

            }
        },

        "Program:after": function() {
            var unused = variables.filter(function(variable) {
                return !variable.used && !variable.ignorable;
            });
            unused.forEach(function(variable) {
                context.report(variable.node, "{{var}} is defined but never used", {"var": variable.name});
            });
        }
    };

};
<commit_msg>refactor variable name lookup into a separate function<commit_after>/**
 * @fileoverview Rule to flag declared but unused variables
 * @author Ilya Volodin
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

    var allowUnusedGlobals = context.options[0] === "all" ? false : true;

    var variables     = [],
        variableNames = {};

    function lookupVariable(variable) {
        if (!Object.prototype.hasOwnProperty.call(variableNames, variable.name)) {
            return null;
        }
        return variableNames[variable.name].map(function (index) {
            return variables[index];
        }).filter(function (candidate) {
            return candidate.name === variable.name && variable.identifiers.some(function (identifier) {
                return candidate.node === identifier;
            });
        })[0];
    }

    function populateVariables(node) {
        var scope = context.getScope(),
            functionName = node && node.id && node.id.name,
            parent = context.getAncestors().pop(),

            // check for function foo(){}.bind(this)
            functionNameUsed = parent && parent.type === "MemberExpression";

        scope.variables.forEach(function(variable) {
            var index;

            //filter out global variables that we add as part of eslint or arguments variable
            if (variable.identifiers.length > 0) {

                //make sure that this variable is not already in the array
                if (!lookupVariable(variable)) {
                    index = variables.push({
                        name: variable.name,
                        node: variable.identifiers[0],
                        used: (variable.name === functionName) && functionNameUsed
                    });
                    if (!Object.prototype.hasOwnProperty.call(variableNames, variable.name)) {
                        variableNames[variable.name] = [index - 1];
                    } else {
                        variableNames[variable.name].push(index - 1);
                    }
                }
            }
        });
    }

    function populateGlobalVariables() {
        if (!allowUnusedGlobals) {
            populateVariables();
        }
    }

    function findVariable(name) {
        var scope = context.getScope();
        var scopeVariable = [];

        function filter(variable) {
            return variable.name === name;
        }

        while (scopeVariable.length === 0) {
            scopeVariable = scope.variables.filter(filter);
            if (scopeVariable.length === 0) {
                if (!scope.upper) {
                    return null;
                }
                scope = scope.upper;
            }
        }

        return lookupVariable(scopeVariable[0]);
    }

    function isFunction(node) {
        return node && node.type && (node.type === "FunctionDeclaration" || node.type === "FunctionExpression");
    }

    function findFirstAncestorThatIsFunctionExpressionOrDeclaration(ancestors) {
        var currentAncestor;
        while (ancestors.length !== 0 && !isFunction(currentAncestor)) {
            currentAncestor = ancestors.pop();
        }
        return isFunction(currentAncestor) ? currentAncestor : undefined;
    }

    function markIgnorableUnusedVariables(usedVariable, ancestors) {
        /* When variables are declared as parameters in a FunctionExpression or
         * FunctionDeclaration, they can go unused so long as at least one
         * to the right of them is used.
         */

        // Find the FunctionExpressions and FunctionDeclarations in which this used variable
        // may be a parameter
        var ancestorFunctionNode = findFirstAncestorThatIsFunctionExpressionOrDeclaration(ancestors);
        if (ancestorFunctionNode) {
            // Get a list of the param names used in the ancestor Function
            var fnParamNames = ancestorFunctionNode.params.map(function(param){
                return param.name;
            });
            // Check if the used variable exists among those params
            var variableIndex = fnParamNames.indexOf(usedVariable.name);
            // This will be true if this variable appears in the param list of an ancestor Function Expression
            // or FunctionDeclaration.
            if (variableIndex !== -1) {
                // All params left of the used variables are ignorable.
                var ignorableVariables = fnParamNames.slice(0, variableIndex);
                // Mark them as ignorable.
                ignorableVariables.forEach(function(ignorableVariable){
                    variables.forEach(function(variable){
                        if (variable.name === ignorableVariable) {
                            variable.ignorable = true;
                        }
                    });
                });
            }
        }
    }

    return {
        "FunctionDeclaration": populateVariables,
        "FunctionExpression": populateVariables,
        "Program": populateGlobalVariables,
        "Identifier": function(node) {
            var ancestors = context.getAncestors(node);
            var parent = ancestors.pop();
            var grandparent = ancestors.pop();
            /*if it's not an assignment expression find corresponding
              *variable in the array and mark it as used
              */
            if ((parent.type !== "AssignmentExpression" || node !== parent.left) &&
                (parent.type !== "VariableDeclarator" || (parent.init && parent.init === node)) &&
                parent.type !== "FunctionDeclaration" &&
                (parent.type !== "FunctionExpression" ||
                (grandparent !== null && (grandparent.type === "CallExpression" || grandparent.type === "AssignmentExpression")))) {

                var variable = findVariable(node.name);
                if (variable) {
                    variable.used = true;
                    markIgnorableUnusedVariables(variable, ancestors);
                }

            }
        },

        "Program:after": function() {
            var unused = variables.filter(function(variable) {
                return !variable.used && !variable.ignorable;
            });
            unused.forEach(function(variable) {
                context.report(variable.node, "{{var}} is defined but never used", {"var": variable.name});
            });
        }
    };

};
<|endoftext|>


<commit_before>'use strict';

var scorecard = require('./scorecard.json');
var jp = require('jsonpath')

module.exports = {
    get: function (id) {
        return jp.query(scorecard, '$..[?(@.id=='+id+')]');
    },
    all: function () {
        return scorecard;
    }
};
<commit_msg>Update scorecardsRepository.js<commit_after>'use strict';

var scorecards = require('./scorecards.json');
var jp = require('jsonpath')

module.exports = {
    get: function (id) {
        return jp.query(scorecards, '$..[?(@.id=='+id+')]');
    },
    all: function () {
        return scorecards;
    }
};
<|endoftext|>


<commit_before>import Serializer from './'
import DefaultSerializer from './default'
import castValue from './cast_value'
import * as keys from '../common/keys'
import * as errors from '../common/errors'
import * as methods from '../common/methods'

const { UnsupportedError, NotAcceptableError, BadRequestError,
  nativeErrors } = errors

/**
 * Reroute the publicly accessed methods of the serializer to an underlying
 * serializer matching the context. For internal use.
 */
export default class SerializerSingleton extends Serializer {

  constructor (dependencies) {
    super()

    const { recordTypes, adapter, serializers } = dependencies
    const ids = []
    const types = serializers ? serializers.reduce((types, serializer) => {
      let { type } = serializer

      if (typeof type !== 'function')
        throw new TypeError(`The serializer must be a function or class.`)

      const CustomSerializer = Serializer.prototype
        .isPrototypeOf(type.prototype) ? type : type(Serializer)

      if (!Serializer.prototype.isPrototypeOf(CustomSerializer.prototype))
        throw new TypeError(`The serializer must be a class that extends ` +
          `Serializer.`)

      const { id } = CustomSerializer

      if (!id)
        throw new Error(`The serializer must have a static property ` +
          `named "id".`)

      ids.push(id)

      types[id] = new CustomSerializer({
        options: serializer.options || {},
        methods, keys, errors, recordTypes, adapter, castValue
      })

      return types
    }, {}) : {}

    Object.defineProperties(this, {

      // Internal property to keep instances of serializers.
      types: { value: types },

      // Internal instance of the default serializer.
      defaultSerializer: {
        value: new DefaultSerializer({ recordTypes, errors })
      },

      // Array of IDs ordered by priority.
      ids: { value: ids }

    })

    assignSerializerProxy.call(this)
  }

}

const inputMethods = new Set([ 'parseCreate', 'parseUpdate' ])

// Assign the proxy methods on top of the base methods.
function assignSerializerProxy () {
  const prototype = Object.getPrototypeOf(this)
  const methods = Object.getOwnPropertyNames(Serializer.prototype)
    .filter(name => name !== 'constructor')

  Object.assign(prototype, methods.reduce((proxy, method) => {
    const isInput = inputMethods.has(method)

    proxy[method] = proxyMethod.bind(this, {
      method, isInput,
      NoopError: isInput ?
        UnsupportedError : NotAcceptableError
    })

    return proxy
  }, {}))
}

// Internal proxy method to call serializer method based on context.
function proxyMethod (options, context, ...args) {
  const { types, defaultSerializer } = this
  const { NoopError, isInput, method } = options
  const format = context.request[isInput ?
    'serializerInput' : 'serializerOutput']
  let serializer

  // If a serializer is specified, use it.
  if (format in types) serializer = types[format]

  // Fall back to default serializer.
  else if (!format) serializer = defaultSerializer

  // Fail if no serializer was found.
  else throw new NoopError(`The serializer for "${format}" is unrecognized.`)

  try {
    return Promise.resolve(serializer[method](context, ...args))
  }
  catch (e) {
    let error = e

    // Only in the special case of input methods, it may be more appropriate to
    // throw a BadRequestError.
    if (nativeErrors.has(error.constructor) && isInput)
      error = new BadRequestError(`The request is malformed.`)

    return Promise.reject(error)
  }
}
<commit_msg>cleanup nooperror in serializer singleton<commit_after>import Serializer from './'
import DefaultSerializer from './default'
import castValue from './cast_value'
import * as keys from '../common/keys'
import * as errors from '../common/errors'
import * as methods from '../common/methods'

const { UnsupportedError, NotAcceptableError, BadRequestError,
  nativeErrors } = errors

/**
 * Reroute the publicly accessed methods of the serializer to an underlying
 * serializer matching the context. For internal use.
 */
export default class SerializerSingleton extends Serializer {

  constructor (dependencies) {
    super()

    const { recordTypes, adapter, serializers } = dependencies
    const ids = []
    const types = serializers ? serializers.reduce((types, serializer) => {
      let { type } = serializer

      if (typeof type !== 'function')
        throw new TypeError(`The serializer must be a function or class.`)

      const CustomSerializer = Serializer.prototype
        .isPrototypeOf(type.prototype) ? type : type(Serializer)

      if (!Serializer.prototype.isPrototypeOf(CustomSerializer.prototype))
        throw new TypeError(`The serializer must be a class that extends ` +
          `Serializer.`)

      const { id } = CustomSerializer

      if (!id)
        throw new Error(`The serializer must have a static property ` +
          `named "id".`)

      ids.push(id)

      types[id] = new CustomSerializer({
        options: serializer.options || {},
        methods, keys, errors, recordTypes, adapter, castValue
      })

      return types
    }, {}) : {}

    Object.defineProperties(this, {

      // Internal property to keep instances of serializers.
      types: { value: types },

      // Internal instance of the default serializer.
      defaultSerializer: {
        value: new DefaultSerializer({ recordTypes, errors })
      },

      // Array of IDs ordered by priority.
      ids: { value: ids }

    })

    assignSerializerProxy.call(this)
  }

}

const inputMethods = new Set([ 'parseCreate', 'parseUpdate' ])

// Assign the proxy methods on top of the base methods.
function assignSerializerProxy () {
  const prototype = Object.getPrototypeOf(this)
  const methods = Object.getOwnPropertyNames(Serializer.prototype)
    .filter(name => name !== 'constructor')

  Object.assign(prototype, methods.reduce((proxy, method) => {
    const isInput = inputMethods.has(method)

    proxy[method] = proxyMethod.bind(this, { method, isInput })

    return proxy
  }, {}))
}

// Internal proxy method to call serializer method based on context.
function proxyMethod (options, context, ...args) {
  const { types, defaultSerializer } = this
  const { isInput, method } = options
  const format = context.request[isInput ?
    'serializerInput' : 'serializerOutput']
  let serializer

  // If a serializer is specified, use it.
  if (format in types) serializer = types[format]

  // Fall back to default serializer.
  else if (!format) serializer = defaultSerializer

  // Fail if no serializer was found.
  else {
    const NoopError = isInput ?
      UnsupportedError : NotAcceptableError

    throw new NoopError(`The serializer for "${format}" is unrecognized.`)
  }

  try {
    return Promise.resolve(serializer[method](context, ...args))
  }
  catch (e) {
    let error = e

    // Only in the special case of input methods, it may be more appropriate to
    // throw a BadRequestError.
    if (nativeErrors.has(error.constructor) && isInput)
      error = new BadRequestError(`The request is malformed.`)

    return Promise.reject(error)
  }
}
<|endoftext|>