Unable to use variables in fs functions when using brfs - node.js

I use browserify in order to be able to use require. To use fs functions with browserify i need to transform it with brfs but as far as I understood this results in only being able to input static strings as parameters inside my fs function. I want to be able to use variables for this.
I want to search for xml files in a specific directory and read them. Either by searching via text field or showing all of their data at once. In order to do this I need fs and browserify in order to require it.
const FS = require('fs')
function lookForRoom() {
let files = getFileNames()
findSearchedRoom(files)
}
function getFileNames() {
return FS.readdirSync('../data/')
}
function findSearchedRoom(files) {
const SEARCH_FIELD_ID = 'room'
let searchText = document.getElementById(SEARCH_FIELD_ID).value
files.forEach((file) => {
const SEARCHTEXT_FOUND = file.includes(searchText.toLowerCase())
if (SEARCHTEXT_FOUND) loadXML(file)
})
}
function loadXML(file) {
const XML2JS = require('xml2js')
let parser = new XML2JS.Parser()
let data = FS.readFile('../data/' + file)
console.dir(data);
}
module.exports = { lookForRoom: lookForRoom }
I want to be able to read contents out of a directory containing xml files.
Current status is that I can only do so when I provide a constant string to the fs function

The brfs README contains this gotcha:
Since brfs evaluates your source code statically, you can't use dynamic expressions that need to be evaluated at run time.
So, basically, you can't use brfs in the way you were hoping.
I want to be able to read contents out of a directory containing xml files
If by "a directory" you mean "any random directory, the name of which is determined by some form input", then that's not going to work. Browsers don't have direct access to directory contents, either locally or on a server.
You're not saying where that directory exists. If it's local (on the machine the browser is running on): I don't think there are standardized API's to do that, at all.
If it's on the server, then you need to implement an HTTP server that will accept a directory-/filename from some clientside code, and retrieve the file contents that way.

Related

JSON file not found

I have a json file with the name of email_templates.json placed in the same folder as my js file bootstrap.js. when I try to read the file I get an error.
no such file or directory, open './email_templates.json'
bootstrap.js
"use strict";
const fs = require('fs');
module.exports = async () => {
const { config } = JSON.parse(fs.readFileSync('./email_templates.json'));
console.log(config);
};
email_templates.json
[
{
"name":"vla",
"subject":"test template",
"path": ""
}
]
I am using VS code , for some reason VS code doesnt autocomplete the path as well which is confusing for me.Does anyone know why it is doing this?
Node v:14*
A possible solution is to get the full path (right from C:\, for example, if you are on Windows).
To do this, you first need to import path in your code.
const path = require("path");
Next, we need to join the directory in which the JavaScript file is in and the JSON filename. To do this, we will use the code below.
const jsonPath = path.resolve(__dirname, "email_templates.json");
The resolve() function basically mixes the two paths together to make one complete, valid path.
Finally, you can use this path to pass into readFileSync().
fs.readFileSync(jsonPath);
This should help with finding the path, if the issue was that it didn't like the relative path. The absolute path may help it find the file.
In conclusion, this solution should help with finding the path.

Determine if file/foder is hidden in Windows via Electron/Node

Is there a way to determine that a file in Windows is hidden in Electron. I need to know the hidden attribute set in Properties of the file and not file name having a dot at front. Currently using fs to get file system information I have no means to obtain this information.
Some sample use case would be (using Typescript):
import fs = require('fs');
getVisibleFilesSync(): string[] {
const folderItems = fs.readdirSync(folderPath);
return folderItems.filter(x => !isHidden(x));
}
isHidden(path: string): boolean {
// how to determine if path is hidden under Windows?
}
Try using the isHiddenSync function in the hidefile module.

How does this npm build work?

