@fontoxml/fontoxml-development-tools
Version:
Development tools for Fonto.
115 lines (105 loc) • 2.79 kB
JavaScript
import fs from 'fs';
import path from 'path';
/**
* @typedef Stats
*
* @property {string} path
* @property {boolean} symlink
* @property {boolean} file
* @property {boolean} directory
* @property {number} size
* @property {Date} accessed
* @property {Date} modified
* @property {Date} changed
* @property {Date} created
*/
/**
* @param {string} fileOrDirectoryPath
* @param {boolean} indiscriminateOfSymlinks
*
* @return {Stats}
*/
function getStatForPath(fileOrDirectoryPath, indiscriminateOfSymlinks) {
/* istanbul ignore next: No symlinks in this package, so we won't test this for now */
const statMethodName = indiscriminateOfSymlinks ? 'statSync' : 'lstatSync';
const stat = fs[statMethodName](fileOrDirectoryPath);
return {
path: fileOrDirectoryPath,
symlink: stat.isSymbolicLink()
? path.resolve(path.dirname(stat.path), fs.readlinkSync(stat.path))
: false,
file: stat.isFile(),
directory: stat.isDirectory(),
size: stat.size,
accessed: stat.atime,
modified: stat.mtime,
changed: stat.ctime,
created: stat.birthtime,
};
}
/**
* @param {string} dir
* @param {boolean} indiscriminateOfSymlinks
*
* @return {Stats[]}
*/
function getAllStatsInPath(dir, indiscriminateOfSymlinks) {
return fs
.readdirSync(dir)
.map((file) => path.resolve(dir, file))
.map((fileOrDirectoryPath) => {
try {
return getStatForPath(
fileOrDirectoryPath,
indiscriminateOfSymlinks
);
} catch (_error) {
// Do nothing
}
return null;
})
.filter((result) => !!result);
}
/**
* @param {string} cwd
* @param {string|string[]|RegExp} matcher
*
* @return {string|null}
*/
export function getFileMatchInDirectoryAncestrySync(cwd, matcher) {
const rootDir = path.parse(cwd).root;
const matchingStats = getAllStatsInPath(cwd, false).filter((stat) => {
if (!stat.file) {
return false;
}
const basename = path.basename(stat.path);
return typeof matcher === 'string'
? basename === matcher
: Array.isArray(matcher)
? matcher.includes(basename)
: basename.match(matcher);
});
// If we have a match, return it.
if (matchingStats.length) {
return matchingStats[0].path;
}
// If we have reached the root, we cannot look any further.
if (cwd === rootDir) {
return null;
}
// Try to find a match in the parent directory.
return getFileMatchInDirectoryAncestrySync(path.dirname(cwd), matcher);
}
/**
* @param {string} cwd
* @param {string|string[]|RegExp} matcher
*
* @return {string|null}
*/
export default function getParentDirectoryContainingFileSync(cwd, matcher) {
const matchingFilename = getFileMatchInDirectoryAncestrySync(cwd, matcher);
if (!matchingFilename) {
return null;
}
return path.dirname(matchingFilename);
}