Use Chokidar for watching over files with specific extentions - javascript

I need to add support for this feature to my app.
My current implementation is very simple:
this.watcher.on("add", (pathName: string) => {
this.sendNotifyAction(new NotifyAction(PathEvent.Add, pathName));
}).on("change", (pathName: string) => {
this.sendNotifyAction(new NotifyAction(PathEvent.Change, pathName));
}).on("unlink", (pathName: string) => {
this.sendNotifyAction(new NotifyAction(PathEvent.Delete, pathName));
}).on("ready", () => {
this.sendReadinessNotification();
});
Now I want to have something like:
private acceptedFileExtensions: string[] = ['.txt', '.docx', '.xlx', ...]
And use this array of extensions inside Chokidar. So if the file in watched directory has extension from the list - send notification, if no - do nothing.
I saw similar question https://stackoverflow.com/questions/40468608/use-chokidar-to-watch-for-specific-file-extension#=, but it's not what I really need.
Filtering inside callback functions doesn't look good for me, but I don't see other variants. Please advise.
Thank you.

Thank you #robertklep, chokidar works with arrays.
So my code looks like:
private buildWildcardList(path:string): string[] {
let result: string[] = [];
_.each(this.acceptedFileExtensions, (extension: string) => {
result.push(path + '/**/*' + extension);
});
return result;
}
let wildcardList: string[] = this.buildWildcardList(path);
this.watcher = chokidar.watch(wildcardList, watchOptions);

Related

React / ES6 - Efficiently update property of an object in an array

I am looking for the most efficient way to update a property of an object in an array using modern JavaScript. I am currently doing the following but it is way too slow so I'm looking for an approach that will speed things up. Also, to put this in context, this code is used in a Redux Saga in a react app and is called on every keystroke* a user makes when writing code in an editor.
*Ok not EVERY keystroke. I do have debounce and throttling implemented I just wanted to focus on the update but I appreciate everyone catching this :)
function* updateCode({ payload: { code, selectedFile } }) {
try {
const tempFiles = stateFiles.filter(file => file.id !== selectedFile.id);
const updatedFile = {
...selectedFile,
content: code,
};
const newFiles = [...tempFiles, updatedFile];
}
catch () {}
}
the above works but is too slow.
I have also tried using splice but I get Invariant Violation: A state mutation
const index = stateFiles.findIndex(file => file.id === selectedFile.id);
const newFiles = Array.from(stateFiles.splice(index, 1, { ...selectedFile, content: code }));
You can use Array.prototype.map in order to construct your new array:
const newFiles = stateFiles.map(file => {
if (file.id !== selectedFile.id) {
return file;
}
return {
...selectedFile,
content: code,
};
});
Also, please consider using debouncing in order not to run your code on every keystroke.

Recursively read directory and create object in NodeJS

