Creating a Folder in NodeJs - javascript

I am trying to write a basic JS script in NodeJs. The script will create a folder with the name of the folder to be reponses_timestamp.
I have written the attached script, however, when it runs, i receive an error which says:
Einval: invalid argument.
Any ideas on how to fix this?
Test.js
const fs = require('fs');
const today = new Date();
const date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
const time = today.getHours()+":"+today.getMinutes()+":"+today.getSeconds();
const dateTime = date + '_' + time;
const uniqueIdentifier = dateTime;
// const folderName = './responses' + '_' + uniqueIdentifier;
try {
if (!fs.existsSync('./responses' + '_' + uniqueIdentifier)) {
fs.mkdirSync('./responses' + '_' + uniqueIdentifier)
}
} catch (err) {
console.error(err)
}

Probably - the problem is with the folder name. In Windows folder should not have special characters, like :

As mentioned the issue is due to the usage of the colon : because Windows (also per your screenshot Windows shown as the path) will not allow special characters.
It wasn't mentioned a solution so I wanted to mention for what you're doing this can be achieved easily with moment js using two lines of code and a substitution of the colon for a dash:
const date = new Date()
const uniqueIdentifier = moment(date).format('YYYY-MM-DD-HH-MM')
console.log('uuid', uniqueIdentifier)
// Result: "uuid" "2021-05-13-11-05"
and even a one-liner:
const uniqueIdentifier = moment(new Date()).format('YYYY-MM-DD-HH-MM')
console.log('uuid', uniqueIdentifier)
// Result: "uuid" "2021-05-13-11-05"

Related

Javascript - How would you make a record unique by adding a number?

