1
0
Fork 0
freesewing/scripts/fs.mjs

275 lines
6.6 KiB
JavaScript
Raw Permalink Normal View History

2025-04-21 18:20:52 +02:00
/*
* Various helper methods to handle file system access
*/
import fs from 'fs'
import path from 'path'
import { glob } from 'glob'
2025-04-26 15:29:25 +02:00
import mustache from 'mustache'
2025-04-21 18:20:52 +02:00
/**
* Re-export these
*/
2025-04-26 15:29:25 +02:00
export { fs, path, glob, mustache }
2025-04-21 18:20:52 +02:00
/**
* The monorepo root folder
*/
export const root = path.resolve(path.basename(import.meta.url), '..')
/**
* Copies a file
*
* @param {arrau} src - Source file
* @param {array} dst - Destination file
* @param {object} options - Options for the fs.cp call in NodeJS
*
*/
export async function cp(src, dst, options = {}) {
if (!Array.isArray(src)) src = [src]
if (!Array.isArray(dst)) dst = [dst]
try {
await fs.promises.cp(path.resolve(root, ...src), path.resolve(root, ...dst), options)
} catch (err) {
return false
}
return true
}
/**
* Removes a file
*
* @param {array} file - Path to the file to remove
* @param {object} options - Options for NodeJS' rm method
*
*/
export async function rm(file, options = { force: true }) {
if (!Array.isArray(file)) file = [file]
try {
await fs.promises.rm(path.resolve(root, ...file), options)
} catch (err) {
return false
}
return true
}
/**
* Reads a folder from disk with an optional glob pattern
*
* @param {string} (relative) path to the file to read
* @param {funtion} onError - a method to call on error
*
* @return {string} File contents, or false in case of trouble
*/
export async function globDir(
folderPath, // The (relative) path to the folder
pattern = '**/*' // Glob pattern to match
) {
if (!Array.isArray(folderPath)) folderPath = [folderPath]
let list = []
try {
list = await glob(path.resolve(root, ...folderPath) + '/' + pattern)
} catch (err) {
if (err) console.log(err)
return false
}
return list
}
/**
* Creates a directory/folder
*
* @param {string} dirPath - (relative) path to the folder to create
* @param {funtion} onError - a method to call on error
*
* @return {string} File contents, or false in case of trouble
*/
export async function mkdir(
dirPath, // The (relative) path to the folder to create
onError // Method to run on error
) {
if (!Array.isArray(dirPath)) dirPath = [dirPath]
let dir
try {
dir = path.resolve(root, ...dirPath)
await fs.promises.mkdir(dir, { recursive: true })
} catch (err) {
if (onError) onError(err)
return false
}
return true
}
/**
* Reads a file from disk
*
* @param {string} (relative) path to the file to read
* @param {funtion} onError - a method to call on error
*
* @return {string} File contents, or false in case of trouble
*/
export async function readFile(
filePath, // The (relative) path to the file
onError, // Method to run on error
binary = false
) {
if (!Array.isArray(filePath)) filePath = [filePath]
let content, file
try {
file = path.resolve(root, ...filePath)
content = await fs.promises.readFile(file, binary ? undefined : 'utf-8')
} catch (err) {
if (onError) onError(err)
return false
}
return content
}
/**
* Reads a JSON file from disk and parses it
*
* @param {string} path - (relative) path to the file to read
* @param {string} onError - a string to log on error rather than the default
*
* @return {string} File contents, or false in case of trouble
*/
export async function readJsonFile(
filePath, // The (relative) path to the file
onError // Method to run on error
) {
if (!Array.isArray(filePath)) filePath = [filePath]
let content
try {
content = await readFile(path.join(root, ...filePath), onError, true)
content = JSON.parse(content)
} catch (err) {
if (onError) onError(err)
return false
}
return content
}
2025-04-26 15:29:25 +02:00
/**
* Templates out a file with mustache
*
* @param {array} from - The source template file
* @param {array} to - The destination file
* @param {object] data - Substitutions for the template
*/
export async function templateOut(from, to, data) {
if (!Array.isArray(from)) from = [from]
if (!Array.isArray(to)) to = [to]
try {
const src = await readFile(from)
await writeFile(to, mustache.render(src, data))
} catch (err) {
console.log(err)
}
return true
}
2025-04-21 18:20:52 +02:00
/**
* Writes a file to disk
*
* @param {string} filePath - (relative) path to the file to write
* @param {string} data - the data to write to disk
* @param {function} log - a logger instance (or false)
* @param {octal} mode - a mode for chmod
*
* @return {bool} true of success, false in case of trouble
*/
export async function writeFile(
filePath, // The (relative) path to the file
data, // The data to write to disk
log = false,
mode = 0o666
) {
if (!Array.isArray(filePath)) filePath = [filePath]
let file
try {
file = path.resolve(root, ...filePath)
await fs.promises.mkdir(path.dirname(file), { recursive: true })
await fs.promises.writeFile(file, data)
await fs.promises.chmod(file, mode)
} catch (err) {
if (log) log.warn(err, `Failed to write file: ${file}`)
else console.log(`Failed to write file: ${file}`)
return false
}
return true
}
/**
* Writes a JSON file to disk
*
* @param {string} filePath - (relative) path to the file to write
* @param {string} data - the data to write to disk as a Javascript object
*
* @return {bool} true of success, false in case of trouble
*/
export async function writeJsonFile(filePath, data, log, mode) {
return await writeFile(filePath, JSON.stringify(data, null, 2), log, mode)
}
/**
* Reads the contents of a directory (non-recursive)
*
* @param {string} dirPath - (relative) path to the directory to read
* @param {funtion} onError - a method to call on error
*/
export async function readDirectory(dirPath, onError) {
if (!Array.isArray(dirPath)) dirPath = [dirPath]
let files
try {
const dir = path.resolve(root, ...dirPath)
files = await fs.promises.readdir(dir)
} catch (err) {
if (onError) onError(err)
return false
}
return files
}
/**
* Copies a folder recursively
*
* @param {string} srcDir - The source folder to copy
* @param {string} dstDir - The destination folder
*/
export async function copyFolderRecursively(srcDir, dstDir) {
/*
* Ensure target folder exists
*/
await mkdir(dstDir)
/*
* Glob all files to copy
* Generate relative from and to arrays
*/
const files = (await globDir(srcDir, '**/*'))
.sort()
.map((target) => target.split(root).pop().slice(1).split('/'))
.map((target) => ({
from: target,
to: [...dstDir, ...target.slice(srcDir.length)],
}))
/*
* Copy files, create folders
*/
for (const op of files) {
const stat = fs.statSync(path.join(root, ...op.from))
if (stat.isDirectory()) await mkdir(op.to)
else await cp(op.from, op.to)
}
}