|
- const fs = require('fs-extra');
- const { join, dirname, basename, extname } = require('path');
- const { toSystemPath, toAppPath, toSiteUrl, getUniqFile, parseTemplate } = require('../core/path');
- const { map } = require('../core/async');
-
- module.exports = {
-
- download: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.download: path is required.'));
- let filename = this.parseOptional(options.filename, 'string', basename(path));
-
- if (fs.existsSync(path)) {
- this.res.download(path, filename);
- this.noOutput = true;
- } else {
- this.res.sendStatus(404);
- }
- },
-
- exists: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.exists: path is required.'));
-
- if (await isFile(path)) {
- if (options.then) {
- await this.exec(options.then, true);
- }
- return true;
- } else {
- if (options.else) {
- await this.exec(options.else, true);
- }
- return false;
- }
- },
-
- direxists: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.direxists: path is required.'));
-
- if (await isDirectory(path)) {
- if (options.then) {
- await this.exec(options.then, true);
- }
- return true;
- } else {
- if (options.else) {
- await this.exec(options.else, true);
- }
- return false;
- }
- },
-
- createdir: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.createdir: path is required.'));
-
- await fs.ensureDir(path);
-
- return toAppPath(path);
- },
-
- removedir: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.removedir: path is required.'));
-
- await fs.remove(path);
-
- return toAppPath(path);
- },
-
- emptydir: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.emptydir: path is required.'));
-
- await fs.emptyDir(path)
-
- return toAppPath(path);
- },
-
- move: async function(options) {
- let from = toSystemPath(this.parseRequired(options.from, 'string', 'fs.move: from is required.'));
- let to = toSystemPath(this.parseRequired(options.to, 'string', 'fs.move: to is required.'));
- let overwrite = this.parseOptional(options.overwrite, 'boolean', false);
- let createdir = this.parseOptional(options.createdir, 'boolean', true);
-
- if (!fs.existsSync(to)) {
- if (createdir) {
- await fs.ensureDir(to);
- } else {
- throw new Error(`Destination path doesn't exists.`);
- }
- }
-
- to = join(to, basename(from));
-
- if (!overwrite) {
- to = getUniqFile(to);
- }
-
- await fs.move(from, to, { overwrite: true });
-
- return toAppPath(to);
- },
-
- rename: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.rename: path is required.'));
- let template = this.parseRequired(options.template, 'string', 'fs.rename: template is required.');
- let overwrite = this.parseOptional(options.overwrite, 'boolean', false);
- let to = parseTemplate(path, template);
-
- if (!overwrite && fs.existsSync(to)) {
- throw new Error(`fs.rename: file "${to}" already exists.`);
- }
-
- await fs.rename(path, to);
-
- return toAppPath(to);
- },
-
- copy: async function(options) {
- let from = toSystemPath(this.parseRequired(options.from, 'string', 'fs.copy: from is required.'));
- let to = toSystemPath(this.parseRequired(options.to, 'string', 'fs.copy: to is required.'));
- let overwrite = this.parseOptional(options.overwrite, 'boolean', false);
- let createdir = this.parseOptional(options.createdir, 'boolean', true);
-
- if (!fs.existsSync(to)) {
- if (createdir) {
- await fs.ensureDir(to);
- } else {
- throw new Error(`Destination path doesn't exist.`);
- }
- }
-
- to = join(to, basename(from));
-
- if (!overwrite && fs.existsSync(to)) {
- to = getUniqFile(to);
- }
-
- await fs.copy(from, to);
-
- return toAppPath(to);
- },
-
- remove: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.remove: path is required.'));
-
- await fs.unlink(path);
-
- return true;
- },
-
- dir: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.dir: path is required.'));
- let allowedExtensions = this.parseOptional(options.allowedExtensions, 'string', '');
- let showHidden = this.parseOptional(options.showHidden, 'boolean', false);
- let includeFolders = this.parseOptional(options.includeFolders, 'boolean', false);
- let folderSize = this.parseOptional(options.folderSize, 'string', 'none');
- let concurrency = this.parseOptional(options.concurrency, 'number', 4);
-
- folderSize = ['none', 'files', 'recursive'].includes(folderSize) ? folderSize : 'none';
- allowedExtensions = allowedExtensions ? allowedExtensions.split(/\s*,\s*/).map(ext => lowercase(ext[0] == '.' ? ext : '.' + ext)) : [];
-
- let files = await fs.readdir(path, { withFileTypes: true });
-
- files = files.filter(entry => {
- if (!includeFolders && entry.isDirectory()) return false;
- if (!showHidden && entry.name[0] == '.') return false;
- if (allowedExtensions.length && entry.isFile() && !allowedExtensions.includes(lowercase(extname(entry.name)))) return false;
- return entry.isFile() || entry.isDirectory();
- });
-
- // Fast parallel map
- return map(files, async (entry) => {
- let curr = join(path, entry.name);
- let stat = await fs.stat(curr);
-
- if (folderSize != 'none' && entry.isDirectory()) {
- stat.size = await calcSize(curr, folderSize == 'recursive', concurrency);
- }
-
- return {
- type: entry.isFile() ? 'file' : 'dir',
- name: entry.name,
- folder: toAppPath(dirname(curr)),
- basename: basename(curr, extname(curr)),
- extension: extname(curr),
- path: toAppPath(curr),
- url: toSiteUrl(curr),
- size: stat.size,
- created: stat.ctime,
- accessed: stat.atime,
- modified: stat.mtime
- };
- }, concurrency);
- },
-
- stat: async function(options) {
- let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.stat: path is required.'));
- let folderSize = this.parseOptional(options.folderSize, 'string', 'none');
- let concurrency = this.parseOptional(options.concurrency, 'number', 4);
-
- folderSize = ['none', 'files', 'recursive'].includes(folderSize) ? folderSize : 'none';
-
- let stat = await fs.stat(path);
-
- if (folderSize != 'none' && stat.isDirectory()) {
- stat.size = await calcSize(path, folderSize == 'recursive', concurrency);
- }
-
- return {
- type: stat.isFile() ? 'file' : 'dir',
- name: basename(path),
- folder: toAppPath(dirname(path)),
- basename: basename(path, extname(path)),
- extension: extname(path),
- path: toAppPath(path),
- url: toSiteUrl(path),
- size: stat.size,
- created: stat.ctime,
- accessed: stat.atime,
- modified: stat.mtime
- };
- },
-
- };
-
- function lowercase(str) {
- return str.toLowerCase();
- }
-
- async function calcSize(folder, recursive, concurrency) {
- let entries = await fs.readdir(folder);
-
- return map(entries, async (entry) => {
- let stat = await fs.stat(join(folder, entry));
-
- if (stat.isDirectory() && recursive) {
- return calcSize(join(folder, entry), recursive, concurrency);
- }
-
- return stat.size;
- }, concurrency).then(arr => arr.reduce((size, curr) => size + curr, 0));
- };
-
- async function isFile(path) {
- try {
- let stats = await fs.stat(path);
- return stats.isFile();
- } catch (err) {
- return false;
- }
- }
-
- async function isDirectory(path) {
- try {
- let stats = await fs.stat(path);
- return stats.isDirectory();
- } catch (err) {
- return false;
- }
- }
|