Creates file resources based on another file resource

@param {String} arg0.source - The path to the source files
@param {String} arg0.destination - The base path of the generated files
@param {Boolean} arg0.onlyFiles - Whether to only generate files
@param {Array} arg0.exclude - The paths to exclude from generated files
@param {RegExp} arg0.variableRegex - The pattern for indentifying template variables
@param {Object} data - The data to pass to the templates when generating
function scaffold(
  {
    source = '',
    destination = 'destination',
    onlyFiles = false,
    exclude = [],
    variableRegex = /\{\{\s?([A-Za-z0-9-]+_?[A-Za-z0-9-]+)+\s?\}\}/g,
  } = {},
  data = {},
) {
  const cwd = process.cwd();

  const thisSource = pathIsAbsolute(source) ? source : path.join(cwd, source);
  const thisDestination = pathIsAbsolute(destination) ? destination : path.join(cwd, destination);
  const thisOnlyFiles = onlyFiles;
  const thisExclude = exclude;
  const thisVariableRegex = variableRegex;


  try {
    const listOfFiles = fs.readdirSync(thisSource);
    const destinationExists = fs.existsSync(thisDestination);

    if (!destinationExists) {
      fs.mkdirSync(thisDestination);
    }

    listOfFiles.forEach((file) => {
      const thisFile = path.join(thisSource, file);
      const stat = fs.statSync(thisFile);
      const destinationFilename = getProcessedPath(file, data);
      const destinationPath = path.join(thisDestination, destinationFilename);

      if (stat && stat.isDirectory() && !thisOnlyFiles && !thisExclude.includes(file)) {
        scaffold({
          source: thisFile,
          destination: destinationPath,
          onlyFiles: thisOnlyFiles,
          exclude: thisExclude,
          variableRegex: thisVariableRegex,
        }, data);
      } else if (!stat.isDirectory()) {
        const template = fs.readFileSync(thisFile, 'utf-8');
        const filledTemplate = getRenderedTemplate(template, data, thisVariableRegex);

        fs.writeFileSync(destinationPath, filledTemplate);
      }
    });
  } catch (e) {
    throw new Error(e);
  }
}