Home Manual Reference Source Test Repository

lib/file-system.js

import Promise from 'bluebird';
import path from 'path';
import _ from 'lodash';
import glob from 'glob';
import Constants from './constants';
import File from './file';

export default class FileSystem {
  constructor({ config, renderer } = {}) {
    /**
     * @type {Config}
     * @private
     */
    this._config = config;

    /**
     * @type {Renderer}
     * @private
     */
    this._renderer = renderer;

    /**
     * All files found in our source path.
     * Key is the full path to the file, value is the actual File object.
     * @type {Object.<string, File>}
     */
    this.files = Object.create(null);
  }

  async loadIntoMemory() {
    const configPathSource = this._config.get('path.source');

    // Create an array of patterns that we should ignore when reading the source
    // files of the Reptar site from disk.
    // This primarily includes the Constants.ConfigFilename file as well as
    // every path directory that isn't our source path.
    const globIgnorePatterns = [
      Constants.ConfigFilename,
      'package.json',
      'node_modules',
    ]
      .concat(
        _.values(this._config.get('path')).filter(
          pathVal => pathVal !== configPathSource
        )
      )
      .map(ignorePath => `**/${ignorePath}/**`);

    // Read all files from disk and get their file paths.
    const files = await Promise.fromCallback(cb => {
      glob(
        `${configPathSource}/**/*`,
        {
          // Do not match directories, only files.
          nodir: true,
          // Array of glob patterns to exclude from matching.
          ignore: globIgnorePatterns,
          // Follow symlinks.
          follow: true,
        },
        cb
      );
    });

    const ignorePatterns = this._config.get('ignore');

    const filePromises = files
      // Filter out files that match our array of ignored patterns.
      .filter(
        rawPath =>
          // If one of our ignore patterns matches then we filter the file out.
          // This is done by asserting that .some returns false, that none pass.
          ignorePatterns.some(ignoreFn => ignoreFn(rawPath)) === false
      )
      .map(rawPath => {
        // Correct the filePath created by glob to be compatible with Windows.
        // Known issue in node-glob
        // https://github.com/isaacs/node-glob/pull/263.
        const filePath = path.normalize(rawPath.replace(/\//g, path.sep));

        const sourceFile = new File(filePath, {
          config: this._config,
          renderer: this._renderer,
        });
        this.files[sourceFile.id] = sourceFile;

        return sourceFile.update();
      });

    return Promise.all(filePromises);
  }
}