I've been struggling with trying to automate and clean up how I utilize sprite generation and loading in my HTML5 game using a NodeJS socket.io server to send an object containing the data needed to generate the sprites.
What I want to do to achieve this is to read through a directory /img and all its subdirectories (/assets1, /assets2, /assets3, etc) and create an object based on the data and structure of them. The problem I came across was that I couldn't find a nice way to handle the sub directories of, say, /assets3. Here's how my assets are setup as an example:
And here's the object example that I want to achieve but haven't without just using endless if/elses which honestly doesn't seem appealing to me and there has got to be a better way with the usage of a library.
var outputWeWant = {
assets1: {
img1: '/img/assets1/img1.png',
img2: '/img/assets1/img2.png',
},
assets2: {
img1: '/img/assets2/img1.png',
img2: '/img/assets2/img2.png',
},
assets3: {
img1: '/img/assets3/img1.png',
img2: '/img/assets3/img2.png',
assets4: {
img1: '/img/assets3/assets4/img1.png'
}
}
}
Below is just a little bit of brainstorming I did, but this isn't as effective as I want down the road and it looks disgusting having all the is a directory check as we add a new directory into assets4
fs.readdirSync('/img/').map(dirName => {
fs.readdirSync('/img/' + dirName).map(fileName => {
if (fs.statSync('/img/' + dirName + '/' + fileName).isDirectory()) {
// Read the new directory and add the files to our object
} else {
// It's not a directory, just add it to our object
}
});
});
This kind of potentially infinite operation calls for a recursive function. I’m going to assume this function is to be written for Node, and I’ll leave the filesystem details to the OP. This snippet should be treated as pseudo-code.
function parseDirectory(directory) {
return directory.getItems().reduce((out, item) => {
switch (item.type) {
case 'file':
out[item.name] = item.path;
break;
case 'directory':
out[item.name] = parseDirectory(item.path);
break;
}
return out;
}, {});
}
With the added fs code in the OP, here’s a (theoretically) working function:
function parseDirectory(directory) {
return fs.readdirSync(directory).reduce((out, item) => {
const itemPath = `${directory}/${item}`;
if (fs.statSync(itemPath).isDirectory()) {
out[item] = parseDirectory(itemPath);
} else {
out[item] = itemPath;
}
return out;
}, {});
}
Of if the syntax of reduce() is too contrived for your liking, try this:
function parseDirectory(directory) {
let out = {};
fs.readdirSync(directory).forEach(item => {
const itemPath = `${directory}/${item}`;
if (fs.statSync(itemPath).isDirectory()) {
out[item] = parseDirectory(itemPath);
} else {
out[item] = itemPath;
}
});
return out;
}

Get version_name from the version_code of an android package?

Is there any way to get the version_name based on the version_code of an android package?
For example:
'com.nianticlabs.pokemongo'
version_code: 2017121800
=> version_name: 0.87.5
all I want is something like:
function getVersionName(version_code) {
// do smt with version_code
return version_name;
}
But I don't think you can get one depending on the other, those are two separate things: only a string and an int
In native java you have:
public static int getVersionCode(Context context) {
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return pInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
return -1;
}
}
public static String getVersionName(Context context) {
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return pInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
return "";
}
}
you could look for the equivalent in your javascript google API
Easiest way to get version name:
private String getVersionName() {
versionName = BuildConfig.VERSION_NAME;
return versionName;
}
No this is not possible in general. Every app is completely free to choose it's own version name (user readable string) and version code scheme. Many apps will have two APKs which have different version codes with exactly the same version name. See the docs.

How to iterate through a loop of HTTP requests and store the data of each iteration appropriately to an array

