Swig-template default extension - node.js

Can I set what extension will be? For example:
.html or .htm
And can I set custom extension for some of layouts? Like:
.xml

Swig doesn't care/know about extensions. You could try writing a custom loader to do this for you. Just copy the filesystem loader and have it check if a path given doesn't include an extension, and if it does, use your default.
var fs = require('fs'),
path = require('path');
module.exports = function (basepath, encoding) {
var ret = {};
encoding = encoding || 'utf8';
basepath = (basepath) ? path.normalize(basepath) : null;
ret.resolve = function (to, from) {
if (basepath) {
from = basepath;
} else {
from = (from) ? path.dirname(from) : process.cwd();
}
return path.resolve(from, to);
};
ret.load = function (identifier, cb) {
if (!fs || (cb && !fs.readFile) || !fs.readFileSync) {
throw new Error('Unable to find file ' + identifier + ' because there is no filesystem to read from.');
}
// Start of added code...
var extension = path.extname(identifier);
if (!extension) {
// Set this to whatever you want as a default
// If the extension exists, like 'foo.xml', it won't add the '.html'
identifier += '.html';
}
// End of added code
identifier = ret.resolve(identifier);
if (cb) {
fs.readFile(identifier, encoding, cb);
return;
}
return fs.readFileSync(identifier, encoding);
};
return ret;
};

Related

Saving blobs as a single webm file

I'm recording the users screen via webrtc, and then posting video blobs every x seconds using MediaStreamRecorder. On the server side I have an action set up in sails which saves the blob as a webm file.
The problem is that I can't get it to append the data, and create one large webm file. When it appends the file size increases like expected, so the data is appending, but when I go to play the file it'll either play the first second, not play at all, or play but not show the video.
It would be possible to merge the files with ffmpeg, but I'd rather avoid this if at all possible.
Here's the code on the client:
'use strict';
// Polyfill in Firefox.
// See https://blog.mozilla.org/webrtc/getdisplaymedia-now-available-in-adapter-js/
if (typeof adapter != 'undefined' && adapter.browserDetails.browser == 'firefox') {
adapter.browserShim.shimGetDisplayMedia(window, 'screen');
}
io.socket.post('/processvideo', function(resData) {
console.log("Response: " + resData);
});
function handleSuccess(stream) {
const video = document.querySelector('video');
video.srcObject = stream;
var mediaRecorder = new MediaStreamRecorder(stream);
mediaRecorder.mimeType = 'video/webm';
mediaRecorder.ondataavailable = function (blob) {
console.log("Sending Data");
//var rawIO = io.socket._raw;
//rawIO.emit('some:event', "using native socket.io");
io.socket.post('/processvideo', {"vidblob": blob}, function(resData) {
console.log("Response: " + resData);
});
};
mediaRecorder.start(3000);
}
function handleError(error) {
errorMsg(`getDisplayMedia error: ${error.name}`, error);
}
function errorMsg(msg, error) {
const errorElement = document.querySelector('#errorMsg');
errorElement.innerHTML += `<p>${msg}</p>`;
if (typeof error !== 'undefined') {
console.error(error);
}
}
if ('getDisplayMedia' in navigator) {
navigator.getDisplayMedia({video: true})
.then(handleSuccess)
.catch(handleError);
} else {
errorMsg('getDisplayMedia is not supported');
}
Code on the server:
module.exports = async function processVideo (req, res) {
var fs = require('fs'),
path = require('path'),
upload_dir = './assets/media/uploads',
output_dir = './assets/media/outputs',
temp_dir = './assets/media/temp';
var params = req.allParams();
if(req.isSocket && req.method === 'POST') {
_upload(params.vidblob, "test.webm");
return res.send("Hi There");
}
else {
return res.send("Unknown Error");
}
function _upload(file_content, file_name) {
var fileRootName = file_name.split('.').shift(),
fileExtension = file_name.split('.').pop(),
filePathBase = upload_dir + '/',
fileRootNameWithBase = filePathBase + fileRootName,
filePath = fileRootNameWithBase + '.' + fileExtension,
fileID = 2;
/* Save all of the files as different files. */
/*
while (fs.existsSync(filePath)) {
filePath = fileRootNameWithBase + fileID + '.' + fileExtension;
fileID += 1;
}
fs.writeFileSync(filePath, file_content);
*/
/* Appends the binary data like you'd expect, but it's not playable. */
fs.appendFileSync(upload_dir + '/' + 'test.file', file_content);
}
}
Any help would be greatly appreciated!
I decided this would be difficult to develop, and wouldn't really fit the projects requirements. So I decided to build an electron app. Just posting this so I can resolve the question.