Right now when file already exist I added prefix which is a timestamp to the filename to make it unique.
But instead of using timestamp I want to use ordinal suffix or add a number to the filename.
I would add an incremented number to the filename if the file exists. But can't quite wrap my head around how to do this in a good way.
Using timestamp works but its too long like when we display the filename it would be like for example so instead of using timestamp I just want to increment a number to a filename.
Hellworldfilename - 1593024232 - timestamp is too long , not a good idea.
It should based from existing records in the database . If for example I add a file with filename Hellworldfilename and it already existed then the new filename would be Hellworldfilename-1 , and if I add Hellworldfilename again the new filename would be Hellworldfilename-2 and so on and so forth. Any idea how we can make a filename everytime unique ?
Let me give an example. let us say I have 3 files in the database with filesname
DOC
DOC-1
DOC-2
If I add a file with filename DOC the new filename would be now DOC-3.
#Code for checking if file exists
const file = await context.service.Model.findOne({
where: { humanId: record.id, filename: data.filename },
paranoid: false,
});
if (file) {
const prefix = Date.now().toString();
// eslint-disable-next-line no-undef
const fileParts = data.filename.split('.');
filename = `${fileParts[0]}-${prefix}.${fileParts[1]}`;
You will need to check whether the filename ends with -somenumber. If so, then you can extract that number and increment it. Otherwise put 1 into the result:
function getNumberedFileName(fileN) {
//These are value initializations to cope with the situation when the file does not have a .
var fileName = fileN;
var fileExtension = "";
var lastDotIndex = fileN.lastIndexOf(".");
if ((lastDotIndex > 0) && (lastDotIndex < fileN.length - 1)) { //We are not interested in file extensions for files without an extension hidden in UNIX systems, like .gitignore and we are not interested in file extensions if the file ends with a dot
fileName = fileN.substring(0, lastDotIndex);
fileExtension = "." + fileN.substring(lastDotIndex + 1);
}
var lastDashIndex = fileName.lastIndexOf("-");
if ((lastDashIndex > 0) && (lastDashIndex < fileName.length - 1)) {
var lastPart = fileName.substring(lastDashIndex + 1);
if (!isNaN(lastPart)) {
var index = parseInt(lastPart) + 1;
return fileName.substring(0, lastDashIndex) + "-" + index + fileExtension;
}
}
return fileName + "-1" + fileExtension;
}
You could declare an object filenames in the global scope like
const filenames={};
and use it for keeping track of already opened files.
Below I defined a function makeUnique() hilighting the ideas I mentioned here before. It turns out I had to tweak my code a little bit but here is a working snippet:
const makeUnique=(function(){
const filenames={};
return function(fn){
const fileParts=fn.split(".");
const prefix=filenames[fn]!=null
? ++filenames[fn]
: filenames[fn]=0;
if (prefix) fileParts[Math.max(fileParts.length-2,0)]+='-'+prefix;
return fileParts.join('.')
}
})();
console.log(["abc","d.e.f.c","abc","ghi","abc","abc.txt","def",
"abc.txt","d.e.f.c","abc.txt","abc"].map(makeUnique))
.as-console-wrapper {max-height:100% !important}
I used an IIFE to generate a protected scope for the static object filenames. This is now accessible by all calls of makeUnique() but otherwise "private", i. e. cannot be modified accidentally from anywhere else.

NodeJS : smart JSON conversion to Excel file

I'm working in NodeJS and I would like to export a JSON-format object to an Excel file.
I am well aware that there are (at least) three npm packages for that purpose, but so far none of these gave me the output I'm dreaming of.
Here is the javascript object I have :
var myObject =
{
hashkey1 : {
keyA : dataA1,
keyB : dataB2
}
hashkey2 : {
keyA : dataA2,
keyB : dataB2
}
};
The .xls (or .xlsx)(or any spreadsheet format) of my dreams has one line for each hashkey. On each line : first column would be the hashkeyX, second column would be the dataAX, third column would be the dataBX.
Is it possible to achieve such a result using available tools, or do I have to code it from scratch ? Any advice to get anywhere near this result ?
You can write to csv (comma-separated values) text file without any additional library. This extension open in Excel by default.
var fs = require('fs');
var file = fs.createWriteStream('file.csv', {'flags': 'w', autoClose: true});
var result = '';
for (var hashkey in myObject)
result += hashkey + ';' + myObject[hashkey].keyA + ';' + myObject[hashkey].keyB + '\n';
file.write(result);

InDesign script to pull file by week number

I have a script for our newspaper that pulls comics from a folder and places them in an InDesign document. Most comics have the full date in the filename, but a few Sunday comics go by the week number for that Sunday. I.E. Blondie sunday filenames are like bln04ts.pdf or bln05ts.pdf. When we run the script we select the day to pull comics for but I'm unsure how to pull these files by week number?
Here is a sample by full date in filename if that helps at all.
` // LUANN
if (pageItem.label == "LUANN")
try{
name = "lu" + myDate.text + ".tif"
var myFile = new File(imagePath+name);
if (myFile.exists)
{
pageItem.place(myFile);
pageItem.fit(FitOptions.CONTENT_TO_FRAME);
}
name = "lu" + myDate.text + "_vacation.tif"
var myFile = new File(imagePath+name);
if (myFile.exists)
{
pageItem.place(File(myFile));
pageItem.fit(FitOptions.CONTENT_TO_FRAME);
}
name = "lu" + myDate.text + "_crx.tif"
var myFile = new File(imagePath+name);
if (myFile.exists)
{
pageItem.place(File(myFile));
pageItem.fit(FitOptions.CONTENT_TO_FRAME);
}
}catch(err){
//alert("caught error")
}`
Any ideas?
Well, if I understand you correctly you would need to add some lines like these to your script:
name = "bln" + myDate.week + "ts.pdf";
var myFile = new File(imagePath+name);
if (myFile.exists)
{
pageItem.place(File(myFile));
pageItem.fit(FitOptions.CONTENT_TO_FRAME);
}
However you'll also need to change the setup of you myDate object to include a week property. I don't know how the myDate object is set up (does it create the date text from the current date? Or from the file name of the document? Or something else?), so you would need to post a snippet of that, if you need further assistance on that step.

Removing the last character from file stream in node.js (fs module)

Using node.js, I am trying to build an array of objects and write them to a file. To do this, I'm using the built in fs library.
After calling
var file = fs.createWriteStream('arrayOfObjects.json'); and file.write('[') I run several asynchronous functions to eventually append objects like this:
file.write(JSON.stringify(objectToAppend) + ',\n')
I can determine when all of the objects have stopped appending, and this is where I run file.write(']') and file.end(). My problem is that adding the last comma to the end of the last object causes the JSON to be invalid.
It is very difficult to determine where and when the last object is being created due to the asynchronous nature of the script, so I was wondering if there is a way to strip or remove characters from a file-stream. If so, I could do this before adding the last ']' character.
I could do this manually, but I was hoping to pipe this to another application. The only solution I've thought about is using the fs.truncate() function, however this doesn't seem to work for file streams, and neither file.length or file.length() will give me the length of the contents because it is not a string so it's difficult to determine how or where to truncate the file.
For now I have just been adding '{}]' to the end of the array to make it valid JSON, but this empty object may cause some problems later.
Also note: the array of objects I am writing in this stream is VERY large, so I would rather not end the stream and re-open the file.
I'd recommend to prepend the separator instead, so that you dynamically can adjust it after the first call:
file.write('[\n')
var sep = "";
forEach(function(objectToAppen) {
file.write(sep + JSON.stringify(objectToAppend))
if (!sep)
sep = ",\n";
});
Example using JSONStream:
var JSONStream = require('JSONStream');
var fs = require('fs');
var jsonwriter = JSONStream.stringify();
var file = fs.createWriteStream('arrayOfObjects.json');
// Pipe the JSON data to the file.
jsonwriter.pipe(file);
// Write your objects to the JSON stream.
jsonwriter.write({ foo : 'bar#1' });
jsonwriter.write({ foo : 'bar#2' });
jsonwriter.write({ foo : 'bar#3' });
jsonwriter.write({ foo : 'bar#4' });
// When you're done, end it.
jsonwriter.end();
Here's a snippet incorporating robertklep's answer. This converts from a pipe-separated file to json:
var fs = require('fs');
var readline = require('readline');
var JSONStream = require('JSONStream');
// Make sure we got a filename on the command line.
if (process.argv.length < 3) {
console.log('Usage: node ' + process.argv[1] + ' FILENAME');
process.exit(1);
}
var filename = process.argv[2];
var outputFilename = filename + '.json';
console.log("Converting psv to json. Please wait.");
var jsonwriter = JSONStream.stringify();
var outputFile = fs.createWriteStream(outputFilename);
jsonwriter.pipe(outputFile);
var rl = readline.createInterface({
input: fs.createReadStream(filename),
terminal: false
}).on('line', function(line) {
console.log('Line: ' + line);
if(!/ADDRESS_DETAIL_PID/.test(line))
{
var split = line.split('|');
var line_as_json = { "address_detail_pid": split[0], "flat_type": split[1], "flat_number": split[2], "level_type": split[3], "level_number": split[4], "number_first": split[5], "street_name": split[6], "street_type_code": split[7], "locality_name": split[8], "state_abbreviation": split[9], "postcode": split[10], "longitude": split[11], "latitude": split[12] };
jsonwriter.write(line_as_json);
}
}).on('close', () => {
jsonwriter.end();
});;
console.log('psv2json complete.');
The accepted answer is interesting (prepending the separator) but in my case I have found it easier to append the separator and remove the last character of the file, just as suggested in the question.
This is how you remove the last character of a file with Node.js :
import fs from 'fs'
async function removeLastCharacter(filename) {
const stat = await fs.promises.stat(filename)
const fileSize = stat.size
await fs.promises.truncate(filename, fileSize - 1)
}
explanation :
fs.promises.stat gives us some information about the file, we will use its size.
fs.promises.truncate remove from the file what is after a certain position
We use the position fileSize - 1 which is the last character.
Note :
Yes I know that we need to wait until the stream is closed, but this is ok because truncate and stat functions are very fast and doesn't depend on the file size, it doesn't have to read its content.

How do I change file extension with javascript

Does anyone know an easy way to change a file extension in Javascript?
For example, I have a variable with "first.docx" but I need to change it to "first.html".
This will change the string containing the file name;
let file = "first.docx";
file = file.substr(0, file.lastIndexOf(".")) + ".htm";
For situations where there may not be an extension:
let pos = file.lastIndexOf(".");
file = file.substr(0, pos < 0 ? file.length : pos) + ".htm";
In Node.js:
path.join(path.dirname(file), path.basename(file, path.extname(file)) + '.md')
or more readably:
// extension should include the dot, for example '.html'
function changeExtension(file, extension) {
const basename = path.basename(file, path.extname(file))
return path.join(path.dirname(file), basename + extension)
}
Unlike the accepted answer, this works for edge cases such as if the file doesn't have an extension and one of the parent directories has a dot in their name.
I'd use this:
path.format({ ...path.parse('/path/to/file.txt'), base: '', ext: '.md' })
to change "/path/to/file.txt" to "/path/to/file.md".
file = file.replace(/\.[^.]+$/, '.html');
This probably won't get many upvotes but I couldn't resist.
This code will deal with the edge case where a file might not have an extension already (in which case it will add it). It uses the "tilde trick"
function changeExt (fileName, newExt) {
var _tmp
return fileName.substr(0, ~(_tmp = fileName.lastIndexOf('.')) ? _tmp : fileName.length) + '.' + newExt
}
EDITED: thanks #kylemit for a much better gist which uses the same logic, but in a much much neater way:
function changeExt(fileName, newExt) {
var pos = fileName.includes(".") ? fileName.lastIndexOf(".") : fileName.length
var fileRoot = fileName.substr(0, pos)
var output = `${fileRoot}.${newExt}`
return output
}
console.log(changeExt("img.jpeg", "jpg")) // img.jpg
console.log(changeExt("img.name.jpeg", "jpg")) // img.name.jpg
console.log(changeExt("host", "csv")) // host.csv
console.log(changeExt(".graphqlrc", "graphqlconfig")) // .graphqlconfig
path.parse("first.docx").name + ".html"
var file = "first.docx";
file = file.split(".");
file = file[0]+".html";

Categories