I am using Spotify's API's search functionality to iterate through an array of SongSearchParams defined as:
export class SongSearchParams {
public title: string;
public artist: string;
constructor(title: string, artist: string){
this.title = title;
this.artist = artist;
}
}
My HTTP request looks like:
searchTrack(searchParams: SongSearchParams, type='track'){
var headers = new Headers({'Authorization': 'Bearer ' + this.hash_params.access_token});
this.user_url = "https://api.spotify.com/v1/search?query="+searchParams.artist+' '+
searchParams.title+"&offset=0&limit=1&type="+type+"&market=US";
return this.http.get(this.user_url, {headers : headers})
.map(res => res.json());
}
And in one of my component's typescript file I have access to the array of SongSearchParams that I want to individually pass into this searchTrack function when a certain button is clicked and save the album-image, trackname, and artist of a song.
onClick(){
for(let searchQuery of this.songService.songSearches){
this.spotifyserv.searchTrack(searchQuery)
.subscribe(res => {
this.searchedSong.artist = res.tracks.items[0].artists[0].name;
this.searchedSong.title = res.tracks.items[0].name;
this.searchedSong.imagePath = res.tracks.items[0].album.images[0].url;
console.log(this.searchedSong);
this.songService.addSong(this.searchedSong);
})
}
}
When I run this code, the console logs the correct song for each iteration but for some reason only the last song in my songSearches array gets physically added for the length of songSearches times.
Googling for answers to this issue, it seems that I need to use Promises called right after the other using the then() functionality so I tried implementing (for the searchTrack function):
This makes me think that it is an issue with my addSong function
addSong(song: Song){
this.songs.push(song);
this.songsChanged.next(this.songs.slice());
}
Though I don't really know what could be wrong with it so my second hunch is that I should be using promises called right after the other (which I have tried) but have failed to implement.
I think take a look at forkjoin
so something along the lines of:
let obsArray = [];
for(let searchQuery of this.songService.songSearches) {
obsArray.push(this.spotifyserv.searchTrack(searchQuery));
}
Observable.forkJoin(obsArray)
.subscribe(results => {
// results[0]
// results[1]
// ...
// results(n)
});
I discovered the solution to my problem though I do not know why it fixes it (I only have an assumption).
In the class where I created the onClick() method, I had a private member of type Song called songSearched which I was trying to overwrite for each song being added to the list. I instead rewrote the function to look like:
onClick(){
for(let searchQuery of this.songService.songSearches){
this.spotifyserv.searchTrack(searchQuery,
response => {
let res = response.json();
console.log(res.tracks.items[0].album.images[0].url);
console.log(res.tracks.items[0].name);
console.log(res.tracks.items[0].artists[0].name);
let searched_song = {artist : null, title : null, imagePath : null}
searched_song.artist = res.tracks.items[0].artists[0].name;
searched_song.title = res.tracks.items[0].name;
searched_song.imagePath = res.tracks.items[0].album.images[0].url;
console.log(searched_song);
//song_queue.push(searched_song);
this.songService.addSong(searched_song);
}
)
}
}
Here I instead create a new searched_song to be appended to the list inside the function itself that way for each request, there exists a searched_Song. I think before what was happening was that I was overwriting the same searchedSong and by the time it got to the addSong(searchedSong) the final song had already been searched with Spotify's API and had already overwritten the previous searches so that one song kept getting added.
Though this still wouldn't explain why the console log works in the previous line in my original attempt.

Reddit API: How do I convert & to & in Angular/Typescript/Ionic?

I cloned this repo: https://github.com/smartapant/ionic2-reddit-reader
It reads Reddit, but returns & as &
This function returns new Reddit posts:
load(url?) {
this.redditApi.fetch(url).subscribe((posts) => {
this.posts = posts;
this.loadCompleted = true;
console.log(posts)
})
}
I changed it to:
load(url?) {
this.redditApi.fetch(url).subscribe((posts) => {
this.posts = posts;
function replace() {
var postscleaned = posts.replace( /&/g, '&' );
return(postscleaned);
};
this.loadCompleted = true;
console.log(postscleaned)
})
}
... following the advice in these questions:
Decode & back to & in JavaScript
Convert json & to & in AngularJS
And added postscleaned: Array<any> to the export class PostsPage.
It builds alright, but I get a Typescript Error
Cannot find name 'postscleaned'.
What is the best way to solve this? Is there a method that will work in Typescript but not Javascript?
With
function replace() {...};
You are defining a function, but not executing it. I am guessing what you really want to achieve is to execute those two lines:
var postscleaned = posts.replace( /&/g, '&' );
return(postscleaned);
instead of just giving them a name as a function.
In other words, the code you're looking for is:
load(url?) {
this.redditApi.fetch(url).subscribe((posts) => {
this.posts = posts;
var postscleaned = posts.replace( /&/g, '&' );
this.loadCompleted = true;
console.log(postscleaned)
})
}
However, posts seems like an array of strings rather than a single string, therefor what you really are looking for might be:
load(url?) {
this.redditApi.fetch(url).subscribe((posts) => {
this.posts = posts;
var postscleaned = [];
for (int i=0; i<posts.length; i++) {
postscleaned[i] = posts[i].replace( /&/g, '&' );
}
this.loadCompleted = true;
console.log(postscleaned)
})
}
Reddit API documentation:
response body encoding
For legacy reasons, all JSON response bodies currently have <, >, and &replaced with <, >, and &, respectively. If you wish to opt out of this behaviour, add a raw_json=1 parameter to your request.
So:
www.reddit.com/r/longevity.json?
becomes
www.reddit.com/r/longevity.json?raw_json=1
& (ampersands) now display correctly. I don't know if there are any performance drawbacks.

Categories

Resources