<commit_before>import * as moment from 'moment';

import { ChangelogConfig, CurrentVersionLoader } from '../types/config';
import { VersionString, VersionQuery } from '../types/version';
import {
  Changelog,
  ChangeType,
  Change,
  ChangelogVersion,
  ChangelogVersionMetadata,
} from '../types/changelog';

import {
  addChange as addUnreleasedDirChange,
  read as readUnreleasedFiles,
  removeDir as deleteUnreleasedFiles,
} from './unreleased-dir';
import { getNextVersion } from './changelog-helpers';
import {
  addChange as addChangelogChange,
  read as readChangelog,
  write as writeChangelog,
} from './changelog-file';
import { sort, isInRange } from './version';

interface NewVersion {
  version: VersionString;
  metadata: ChangelogVersionMetadata;
  changes: ChangelogVersion;
}

const loadCurrentVersion = async (
  loaders: CurrentVersionLoader,
  releasedVersions: Changelog
) => {
  if (Array.isArray(loaders)) {
    let version;
    let i = 0;
    while (!version && loaders[i]) {
      version = await loaders[i](releasedVersions);
      i += 1;
    }
    return version;
  } else {
    return await loaders(releasedVersions);
  }
};

export const addChange = (
  changeType: ChangeType,
  change: Change,
  { unreleasedDir = '' } = {}
) =>
  unreleasedDir
    ? addUnreleasedDirChange(changeType, change, unreleasedDir)
    : addChangelogChange(changeType, change);

export const bumpVersion = async (
  currentVersionLoader: CurrentVersionLoader,
  config: ChangelogConfig = {}
) => {
  const {
    unreleased: changelogUnreleased,
    ...released,
  } = await readChangelog();

  // TODO: Combine?
  const changes = config.unreleasedDir
    ? await readUnreleasedFiles(config.unreleasedDir)
    : changelogUnreleased;

  if (changes && Object.keys(changes).length) {
    const currentVersion = await loadCurrentVersion(
      currentVersionLoader,
      released
    );

    const version = getNextVersion(changes, currentVersion, config);
    if (version) {
      const metadata = {
        date: moment().format('YYYY-MM-DD'),
      };

      await writeChangelog({
        [version]: {
          metadata,
          ...changes,
        },
        ...released,
      });

      if (config.unreleasedDir) {
        await deleteUnreleasedFiles(config.unreleasedDir);
      }

      const newVersion: NewVersion = {
        version,
        metadata,
        changes,
      };

      return newVersion;
    }
  }

  return undefined;
};

const getVersionRangeChanges = (
  changelog: Changelog,
  from: VersionString,
  to: VersionString
) => {
  const versions = Object.keys(changelog);
  const versionRange = versions.reduce((acc: Changelog, v) => {
    if (isInRange(v, from, to)) {
      acc[v] = changelog[v];
    }
    return acc;
  }, {});
  return Object.keys(versionRange).length ? versionRange : undefined;
};

export const getUnreleasedChanges = async (dir: string) => {
  if (dir) return readUnreleasedFiles(dir);
  else {
    const { unreleased } = await readChangelog();
    return unreleased;
  }
};

export const getChanges = async (
  version?: VersionQuery,
  { unreleasedDir = '' } = {}
): Promise<Changelog | ChangelogVersion | undefined> => {
  if (version && version === 'unreleased') {
    return getUnreleasedChanges(unreleasedDir);
  }<commit_msg>Fix failing test<commit_after>import * as moment from 'moment';

import { ChangelogConfig, CurrentVersionLoader } from '../types/config';
import { VersionString, VersionQuery } from '../types/version';
import {
  Changelog,
  ChangeType,
  Change,
  ChangelogVersion,
  ChangelogVersionMetadata,
} from '../types/changelog';

import {
  addChange as addUnreleasedDirChange,
  read as readUnreleasedFiles,
  removeDir as deleteUnreleasedFiles,
} from './unreleased-dir';
import { getNextVersion } from './changelog-helpers';
import {
  addChange as addChangelogChange,
  read as readChangelog,
  write as writeChangelog,
} from './changelog-file';
import { sort, isInRange } from './version';

interface NewVersion {
  version: VersionString;
  metadata: ChangelogVersionMetadata;
  changes: ChangelogVersion;
}

const loadCurrentVersion = async (
  loaders: CurrentVersionLoader,
  releasedVersions: Changelog
) => {
  if (Array.isArray(loaders)) {
    let version;
    let i = 0;
    while (!version && loaders[i]) {
      version = await loaders[i](releasedVersions);
      i += 1;
    }
    return version;
  } else {
    return await loaders(releasedVersions);
  }
};

export const addChange = (
  changeType: ChangeType,
  change: Change,
  { unreleasedDir = '' } = {}
) =>
  unreleasedDir
    ? addUnreleasedDirChange(changeType, change, unreleasedDir)
    : addChangelogChange(changeType, change);

export const bumpVersion = async (
  currentVersionLoader: CurrentVersionLoader,
  config: ChangelogConfig = {}
) => {
  const {
    unreleased: changelogUnreleased,
    ...released,
  } = await readChangelog();

  // TODO: Combine?
  const changes = config.unreleasedDir
    ? await readUnreleasedFiles(config.unreleasedDir)
    : changelogUnreleased;

  if (changes && Object.keys(changes).length) {
    const currentVersion = await loadCurrentVersion(
      currentVersionLoader,
      released
    );

    const version = getNextVersion(changes, currentVersion, config);
    if (version) {
      const metadata = {
        date: moment().format('YYYY-MM-DD'),
      };

      await writeChangelog({
        [version]: {
          metadata,
          ...changes,
        },
        ...released,
      });

      if (config.unreleasedDir) {
        await deleteUnreleasedFiles(config.unreleasedDir);
      }

      const newVersion: NewVersion = {
        version,
        metadata,
        changes,
      };

      return newVersion;
    }
  }

  return undefined;
};

const getVersionRangeChanges = (
  changelog: Changelog,
  from: VersionString,
  to: VersionString
) => {
  const versions = sort(Object.keys(changelog));
  const versionRange = versions.reduce((acc: Changelog, v) => {
    if (isInRange(v, from, to)) {
      acc[v] = changelog[v];
    }
    return acc;
  }, {});
  return Object.keys(versionRange).length ? versionRange : undefined;
};

export const getUnreleasedChanges = async (dir: string) => {
  if (dir) return readUnreleasedFiles(dir);
  else {
    const { unreleased } = await readChangelog();
    return unreleased;
  }
};

export const getChanges = async (
  version?: VersionQuery,
  { unreleasedDir = '' } = {}
): Promise<Changelog | ChangelogVersion | undefined> => {
  if (version && version === 'unreleased') {
    return getUnreleasedChanges(unreleasedDir);
  }
{'fraction_non_alphanumeric': 0.11873390882932, 'fraction_numerical': 0.0006057852491291837, 'mean_word_length': 3.2966818477553677, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6848930', 'n_tokens_mistral': 2041, 'n_tokens_neox': 1981, 'n_words': 460}