<commit_before>import { chmodSync, constants, exists, existsSync, unlinkSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import { readFile, writeFile } from 'jsonfile';

export interface Dotfile {
  exists: () => Promise<boolean>;
  read: () => Promise<any>; // tslint:disable-line: no-any
  write: <T>(obj: T) => Promise<T>;
  delete: () => Promise<void>;
}

/**
 * Read, Write, or Exist Dotfiles
 * @param  {__dirname} dirname The relative dirname
 * @param  {string} name The dotfile name
 * @return {Dotfile} `delete`, `exists`, `read` and `write` Promises
 */
export default (dirname: string, name: string): Dotfile => {
  if (!name || !dirname) {
    throw new Error('Both name and dirname parameters are required');
  }

  if (dirname[0] === '~') {
    dirname = homedir();
  }
  const filename = `.${name}`;
  const fullpath = join(dirname, filename);

  return {
    exists: () => new Promise<boolean>((resolve) => resolve(existsSync(fullpath))),
    read: () => new Promise<any>( // tslint:disable-line: no-any
      (resolve, reject) => readFile(fullpath, (err, obj) => err ? reject(err) : resolve(obj)),
    ),
    write: <T>(obj: T) => new Promise<T>(
      (resolve, reject) => writeFile(fullpath, obj,
        (err) => {
          if (err) {
            reject(err);
          } else {
            // if a platform is not Windows(include x64)
            if ('win32' !== process.platform) {
              // same as chmod 600
              chmodSync(fullpath, constants.S_IRUSR | constants.S_IWUSR);
            }
            resolve(obj);
          }
        },
      ),
    ),
    delete: () => new Promise<void>((resolve) => {
      unlinkSync(fullpath);
      resolve();
    }),
  };
};<commit_msg>better interface + cleanup redundant type definitions<commit_after>import { chmodSync, constants, exists, existsSync, unlinkSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import { readFile, writeFile } from 'jsonfile';

export interface Dotfile {
  exists: () => Promise<boolean>;
  read: <T>() => Promise<T>;
  write: <T>(obj: T) => Promise<T>;
  delete: () => Promise<void>;
}

/**
 * Read, Write, or Exist Dotfiles
 * @param  {__dirname} dirname The relative dirname
 * @param  {string} name The dotfile name
 * @return {Dotfile} `delete`, `exists`, `read` and `write` Promises
 */
export default (dirname: string, name: string): Dotfile => {
  if (!name || !dirname) {
    throw new Error('Both name and dirname parameters are required');
  }

  if (dirname[0] === '~') {
    dirname = homedir();
  }
  const filename = `.${name}`;
  const fullpath = join(dirname, filename);

  return {
    exists: () => new Promise((resolve) => resolve(existsSync(fullpath))),
    read: () => new Promise( // tslint:disable-line: no-any
      (resolve, reject) => readFile(fullpath, (err, obj) => err ? reject(err) : resolve(obj)),
    ),
    write: (obj) => new Promise(
      (resolve, reject) => writeFile(fullpath, obj,
        (err) => {
          if (err) {
            reject(err);
          } else {
            // if a platform is not Windows(include x64)
            if ('win32' !== process.platform) {
              // same as chmod 600
              chmodSync(fullpath, constants.S_IRUSR | constants.S_IWUSR);
            }
            resolve(obj);
          }
        },
      ),
    ),
    delete: () => new Promise((resolve) => {
      unlinkSync(fullpath);
      resolve();
    }),
  };
};
{'fraction_non_alphanumeric': 0.1676750216076059, 'fraction_numerical': 0.004609622587150677, 'mean_word_length': 2.6975505857294997, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 49, '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': '2584779', 'n_tokens_mistral': 1110, 'n_tokens_neox': 1084, 'n_words': 295}