fs-extra: Copy files without overwrite

I am using copy method of fs-extra to copy files from a source to destination. My use case is to create a copy of the file with a name like if a file of the same name exists in the destination. The copy method of fs-extra module overwrites the destination file.
You could try something like this:
const fs = require('fs-extra');
async function copy(src, dest) {
try {
await fs.copy(src, dest, { overwrite: false, errorOnExist: true });
return true;
} catch (error) {
if (error.message.includes('already exists')) {
return false;
}
throw error;
}
}
async function copyWithoutOverwrite(src, dest, maxAttempts) {
try {
if (!await copy(src, dest)); {
for (let i = 1; i <= maxAttempts; i++) {
if (await copy(src, `${dest}_copy${i}`)) {
return;
}
}
}
} catch (error) {
console.error(error);
}
}
const src = '/tmp/testfile';
const dest = '/tmp/mynewfile';
const maxAttempts = 10;
copyWithoutOverwrite(src, dest, maxAttempts);
So basically you need to implement custom copy procedure, that you can interrupt and alter at any moment. fs-jetpack does this very well.
const pathUtil = require("path");
const jetpack = require("fs-jetpack");
const src = jetpack.cwd("path/to/source/folder");
const dst = jetpack.cwd("path/to/destination/folder");
const findUnusedPath = path => {
const pathDir = pathUtil.dirname(path);
const extension = pathUtil.extname(path);
const fileName = pathUtil.basename(path, extension);
const pathCandidate = pathUtil.join(pathDir, `${fileName}-duplicate${extension}`);
if (dst.exists(pathCandidate)) {
// Will just add "-duplicate-duplicate-duplicate..." to name
// of the file until finds unused name.
return findUnusedPath(pathCandidate);
} else {
return pathCandidate;
}
};
// Iterate over all files in source directory and manually decide
// where to put them in destination directory.
src.find().forEach(filePath => {
const content = src.read(filePath, "buffer");
let destPath = filePath;
if (dst.exists(destPath)) {
destPath = findUnusedPath(destPath);
}
dst.write(destPath, content);
});
Here using file read/write instead of copy, because it's faster in this particular case. Copy needs to check first what the path is: directory or file. If we already know it is a file there is no need for this extra work.

nodeschool learnyounode node.js module FILTER LS exercise

