@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
167 lines • 6.08 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAllFiles = getAllFiles;
exports.allRFiles = allRFiles;
exports.allRFilesFrom = allRFilesFrom;
exports.writeTableAsCsv = writeTableAsCsv;
exports.readLineByLine = readLineByLine;
exports.readLineByLineSync = readLineByLineSync;
exports.getParentDirectory = getParentDirectory;
const fs_1 = __importStar(require("fs"));
const path_1 = __importDefault(require("path"));
const log_1 = require("./log");
const n_readlines_1 = __importDefault(require("n-readlines"));
/**
* Retrieves all files in the given directory recursively
* @param dir - Directory path to start the search from
* @param suffix - Suffix of the files to be retrieved
* Based on {@link https://stackoverflow.com/a/45130990}
*/
async function* getAllFiles(dir, suffix = /.*/) {
const entries = await fs_1.promises.readdir(dir, { withFileTypes: true, recursive: false });
for (const subEntries of entries) {
const res = path_1.default.resolve(dir, subEntries.name);
if (subEntries.isDirectory()) {
yield* getAllFiles(res, suffix);
}
else if (suffix.test(subEntries.name)) {
yield res;
}
}
}
const rFileRegex = /\.[rR]$/;
/**
* Retrieves all R files in a given directory (asynchronously)
*
*
* @param input - directory-path to start the search from, can be a file as well. Will just return the file then.
* @param limit - limit the number of files to be retrieved
*
* @returns Number of files processed (normally ≤ `limit`, is ≥ `limit` if limit was reached).
* Will be `1`, if `input` is an R file (and `0` if it isn't).
*
* @see getAllFiles
*/
async function* allRFiles(input, limit = Number.MAX_VALUE) {
let count = 0;
if (fs_1.default.statSync(input).isFile()) {
if (rFileRegex.test(input)) {
yield { request: 'file', content: input };
return 1;
}
log_1.log.warn(`Input ${input} is not an R file`);
return 0;
}
for await (const f of getAllFiles(input, rFileRegex)) {
if (++count > limit) {
return count;
}
yield { request: 'file', content: f };
}
return count;
}
/**
* Retrieves all R files in a given set of directories and files (asynchronously)
*
* @param inputs - Files or directories to validate for R-files
* @param limit - Limit the number of files to be retrieved
* @returns Number of files processed (≤ limit)
*
* @see allRFiles
*/
async function* allRFilesFrom(inputs, limit) {
limit ??= Number.MAX_VALUE;
if (inputs.length === 0) {
log_1.log.info('No inputs given, nothing to do');
return 0;
}
let count = 0;
for (const input of inputs) {
count += yield* allRFiles(input, limit - count);
}
return count;
}
function writeTableAsCsv(table, file, sep = ',', newline = '\n') {
const csv = [table.header.join(sep), ...table.rows.map(row => row.join(sep))].join(newline);
fs_1.default.writeFileSync(file, csv);
}
/**
* Reads a file line by line and calls the given function for each line.
* The `lineNumber` starts at `0`.
*
* See {@link readLineByLineSync} for a synchronous version.
*/
async function readLineByLine(filePath, onLine) {
const reader = new n_readlines_1.default(filePath);
let line;
let counter = 0;
// eslint-disable-next-line no-cond-assign
while (line = reader.next()) {
await onLine(line, counter++);
}
}
/**
* Reads a file line by line and calls the given function for each line.
* The `lineNumber` starts at `0`.
*
* See {@link readLineByLine} for an asynchronous version.
*/
function readLineByLineSync(filePath, onLine) {
if (!fs_1.default.existsSync(filePath)) {
log_1.log.warn(`File ${filePath} does not exist`);
return;
}
const reader = new n_readlines_1.default(filePath);
let line;
let counter = 0;
// eslint-disable-next-line no-cond-assign
while (line = reader.next()) {
onLine(line, counter++);
}
}
/**
* Chops off the last part of the given directory path after a path separator, essentially returning the path's parent directory.
* If an absolute path is passed, the returned path is also absolute.
* @param directory - The directory whose parent to return
*/
function getParentDirectory(directory) {
// apparently this is somehow the best way to do it in node, what
return directory.split(path_1.default.sep).slice(0, -1).join(path_1.default.sep);
}
//# sourceMappingURL=files.js.map