https://github.com/apigee-127/swagger-converter
I see this code:
var convert = require('swagger-converter');
var fs = require('fs');
var resourceListing = JSON.parse(fs.readFileSync('/path/to/petstore/index.json').toString());
var apiDeclarations = [ JSON.parse(fs.readFileSync('/path/to/petstore/pet.json').toString()),
JSON.parse(fs.readFileSync('/path/to/petstore/user.json').toString()),
JSON.parse(fs.readFileSync('/path/to/petstore/store.json').toString())
];
var swagger2Document = convert(resourceListing, apiDeclarations);
console.log(JSON.stringify(swagger2Document, null, 2));
I'm confsued as to what exactly I'm supposed to do here to run this? Do I start a node http server?
To run the file you pasted, just save the code into a file like script.js. Then from the command line (with node installed) run node script.js. That will run the file. Here's a breakdown of what it's doing:
var convert = require('swagger-converter');
This line gets reference to the swagger-converter module that you linked to. That module is designed to allow you to convert swagger documents into JSON.
var fs = require('fs');
This line gets reference to the node built-in filesystem module (fs for short). It provides an API for interacting with the filesystem on your machine when the script is running.
var resourceListing = JSON.parse(fs.readFileSync('/path/to/petstore/index.json').toString());
This line could be broken down to:
var indexContent = fs.readFileSync('/path/to/petstore/index.json');
JSON.parse(indexContent.toString());
readFileSync returns the contents of the index.json file as a buffer object, which is easily turned into a simple string with the call to .toString(). Then they pass it to JSON.parse which parses the string and turns it into a simple JavaScript object.
Fun Fact: They could have skipped those steps with a simple var resourceListing = require('/path/to/petstore/index.json');. Node knows how to read JSON files and automatically turn them into JavaScript objects. You need only pass the path to require.
var apiDeclarations = [ JSON.parse(fs.readFileSync('/path/to/petstore/pet.json').toString()),
JSON.parse(fs.readFileSync('/path/to/petstore/user.json').toString()),
JSON.parse(fs.readFileSync('/path/to/petstore/store.json').toString())
];
This bit of code does the same thing as the resourceListing except it creates an array of three JavaScript objects based on those JSON files. They also could have used require here to save a bit of work.
Then finally they use the converter to do the conversion and then they log that data to the terminal where your script is running.
var swagger2Document = convert(resourceListing, apiDeclarations);
console.log(JSON.stringify(swagger2Document, null, 2));
JSON.stringify is the opposite of JSON.parse. stringify turns a JavaScript object into a JSON string whereas parse turns a JSON string into a JavaScript object.

Get file name from absolute path in Nodejs?

