I'm making a build script for my angular app in node. Please have a look at the snippet:
const fs = require('fs-extra');
const dev = process.argv[2] === 'dev';
const folder = process.argv[3];
if (folder && fs.existsSync(`./projects/${folder}`)) {
const execSync = require('child_process').execSync;
// ng build --prod --output-hashing=none OR ng build --source-map --output-hashing=none
let command;
if (dev) {
command = 'ng build --source-map --output-hashing=none ' + folder;
} else {
command = 'ng build --prod --output-hashing=none ' + folder;
}
// execSync(command, {stdio:[0, 1, 2]});
(async function build()
{
const files = [
];
const { promisify } = require('util')
const getFiles = async () => {
try {
const readdir = promisify(fs.readdir);
await readdir(`./dist/${folder}`, {withFileTypes:true}, (err, elements) => {
//handling error
if (err) {
return console.error('Unable to scan directory: ' + err);
} else {
elements.forEach(async element => {
if( !element.isDirectory() && /.*-es2015.js$/.test(element.name) ) {
files.push(`./dist/${folder}/${element.name}`);
console.log(`Pushing file: ./dist/${folder}/${element.name}`);
}
});
}
});
} catch (err) {
console.error(err);
}
}
await getFiles();
// We need a random number for voiding the cache with every new build
const random = [...Array(10)].map(()=>(c = (r = Math.random()).toString(36)[2]) && r>.5 ? c.toUpperCase():c ).join('');
// create directory if doesnt exists (not needed anymore): await fs.ensureDir(`../js/${folder}/dist`)
if (!dev && files.length) {
const concat = require('concat');
await concat(files, `./dist/${folder}/concatenated.${random}.js`);
}
console.log('Build complete');
}
)();
} else if (folder && !fs.existsSync(`projects/${folder}`)) {
console.log('Specified destination folder does not exists as a project');
}
else {
console.log('Please specify a destination folder such as app-name');
}
Well, the mysterious is that just after await getFiles() call, the execution halts, no error neither message anywhere is shown. I'm getting crazy investigating this.
Can anybody spot the issue?
Thanks
The main issue in your code is that you are not promisfying the readdir correctly.
Try this:
(async () => {
try {
const readdir = require('util').promisify(require('fs').readdir);
const elements = await readdir(`./dist/${folder}`, { withFileTypes: true });
await Promise.all(
elements.map(async (element) => {
if (!element.isDirectory() && /.*-es2015.js$/.test(element.name)) {
files.push(`./dist/${folder}/${element.name}`);
console.log(`Pushing file: ./dist/${folder}/${element.name}`);
}
})
);
} catch (error) {
console.error('Unable to scan directory: ' + err);
}
})();
You can of course keep your forEach while omitting the async instead of the map + async + Promise.all. The difference is is that the one I suggest is faster since it utilizes concurrency while forEach would work sequentially! But either one would work!
Related
I am trying to save to json the values returned from indeed api. I use indeed-scraper code from github https://github.com/rynobax/indeed-scraper
My code:
... required files ...
const parsedResults = []
indeed.query(queryOptions).then(response => {
response.forEach((res,i) => {
setTimeout(function(){
let url = res.url
let resultCount = 0
console.log(`\n Scraping of ${url} initiated...\n`)
const getWebsiteContent = async (url) => {
try {
const response = await axios.get(url)
const $ = cheerio.load(response.data)
...get scraped data...
parsedResults.push(metadata)
} catch (error) {
exportResults(parsedResults)
console.error(error)
}
}
getWebsiteContent(url)
}
, i*3000);
});
});
const outputFile = 'data.json'
const fs = require('fs');
const exportResults = (parsedResults) => {
fs.writeFile(outputFile, JSON.stringify(parsedResults, null, 4), (err) => {
if (err) {
console.log(err)
}
console.log(`\n ${parsedResults.length} Results exported successfully to ${outputFile}\n`)
})
}
parsedResults is not accessible in last portion of script, so to save as json file.
Any help appreciated!
I want to cofigure mocha report to only contain failed cases.
I am using below code to read js test files and send mail on completion .
I want to send only failure cases. How to configure it in mocha ?
const Mocha = require('mocha');
const fs = require('fs');
const path = require('path');
const mocha = new Mocha({});
const sendMail = require('./sendMail');
const error = require('./errMsg');
async function executeMocha() {
const testDirPath = path.resolve('./') + '/test';
fs.readdirSync(testDirPath).filter(function (file) {
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function (file) {
mocha.addFile(
path.join(testDirPath, file)
);
});
mocha.reporter('mocha-simple-html-reporter', { output: '/tmp/testspec.html' }).run(
async (err,res) => {
if(err){
console.log("\n\n\n\nTest Case FAAAAAAAAAAILLLLLL \n\n\n\n");
}
console.log("\n\n\n\nTest Case Execution Successfull\n\n\n\n");
await getResult();
}
);
}
async function getResult() {
fs.readFile(('/tmp/testspec.html'), 'utf8', async (err, res) => {
if (err) {
await sendMail((process.env.env_type +error.fail.subject + process.env.CB_TEST_URL ), error.fail.body + err);
}
await sendMail((process.env.env_type +error.success.subject + process.env.CB_TEST_URL ), res);
})
}
module.exports = executeMocha
Um, assuming in your mocha.reporter function that that if(err) the test case is a fail, u can just do this(however I'm not even sure what would be a fail for u, not seeing you wanting any specific results or anything)
const Mocha = require('mocha');
const fs = require('fs');
const path = require('path');
const mocha = new Mocha({});
const sendMail = require('./sendMail');
const error = require('./errMsg');
async function executeMocha() {
const testDirPath = path.resolve('./') + '/test';
fs.readdirSync(testDirPath).filter(function (file) {
//in case someone has a FOLDER named with '.js' at the end
if(!fs.lstatSync(file).isFile()){return null}
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function (file) {
mocha.addFile(
path.join(testDirPath, file)
);
});
mocha.reporter('mocha-simple-html-reporter', { output: '/tmp/testspec.html' }).run(
async (err,res) => {
if(err){
console.log("\n\n\n\nTest Case FAAAAAAAAAAILLLLLL \n\n\n\n");
return await sendMail((process.env.env_type +error.fail.subject + process.env.CB_TEST_URL ), error.fail.body + err);
}
console.log("\n\n\n\nTest Case Execution Successfull\n\n\n\n");
}
);
}
async function getResult() { //error would only happen here if there was a problem READING the html file, unsure where the js files in question would be responsible
fs.readFile(('/tmp/testspec.html'), 'utf8', async (err, res) => {
if (err) {
await sendMail((process.env.env_type +error.fail.subject + process.env.CB_TEST_URL ), error.fail.body + err);
}
await sendMail((process.env.env_type +error.success.subject + process.env.CB_TEST_URL ), res);
})
}
module.exports = executeMocha
electron app code from the book Cross-platform Desktop Applications, It aims to display the users file directory like in a desktop explorer application to the browser.
const os = require('os');
const fs = require('fs');
const path = require('path');
const async = require('async');
function getHomeFolder (){
return os.homedir();
}
function retrieveFiles (folderPath,cb) {
fs.readdir(folderPath,cb);
}
function inspectAndDescribeFiles (filepath,cb) {
let result = {
file:path.basename(filepath),
path:filepath,type:''
};
fs.stat(filepath,(err,stat) =>{
if(err){
cb(err);
}else{
if(stat.isFile()){
result.type = 'file';
}
if(stat.isDirectory()){
result.type = 'directory';
}
//cb(err,result);
}
});
}
function inspectAndDescribeFiles(folderPath,files,cb){
async.map(files,(file,asyncCb) => {
let resolvedFilePath = path.resolve(folderPath,file);
inspectAndDescribeFiles(resolvedFilePath,asyncCb);
},cb);
}
function displayFileIcons (file){
const mainArea = document.getElementById('main-area');
//const template = document.querySelector('item-template');
//let clone = document.importNode(template.content, true);
const img = document.querySelector('img').src = './assets/foldericon.png';
const fileImg = document.querySelector('.filename').innerText =file.file;
//clone.querySelector('img').src =`assets/${file.type}.png`;
//clone.querySelector('.filename').innerText =file.file;
mainArea.appendChild(img);
}
function displayFiles (err,files){
if(err){
return alert("Sorry we couldn't display your files");
}
//files.forEach((file)=>{console.log(file); });
files.forEach(displayFileIcons);
}
function main () {
const folderPath = getHomeFolder();
retrieveFiles(folderPath,(err,files) => {
if(err) {
return alert('Sorry we could not load your home folder');
}
// files.forEach((file) => {
// console.log(`${folderPath}/${file}`);
// });
inspectAndDescribeFiles(folderPath,files,displayFileIcons);
});
}
main();
The error printing to the developer tools console reads "Uncaught (in promise) TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined.What I'm I doing wrong ?
This line: inspectAndDescribeFiles(resolvedFilePath,asyncCb);. inspectAndDescribeFiles takes three arguments, not two.
I wonder why I am getting this err/warning even though my code looks okay.
Here's the UserModel I started building:
const fs = require('fs');
class UserModel {
constructor(filename) {
if (!filename) {
throw new Error('Require a filename...');
}
this.file = filename;
try{
fs.accessSync(this.file); //to check if the file exists already
} catch (err) { //if not, make a new file
fs.writeFileSync(this.file, ['']);
}
}
async getAll() {
return JSON.parse(await fs.promises.readFile(this.file,{
encoding: 'utf8'
}));
}
}
//to test the above code
const test = async () => {
const user = new UserModel('users.json');
const data = await user.getAll();
console.log(data);
}
test();
Please help, new to NodeJS world.
Like the comment says, you should put a try/catch around the await in getAll. Like this:
const fs = require('fs');
class UserModel {
constructor(filename) {
if (!filename) {
throw new Error('Require a filename...');
}
this.file = filename;
try{
fs.accessSync(this.file); //to check if the file exists already
} catch (err) { //if not, make a new file
fs.writeFileSync(this.file, ['']);
}
}
async getAll() {
return JSON.parse(await fs.promises.readFile(this.file,{
encoding: 'utf8'
}));
}
}
//to test the above code
const test = async () => {
const user = new UserModel('users.json');
try {
const data = await user.getAll();
console.log(data);
} catch (error) {
// handle error
console.log(error.stack)
}
}
test();
I want to check if the path is a file or a directory. If it's a directory then Log the directory and file separately. Later I want to send them as json object.
const testFolder = './data/';
fs.readdir(testFolder, (err, files) => {
files.forEach(file => {
console.log(`FILES: ${file}`);
})});
Edit:
If I try to this
fs.readdir(testFolder, (err, files) => {
files.forEach(file => {
if (fs.statSync(file).isDirectory()) {
console.log(`DIR: ${file}`);
} else {
console.log(`FILE: ${file}`)
}
})});
I get this error:
nodejs binding.lstat(pathModule._makeLong(path))
Update: Found the solution. I had to add testFolder + file like this :
if (fs.statSync(testFolder + file).isDirectory()) {
quick google search..
var fs = require('fs');
var stats = fs.statSync("c:\\dog.jpg");
console.log('is file ? ' + stats.isFile());
read: http://www.technicalkeeda.com/nodejs-tutorials/how-to-check-if-path-is-file-or-directory-using-nodejs
Since Node 10.10+, fs.readdir has withFileTypes option which makes it return directory entry fs.Dirent instead of just the filename. Directory entry contains useful methods such as isDirectory or isFile.
Your example then would be solved by:
const testFolder = './data/';
fs.readdir(testFolder, { withFileTypes: true }, (err, dirEntries) => {
dirEntries.forEach((dirEntry) => {
const { name } = dirEntry;
if (dirEntry.isDirectory()) {
console.log(`DIR: ${name}`);
} else {
console.log(`FILE: ${name}`);
}
})})