Below is the exercise 5 of nodeschool learnyounode module
Create a program that prints a list of files in a given directory, filtered by he extension of the files. You will be provided a directory name as the first agument to your program (e.g. /path/to/dir/) and a file extension to filter by as the second argument.
For example, if you get 'txt' as the second argument then you will need to filter the list to only files that end with .txt.
The list of files should be printed to the console, one file per line and have to use asynchronous I/O.
var fs = require('fs');
var path = require('path');
var mydir = process.argv[2];
var ext1 = process.argv[3]
fs.readdir(mydir, function(err, files){
if(err){
throw err
}
//console.log(files);
files.forEach(function(filename){
var ext = path.extname(filename);
if(ext == ext1){
console.log(filename);
}
});
});
When i run this i got the correct output, But when i verify output using learnyounode actual result not matching with expected result
Dont know where i went wrong. Can someone give me the solution plz???
Here's the official solution:
var fs = require('fs')
var path = require('path')
fs.readdir(process.argv[2], function (err, list) {
list.forEach(function (file) {
if (path.extname(file) === '.' + process.argv[3])
console.log(file)
})
})
Your problem is just a typo. You're doing this:
if(ext == ext){ // you're comparing the same variable
console.log(filename);
}
, but you should be doing this:
if(ext === ext1){ // try to use '==='
console.log(filename);
}
Other thing: they're not considering the . of .txt in the input, so you have to append this in your variable ext1 because .extname(file) returns the extention with the .:
var ext1 = '.' + process.argv[3];
You can try this code to solve this exercise :
var fs = require('fs');
function endsWith(str, suffix) {
var s = str.slice(str.length - suffix.length - 1);
if (s == "." + suffix)
return true;
else
return false;
};
fs.readdir(process.argv[2], function (err, list) {
if (process.argv[3]) {
for (var i = 0; i < list.length; i++) {
if (endsWith(list[i], process.argv[3]))
console.log(list[i]);
}
}
});
Here is what I came up with:
var fs = require('fs');
var filePath = process.argv[2];
var fileType = '.' + process.argv[3];
fs.readdir(filePath, function(err, list) {
for(var i=0; i<list.length; i++){
if (list[i].match(fileType)) {
console.log(list[i]);
}
}
});
Heres what I came up with, if you want other solutions to problem:
var fs = require('fs');
var path = process.argv[2]; //first argument
var extension = process.argv[3]; //second argument
var re = new RegExp("."+extension, "g"); //a regexp that matches every string that begins with a dot and is followed by the extension, i.e. .txt
fs.readdir(path, function callback(err, list){ //read the directory
if (!err) { //if no errors occur run next funtion
list.forEach(function(val) { //take the list and check every value with the statement below
if(re.test(val)) { //if the .test() rexexp-function does not match it will return a false, if it does it will return true
console.log(val); //if it matches console log the value
}
});
}
});
The only thing missing in your code is the concatenation of '.' before the file extension type.
var extension = '.'+ process.argv[3];
You can then do the comparison and printing.
thats how i solved it
var fs = require('fs');
const path = require("path")
var dir = process.argv[2],
ext = "."+process.argv[3];
function borer(callback){
fs.readdir(dir,function(err,list){
if(err){
console.log(err)
}else{
var row = list.filter((a)=>{
var regexp = new RegExp(ext+"$","ig")
if( a.search(regexp) > -1 ){
callback(a)
}
})
}
})
}
function print(f){
console.log(f)
}
borer(print)
The solution given uses the path module from Node JS package. The solution below doesn't use path, instead relies on simple deconstruction of given filename and using the parts needed.
-Import fs module
var fs = require('fs');
-Extract the path and ext name required from cmd line
let filePath = process.argv[2];
let extName = process.argv[3];
-Use (readdir) method to read the contents of a directory. The names of files inside the directory will be returned in the form of an array.
fs.readdir(filePath, 'utf-8', function(err, data) {
if (err) throw err;
data.forEach(element => {
-Take each element and split it into filename and extension name
let temp = element.split('.');
let tempSplit = temp[1];
if(tempSplit === extName) {
console.log(temp[0] + '.' + temp[1]);
}
});
Whole code for reference:
var fs = require('fs');
let filePath = process.argv[2];
let extName = process.argv[3];
fs.readdir(filePath, 'utf-8', function(err, data) {
if (err) throw err;
data.forEach(element => {
let temp = element.split('.');
let tempSplit = temp[1];
if(tempSplit === extName) {
console.log(temp[0] + '.' + temp[1]);
}
});

Load node.js module from string in memory

How would I require() a file if I had the file's contents as a string in memory, without writing it out to disk? Here's an example:
// Load the file as a string
var strFileContents = fs.readFileSync( "./myUnalteredModule.js", 'utf8' );
// Do some stuff to the files contents
strFileContents[532] = '6';
// Load it as a node module (how would I do this?)
var loadedModule = require( doMagic(strFileContents) );
function requireFromString(src, filename) {
var Module = module.constructor;
var m = new Module();
m._compile(src, filename);
return m.exports;
}
console.log(requireFromString('module.exports = { test: 1}', ''));
look at _compile, _extensions and _load in module.js
The question is already answered by Andrey, but I ran into a shortcoming that I had to solve and which might be of interest for others.
I wanted the module in the memorized string to be able to load other modules via require, but the module path was broken with the above solution (so e.g. needle wasn't found).
I tried to find an elegant solution to maintain the paths, by using some existing function but I ended up with hard wiring the paths:
function requireFromString(src, filename) {
var m = new module.constructor();
m.paths = module.paths;
m._compile(src, filename);
return m.exports;
}
var codeString = 'var needle = require(\'needle\');\n'
+ '[...]\n'
+ 'exports.myFunc = myFunc;';
var virtMod = requireFromString(codeString);
console.log('Available public functions: '+Object.keys(virtMod));
After that I was able to load all existing modules from the stringified module.
Any comments or better solutions highly appreciated!
The require-from-string package does the job.
Usage:
var requireFromString = require('require-from-string');
requireFromString('module.exports = 1');
//=> 1
After analyzing the source code of such solutions as pirates and require-from-string, I came to the conclusion that a simple mock of fs and Module methods would be no worse in terms of support. And in terms of functionality it will be better, because it supports #babel/register, pirates and other modules that changes the module loading process.
You can try this npm module require-from-memory
import fs from 'fs'
import BuiltinModule from 'module'
const Module = module.constructor.length > 1 ? module.constructor : BuiltinModule
function requireFromString(code, filename) {
if (!filename) {
filename = ''
}
if (typeof filename !== 'string') {
throw new Error(`filename must be a string: ${filename}`)
}
let buffer
function getBuffer() {
if (!buffer) {
buffer = Buffer.from(code, 'utf8')
}
return buffer
}
const now = new Date()
const nowMs = now.getTime()
const size = Buffer.byteLength(code, 'utf8')
const fileStat = {
size,
blksize : 4096,
blocks : Math.ceil(size / 4096),
atimeMs : nowMs,
mtimeMs : nowMs,
ctimeMs : nowMs,
birthtimeMs: nowMs,
atime : now,
mtime : now,
ctime : now,
birthtime : now
}
const resolveFilename = Module._resolveFilename
const readFileSync = fs.readFileSync
const statSync = fs.statSync
try {
Module._resolveFilename = () => {
Module._resolveFilename = resolveFilename
return filename
}
fs.readFileSync = (fname, options, ...other) => {
if (fname === filename) {
console.log(code)
return typeof options === 'string'
? code
: getBuffer()
}
console.log(code)
return readFileSync.apply(fs, [fname, options, ...other])
}
fs.statSync = (fname, ...other) => {
if (fname === filename) {
return fileStat
}
return statSync.apply(fs, [fname, ...other])
}
return require(filename)
} finally {
Module._resolveFilename = resolveFilename
fs.readFileSync = readFileSync
fs.statSync = statSync
}
}
Based on Andrey Sidorov & Dominic solutions, I was saddened by the fact of not being able to require a stringified module then I suggest this version *.
Code:
void function() {
'use strict';
const EXTENSIONS = ['.js', '.json', '.node'];
var Module,
path,
cache,
resolveFilename,
demethodize,
hasOwnProperty,
dirname,
parse,
resolve,
stringify,
virtual;
Module = require('module');
path = require('path');
cache = Module._cache;
resolveFilename = Module._resolveFilename;
dirname = path.dirname;
parse = path.parse;
resolve = path.resolve;
demethodize = Function.bind.bind(Function.call);
hasOwnProperty = demethodize(Object.prototype.hasOwnProperty);
Module._resolveFilename = function(request, parent) {
var filename;
// Pre-resolution
filename = resolve(parse(parent.filename).dir, request);
// Adding extension, if needed
if (EXTENSIONS.indexOf(parse(filename).ext) === -1) {
filename += '.js';
}
// If the module exists or is virtual, return the filename
if (virtual || hasOwnProperty(cache, filename)) {
return filename;
}
// Preserving the native behavior
return resolveFilename.apply(Module, arguments);
};
Module._register = function(request, parent, src) {
var filename,
module;
// Enabling virtual resolution
virtual = true;
filename = Module._resolveFilename(request, parent);
// Disabling virtual resolution
virtual = false;
// Conflicts management
if (hasOwnProperty(cache, filename)) {
error = new Error('Existing module "' + request + '"');
error.code = 'MODULE_EXISTS';
throw error;
}
// Module loading
cache[filename] = module = new Module(filename, parent);
module.filename = filename;
module.paths = Module._nodeModulePaths(dirname(filename));
module._compile(stringify(src), filename);
module.loaded = true;
return module;
};
stringify = function(src) {
// If src is a function, turning to IIFE src
return typeof src === 'function'
? 'void ' + src.toString() + '();'
: src;
};
}();
void function() {
var Module,
parentModule,
child;
Module = require('module');
// Creating a parent module from string
parentModule = Module._register('parent', process.mainModule, `
module.exports = {
name: module.filename,
getChild: function() {
return require('child');
}
};
`);
// Creating a child module from function
Module._register('child', parentModule, function() {
module.exports = {
name: module.filename,
getParent: function() {
return module.parent.exports;
}
};
});
child = require('child');
console.log(child === child.getParent().getChild());
}();
Usage:
void function() {
var Module,
parentModule,
child;
Module = require('module');
// Creating a parent module from string
parentModule = Module._register('parent', process.mainModule, `
module.exports = {
name: module.filename,
getChild: function() {
return require('child');
}
};
`);
// Creating a child module from function
Module._register('child', parentModule, function() {
module.exports = {
name: module.filename,
getParent: function() {
return module.parent.exports;
}
};
});
child = require('child');
console.log(child === child.getParent().getChild());
}();
* as you can see, it contains a function formater which provides a way to create some modules from functions.
I think the better way to approach this would be to have a parameter that you could set afterwards...
such as inside the file: myUnalteredModule.js
exports.setChanges = function( args )...
Then you could do:
var loadedModule = require( 'myUnalteredModule' );
loadedModule

Get the most recent file in a directory, Node.js

I am trying to find the most recently created file in a directory using Node.js and cannot seem to find a solution. The following code seemed to be doing the trick on one machine but on another it was just pulling a random file from the directory - as I figured it might. Basically, I need to find the newest file and ONLY that file.
var fs = require('fs'); //File System
var audioFilePath = 'C:/scanner/audio/'; //Location of recorded audio files
var audioFile = fs.readdirSync(audioFilePath)
.slice(-1)[0]
.replace('.wav', '.mp3');
Many thanks!
Assuming availability of underscore (http://underscorejs.org/) and taking synchronous approach (which doesn't utilize the node.js strengths, but is easier to grasp):
var fs = require('fs'),
path = require('path'),
_ = require('underscore');
// Return only base file name without dir
function getMostRecentFileName(dir) {
var files = fs.readdirSync(dir);
// use underscore for max()
return _.max(files, function (f) {
var fullpath = path.join(dir, f);
// ctime = creation time is used
// replace with mtime for modification time
return fs.statSync(fullpath).ctime;
});
}
While not the most efficient approach, this should be conceptually straight forward:
var fs = require('fs'); //File System
var audioFilePath = 'C:/scanner/audio/'; //Location of recorded audio files
fs.readdir(audioFilePath, function(err, files) {
if (err) { throw err; }
var audioFile = getNewestFile(files, audioFilePath).replace('.wav', '.mp3');
//process audioFile here or pass it to a function...
console.log(audioFile);
});
function getNewestFile(files, path) {
var out = [];
files.forEach(function(file) {
var stats = fs.statSync(path + "/" +file);
if(stats.isFile()) {
out.push({"file":file, "mtime": stats.mtime.getTime()});
}
});
out.sort(function(a,b) {
return b.mtime - a.mtime;
})
return (out.length>0) ? out[0].file : "";
}
BTW, there is no obvious reason in the original post to use synchronous file listing.
Another approach:
const fs = require('fs')
const glob = require('glob')
const newestFile = glob.sync('input/*xlsx')
.map(name => ({name, ctime: fs.statSync(name).ctime}))
.sort((a, b) => b.ctime - a.ctime)[0].name
A more functional version might look like:
import { readdirSync, lstatSync } from "fs";
const orderReccentFiles = (dir: string) =>
readdirSync(dir)
.filter(f => lstatSync(f).isFile())
.map(file => ({ file, mtime: lstatSync(file).mtime }))
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
const getMostRecentFile = (dir: string) => {
const files = orderReccentFiles(dir);
return files.length ? files[0] : undefined;
};
First, you need to order files (newest at the begin)
Then, get the first element of an array for the most recent file.
I have modified code from #mikeysee to avoid the path exception so that I use the full path to fix them.
The snipped codes of 2 functions are shown below.
const fs = require('fs');
const path = require('path');
const getMostRecentFile = (dir) => {
const files = orderReccentFiles(dir);
return files.length ? files[0] : undefined;
};
const orderReccentFiles = (dir) => {
return fs.readdirSync(dir)
.filter(file => fs.lstatSync(path.join(dir, file)).isFile())
.map(file => ({ file, mtime: fs.lstatSync(path.join(dir, file)).mtime }))
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
};
const dirPath = '<PATH>';
getMostRecentFile(dirPath)
this should do the trick ("dir" is the directory you use fs.readdir over to get the "files" array):
function getNewestFile(dir, files, callback) {
if (!callback) return;
if (!files || (files && files.length === 0)) {
callback();
}
if (files.length === 1) {
callback(files[0]);
}
var newest = { file: files[0] };
var checked = 0;
fs.stat(dir + newest.file, function(err, stats) {
newest.mtime = stats.mtime;
for (var i = 0; i < files.length; i++) {
var file = files[i];
(function(file) {
fs.stat(file, function(err, stats) {
++checked;
if (stats.mtime.getTime() > newest.mtime.getTime()) {
newest = { file : file, mtime : stats.mtime };
}
if (checked == files.length) {
callback(newest);
}
});
})(dir + file);
}
});
}
[Extended umair's answer to correct a bug with current working directory]
function getNewestFile(dir, regexp) {
var fs = require("fs"),
path = require('path'),
newest = null,
files = fs.readdirSync(dir),
one_matched = 0,
i
for (i = 0; i < files.length; i++) {
if (regexp.test(files[i]) == false)
continue
else if (one_matched == 0) {
newest = files[i];
one_matched = 1;
continue
}
f1_time = fs.statSync(path.join(dir, files[i])).mtime.getTime()
f2_time = fs.statSync(path.join(dir, newest)).mtime.getTime()
if (f1_time > f2_time)
newest[i] = files[i]
}
if (newest != null)
return (path.join(dir, newest))
return null
}
Using pure JavaScript and easy to understand structure :
function getLatestFile(dirpath) {
// Check if dirpath exist or not right here
let latest;
const files = fs.readdirSync(dirpath);
files.forEach(filename => {
// Get the stat
const stat = fs.lstatSync(path.join(dirpath, filename));
// Pass if it is a directory
if (stat.isDirectory())
return;
// latest default to first file
if (!latest) {
latest = {filename, mtime: stat.mtime};
return;
}
// update latest if mtime is greater than the current latest
if (stat.mtime > latest.mtime) {
latest.filename = filename;
latest.mtime = stat.mtime;
}
});
return latest.filename;
}
Unfortunately, I don't think the files are guaranteed to be in any particular order.
Instead, you'll need to call fs.stat (or fs.statSync) on each file to get the date it was last modified, then select the newest one once you have all of the dates.
Surprisingly, there is no example in this questions that explicitly uses Array functions, functional programming.
Here is my take on getting the latest file of a directory in nodejs. By default, it will get the latest file by any extension. When passing the extension property, the function will return the latest file for that extension.
The advantage of this code is that its declarative and modular and easy to understand as oppose to using "logic branching/control flows", of course given you understand how these array functions work 😀
const fs = require('fs');
const path = require('path');
function getLatestFile({directory, extension}, callback){
fs.readdir(directory, (_ , dirlist)=>{
const latest = dirlist.map(_path => ({stat:fs.lstatSync(path.join(directory, _path)), dir:_path}))
.filter(_path => _path.stat.isFile())
.filter(_path => extension ? _path.dir.endsWith(`.${extension}`) : 1)
.sort((a, b) => b.stat.mtime - a.stat.mtime)
.map(_path => _path.dir);
callback(latest[0]);
});
}
getLatestFile({directory:process.cwd(), extension:'mp3'}, (filename=null)=>{
console.log(filename);
});
with synchronized version of read directory (fs.readdirSync) and file status (fs.statSync):
function getNewestFile(dir, regexp) {
newest = null
files = fs.readdirSync(dir)
one_matched = 0
for (i = 0; i < files.length; i++) {
if (regexp.test(files[i]) == false)
continue
else if (one_matched == 0) {
newest = files[i]
one_matched = 1
continue
}
f1_time = fs.statSync(files[i]).mtime.getTime()
f2_time = fs.statSync(newest).mtime.getTime()
if (f1_time > f2_time)
newest[i] = files[i]
}
if (newest != null)
return (dir + newest)
return null
}
you can call this function as follows:
var f = getNewestFile("./", new RegExp('.*\.mp3'))
An async version of #pguardiario's functional answer (I did this myself then found theirs halfway down the page when I went to add this).
import {promisify} from 'util';
import _glob from 'glob';
const glob = promisify(_glob);
const newestFile = (await Promise.all(
(await glob(YOUR_GLOB)).map(async (file) => (
{file, mtime:(await fs.stat(file)).mtime}
))
))
.sort(({mtime:a}, {mtime:b}) => ((a < b) ? 1 : -1))
[0]
.file
;
This is a commonplace need - write files out to a temp dir and automatically open the most recent one.
The following works with node version 16:
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
const fsPromises = fs.promises;
process.on('exit', code => {
console.log('exiting with code:', code);
});
const folder = path.join(process.env.HOME, 'publications/temp');
const c = cp.spawn('sh');
const files = fs.readdirSync(folder).map(v => path.resolve(folder + '/' + v));
const openFile = (file) => {
c.stdin.end(`(open "${file}" &> /dev/null) &> /dev/null &`);
};
if(files.length > 500) {
console.error('too many files, clean this folder up lol');
process.exit(1);
}
const newest = {file: null, mtime: null};
Promise.all(files.map(f => {
return fsPromises.stat(f).then(stats => {
if (!newest.file || (stats.mtime.getTime() > newest.mtime.getTime())) {
newest.file= f;
newest.mtime= stats.mtime;
}
});
})).then(v => {
if(!newest.file){
console.error('could not find the newest file?!');
return;
}
openFile(newest.file);
});
you may want to check for folders instead of files, and you could add something like this towards the beginning:
if (files.length === 1) {
if (fs.statSync(files[0]).isFile()) {
openFile(files[0]);
process.exit(0);
} else {
console.error('folder or symlink where file should be?');
process.exit(1);
}
}

Resources