Home Manual Reference Source

src/services/common/tempFiles.js

const path = require('path');
const fs = require('fs-extra');
const { provider } = require('jimple');
/**
 * A utility service to read, write and delete temporary files.
 */
class TempFiles {
  /**
   * Class constructor.
   * @param {Object}    info                  The application `package.json`, necessary to get the
   *                                          module name and build the path of the temp directory.
   * @param {PathUtils} pathUtils             To Register the temp directory location and build the
   *                                          paths to the files.
   * @param {string}    [directory='.tmp']    The name of the temp directory.
   * @param {string}    [locationName='temp'] The name that will be used to register the temp
   *                                          directory path as a location on the `pathUtils`
   *                                          service.
   */
  constructor(info, pathUtils, directory = '.tmp', locationName = 'temp') {
    /**
     * A local reference for the `pathUtils` service.
     * @type {PathUtils}
     */
    this.pathUtils = pathUtils;
    /**
     * The location name for the temp directory path on the `pathUtils` service.
     * @type {string}
     */
    this.locationName = locationName;

    this.pathUtils.addLocation(locationName, path.join(
      'node_modules',
      info.name,
      directory
    ));
  }
  /**
   * Generate a path for the temp directory.
   * @param {Array} rest The rest of the components that will be added to the path after the one
   *                     for the temp directory.
   * @return {string}
   */
  path(...rest) {
    return this.pathUtils.joinFrom(this.locationName, ...rest);
  }
  /**
   * Read a file from the temp directory.
   * @param {string} filepath           The path to the file.
   * @param {string} [encoding='utf-8'] The text encoding in which the file should be read.
   * @return {Promise<string,Error>}
   */
  read(filepath, encoding = 'utf-8') {
    return this.ensureDirectory()
    .then(() => fs.readFile(this.path(filepath), encoding));
  }
  /**
   * Read a file from the temp directory, sync version.
   * @param {string} filepath           The path to the file.
   * @param {string} [encoding='utf-8'] The text encoding in which the file should be read.
   * @return {string}
   * @throws {Error} If the file can't be read.
   */
  readSync(filepath, encoding = 'utf-8') {
    this.ensureDirectorySync();
    return fs.readFileSync(this.path(filepath), encoding);
  }
  /**
   * Write a file on the temp directory.
   * @param {string} filepath The path to the file.
   * @param {string} data     The contents of the file.
   * @return {Promise<string,Error>} On success, the promise resolves with the absolute path to
   *                                 the file.
   */
  write(filepath, data) {
    const tempFilepath = this.path(filepath);
    return this.ensureDirectory()
    .then(() => fs.writeFile(tempFilepath, data))
    .then(() => tempFilepath);
  }
  /**
   * Write a file on the temp directory, sync version.
   * @param {string} filepath The path to the file.
   * @param {string} data     The contents of the file.
   * @return {string} The absolute path to the file.
   * @throws {Error} If the method couldn't write on the file.
   */
  writeSync(filepath, data) {
    this.ensureDirectorySync();
    const tempFilepath = this.path(filepath);
    fs.writeFileSync(tempFilepath, data);
    return tempFilepath;
  }
  /**
   * Delete a file from the temp directory.
   * @param {string} filepath The path to the file.
   * @return {Promise<string,Error>} On success, the promise resolves with the absolute path to
   *                                 the file.
   */
  delete(filepath) {
    const tempFilepath = this.path(filepath);
    return this.ensureDirectory()
    .then(() => fs.unlink(tempFilepath))
    .then(() => tempFilepath);
  }
  /**
   * Delete a file from the temp directory, sync version.
   * @param {string} filepath The path to the file.
   * @return {string} The absolute path to the file.
   * @throws {Error} If the method couldn't delete the file.
   */
  deleteSync(filepath) {
    this.ensureDirectorySync();
    const tempFilepath = this.path(filepath);
    fs.unlinkSync(tempFilepath);
    return tempFilepath;
  }
  /**
   * Ensure that the temp directory exists
   * @return {Promise<undefined,Error>}
   */
  ensureDirectory() {
    return fs.ensureDir(this.pathUtils.getLocation(this.locationName));
  }
  /**
   * Ensure that the temp directory exists, sync version.
   * @throws {Error} If the directory can't be created.
   */
  ensureDirectorySync() {
    return fs.ensureDirSync(this.pathUtils.getLocation(this.locationName));
  }
}
/**
 * Generates a {@link Provider} with a custom directory and/or location name for the temp directory.
 * You can also specify a custom service name, which can be helpfull if you want to create multiple
 * services for temp files.
 * @example
 * // Generate the provider
 * const provider = tempFilesCustom('.my-files', 'myTempFiles', 'myTempFiles');
 * // Register it on the container
 * container.register(provider);
 * // Get access to the service instance
 * const myTempFiles = container.get('myTempFiles');
 * @param {string} [directory]               The name of the temp directory.
 * @param {string} [locationName]            The name that will be used to register the temp
 *                                           directory path as a location on the `pathUtils`
 *                                           service.
 * @param {string} [serviceName='tempFiles'] The name that will be used to register the
 *                                           {@link TempFiles} instance as a service.
 * @return {Provider}
 */
const tempFilesCustom = (directory, locationName, serviceName = 'tempFiles') => provider((app) => {
  app.set(serviceName, () => new TempFiles(
    app.get('info'),
    app.get('pathUtils'),
    directory,
    locationName
  ));
});
/**
 * The service provider that once registered on the app container will set an instance of
 * {@link TempFiles} as the `tempFiles` service.
 * @example
 * // Register it on the container
 * container.register(tempFiles);
 * // Getting access to the service instance
 * const tempFiles = container.get('tempFiles');
 * @type {Provider}
 */
const tempFiles = tempFilesCustom();

module.exports = {
  TempFiles,
  tempFilesCustom,
  tempFiles,
};