Swap-Aggregator-Subgraph/node_modules/fs-jetpack/lib/inspect.js
2022-07-03 07:27:35 +05:30

194 lines
4.9 KiB
JavaScript

"use strict";
const crypto = require("crypto");
const pathUtil = require("path");
const fs = require("./utils/fs");
const validate = require("./utils/validate");
const supportedChecksumAlgorithms = ["md5", "sha1", "sha256", "sha512"];
const symlinkOptions = ["report", "follow"];
const validateInput = (methodName, path, options) => {
const methodSignature = `${methodName}(path, [options])`;
validate.argument(methodSignature, "path", path, ["string"]);
validate.options(methodSignature, "options", options, {
checksum: ["string"],
mode: ["boolean"],
times: ["boolean"],
absolutePath: ["boolean"],
symlinks: ["string"]
});
if (
options &&
options.checksum !== undefined &&
supportedChecksumAlgorithms.indexOf(options.checksum) === -1
) {
throw new Error(
`Argument "options.checksum" passed to ${methodSignature} must have one of values: ${supportedChecksumAlgorithms.join(
", "
)}`
);
}
if (
options &&
options.symlinks !== undefined &&
symlinkOptions.indexOf(options.symlinks) === -1
) {
throw new Error(
`Argument "options.symlinks" passed to ${methodSignature} must have one of values: ${symlinkOptions.join(
", "
)}`
);
}
};
const createInspectObj = (path, options, stat) => {
const obj = {};
obj.name = pathUtil.basename(path);
if (stat.isFile()) {
obj.type = "file";
obj.size = stat.size;
} else if (stat.isDirectory()) {
obj.type = "dir";
} else if (stat.isSymbolicLink()) {
obj.type = "symlink";
} else {
obj.type = "other";
}
if (options.mode) {
obj.mode = stat.mode;
}
if (options.times) {
obj.accessTime = stat.atime;
obj.modifyTime = stat.mtime;
obj.changeTime = stat.ctime;
}
if (options.absolutePath) {
obj.absolutePath = path;
}
return obj;
};
// ---------------------------------------------------------
// Sync
// ---------------------------------------------------------
const fileChecksum = (path, algo) => {
const hash = crypto.createHash(algo);
const data = fs.readFileSync(path);
hash.update(data);
return hash.digest("hex");
};
const addExtraFieldsSync = (path, inspectObj, options) => {
if (inspectObj.type === "file" && options.checksum) {
inspectObj[options.checksum] = fileChecksum(path, options.checksum);
} else if (inspectObj.type === "symlink") {
inspectObj.pointsAt = fs.readlinkSync(path);
}
};
const inspectSync = (path, options) => {
let statOperation = fs.lstatSync;
let stat;
const opts = options || {};
if (opts.symlinks === "follow") {
statOperation = fs.statSync;
}
try {
stat = statOperation(path);
} catch (err) {
// Detection if path exists
if (err.code === "ENOENT") {
// Doesn't exist. Return undefined instead of throwing.
return undefined;
}
throw err;
}
const inspectObj = createInspectObj(path, opts, stat);
addExtraFieldsSync(path, inspectObj, opts);
return inspectObj;
};
// ---------------------------------------------------------
// Async
// ---------------------------------------------------------
const fileChecksumAsync = (path, algo) => {
return new Promise((resolve, reject) => {
const hash = crypto.createHash(algo);
const s = fs.createReadStream(path);
s.on("data", data => {
hash.update(data);
});
s.on("end", () => {
resolve(hash.digest("hex"));
});
s.on("error", reject);
});
};
const addExtraFieldsAsync = (path, inspectObj, options) => {
if (inspectObj.type === "file" && options.checksum) {
return fileChecksumAsync(path, options.checksum).then(checksum => {
inspectObj[options.checksum] = checksum;
return inspectObj;
});
} else if (inspectObj.type === "symlink") {
return fs.readlink(path).then(linkPath => {
inspectObj.pointsAt = linkPath;
return inspectObj;
});
}
return Promise.resolve(inspectObj);
};
const inspectAsync = (path, options) => {
return new Promise((resolve, reject) => {
let statOperation = fs.lstat;
const opts = options || {};
if (opts.symlinks === "follow") {
statOperation = fs.stat;
}
statOperation(path)
.then(stat => {
const inspectObj = createInspectObj(path, opts, stat);
addExtraFieldsAsync(path, inspectObj, opts).then(resolve, reject);
})
.catch(err => {
// Detection if path exists
if (err.code === "ENOENT") {
// Doesn't exist. Return undefined instead of throwing.
resolve(undefined);
} else {
reject(err);
}
});
});
};
// ---------------------------------------------------------
// API
// ---------------------------------------------------------
exports.supportedChecksumAlgorithms = supportedChecksumAlgorithms;
exports.symlinkOptions = symlinkOptions;
exports.validateInput = validateInput;
exports.sync = inspectSync;
exports.async = inspectAsync;