How can I get the file name from an absolute path in Nodejs?
e.g. "foo.txt" from "/var/www/foo.txt"
I know it works with a string operation, like fullpath.replace(/.+\//, ''),
but I want to know is there an explicit way, like file.getName() in Java?
Use the basename method of the path module:
path.basename('/foo/bar/baz/asdf/quux.html')
// returns
'quux.html'
Here is the documentation the above example is taken from.
To get the file name portion of the file name, the basename method is used:
var path = require("path");
var fileName = "C:\\Python27\\ArcGIS10.2\\python.exe";
var file = path.basename(fileName);
console.log(file); // 'python.exe'
If you want the file name without the extension, you can pass the extension variable (containing the extension name) to the basename method telling Node to return only the name without the extension:
var path = require("path");
var fileName = "C:\\Python27\\ArcGIS10.2\\python.exe";
var extension = path.extname(fileName);
var file = path.basename(fileName,extension);
console.log(file); // 'python'
var path = require("path");
var filepath = "C:\\Python27\\ArcGIS10.2\\python.exe";
var name = path.parse(filepath).name;
console.log(name); //python
var base = path.parse(filepath).base;
console.log(base); //python.exe
var ext = path.parse(filepath).ext;
console.log(ext); //.exe
For those interested in removing extension from filename, you can use
https://nodejs.org/api/path.html#path_path_basename_path_ext
path.basename('/foo/bar/baz/asdf/quux.html', '.html');
If you already know that the path separator is / (i.e. you are writing for a specific platform/environment), as implied by the example in your question, you could keep it simple and split the string by separator:
'/foo/bar/baz/asdf/quux.html'.split('/').pop()
That would be faster (and cleaner imo) than replacing by regular expression.
Again: Only do this if you're writing for a specific environment, otherwise use the path module, as paths are surprisingly complex. Windows, for instance, supports / in many cases but not for e.g. the \\?\? style prefixes used for shared network folders and the like. On Windows the above method is doomed to fail, sooner or later.
path is a nodeJS module meaning you don't have to install any package for using its properties.
import path from 'path'
const dir_name = path.basename('/Users/Project_naptha/demo_path.js')
console.log(dir_name)
// returns
demo_path.js
In NodeJS, __filename.split(/\|//).pop() returns just the file name from the absolute file path on any OS platform.
Why need to care about remembering/importing an API while this regex approach also letting us recollect our regex skills.
So Nodejs comes with the default global variable called '__fileName' that holds the current file being executed
My advice is to pass the __fileName to a service from any file , so that the retrieval of the fileName is made dynamic
Below, I make use of the fileName string and then split it based on the path.sep. Note path.sep avoids issues with posix file seperators and windows file seperators (issues with '/' and '\'). It is much cleaner. Getting the substring and getting only the last seperated name and subtracting it with the actulal length by 3 speaks for itself.
You can write a service like this (Note this is in typescript , but you can very well write it in js )
export class AppLoggingConstants {
constructor(){
}
// Here make sure the fileName param is actually '__fileName'
getDefaultMedata(fileName: string, methodName: string) {
const appName = APP_NAME;
const actualFileName = fileName.substring(fileName.lastIndexOf(path.sep)+1, fileName.length - 3);
//const actualFileName = fileName;
return appName+ ' -- '+actualFileName;
}
}
export const AppLoggingConstantsInstance = new AppLoggingConstants();

Can I load multiple files with one require statement?

maybe this question is a little silly, but is it possible to load multiple .js files with one require statement? like this:
var mylib = require('./lib/mylibfiles');
and use:
mylib.foo(); //return "hello from one"
mylib.bar(): //return "hello from two"
And in the folder mylibfiles will have two files:
One.js
exports.foo= function(){return "hello from one";}
Two.js
exports.bar= function(){return "hello from two";}
I was thinking to put a package.json in the folder that say to load all the files, but I don't know how. Other aproach that I was thinking is to have a index.js that exports everything again but I will be duplicating work.
Thanks!!
P.D: I'm working with nodejs v0.611 on a windows 7 machine
First of all using require does not duplicate anything. It loads the module and it caches it, so calling require again will get it from memory (thus you can modify module at fly without interacting with its source code - this is sometimes desirable, for example when you want to store db connection inside module).
Also package.json does not load anything and does not interact with your app at all. It is only used for npm.
Now you cannot require multiple modules at once. For example what will happen if both One.js and Two.js have defined function with the same name?? There are more problems.
But what you can do, is to write additional file, say modules.js with the following content
module.exports = {
one : require('./one.js'),
two : require('./two.js'),
/* some other modules you want */
}
and then you can simply use
var modules = require('./modules.js');
modules.one.foo();
modules.two.bar();
I have a snippet of code that requires more than one module, but it doesn't clump them together as your post suggests. However, that can be overcome with a trick that I found.
function requireMany () {
return Array.prototype.slice.call(arguments).map(function (value) {
try {
return require(value)
}
catch (event) {
return console.log(event)
}
})
}
And you use it as such
requireMany("fs", "socket.io", "path")
Which will return
[ fs {}, socketio {}, path {} ]
If a module is not found, an error will be sent to the console. It won't break the programme. The error will be shown in the array as undefined. The array will not be shorter because one of the modules failed to load.
Then you can bind those each of those array elements to a variable name, like so:
var [fs, socketio, path] = requireMany("fs", "socket.io", "path")
It essentially works like an object, but assigns the keys and their values to the global namespace. So, in your case, you could do:
var [foo, bar] = requireMany("./foo.js", "./bar.js")
foo() //return "hello from one"
bar() //return "hello from two"
And if you do want it to break the programme on error, just use this modified version, which is smaller
function requireMany () {
return Array.prototype.slice.call(arguments).map(require)
}
Yes, you may require a folder as a module, according to the node docs. Let's say you want to require() a folder called ./mypack/.
Inside ./mypack/, create a package.json file with the name of the folder and a main javascript file with the same name, inside a ./lib/ directory.
{
"name" : "mypack",
"main" : "./lib/mypack.js"
}
Now you can use require('./mypack') and node will load ./mypack/lib/mypack.js.
However if you do not include this package.json file, it may still work. Without the file, node will attempt to load ./mypack/index.js, or if that's not there, ./mypack/index.node.
My understanding is that this could be beneficial if you have split your program into many javascript files but do not want to concatenate them for deployment.
You can use destructuring assignment to map an array of exported modules from require statements in one line:
const requires = (...modules) => modules.map(module => require(module));
const [fs, path] = requires('fs', 'path');
I was doing something similar to what #freakish suggests in his answer with a project where I've a list of test scripts that are pulled into a Puppeteer + Jest testing setup. My test files follow the naming convention testname1.js - testnameN.js and I was able use a generator function to require N number of files from the particular directory with the approach below:
const fs = require('fs');
const path = require('path');
module.exports = class FilesInDirectory {
constructor(directory) {
this.fid = fs.readdirSync(path.resolve(directory));
this.requiredFiles = (this.fid.map((fileId) => {
let resolvedPath = path.resolve(directory, fileId);
return require(resolvedPath);
})).filter(file => !!file);
}
printRetrievedFiles() {
console.log(this.requiredFiles);
}
nextFileGenerator() {
const parent = this;
const fidLength = parent.requiredFiles.length;
function* iterate(index) {
while (index < fidLength) {
yield parent.requiredFiles[index++];
}
}
return iterate(0);
}
}
Then use like so:
//Use in test
const FilesInDirectory = require('./utilities/getfilesindirectory');
const StepsCollection = new FilesInDirectory('./test-steps');
const StepsGenerator = StepsCollection.nextFileGenerator();
//Assuming we're in an async function
await StepsGenerator.next().value.FUNCTION_REQUIRED_FROM_FILE(someArg);

Resources