Nodejs absolute paths in windows with forward slash - node.js

Can I have absolute paths with forward slashes in windows in nodejs? I am using something like this :
global.__base = __dirname + '/';
var Article = require(__base + 'app/models/article');
But on windows the build is failing as it is requiring something like C:\Something\Something/apps/models/article. I aam using webpack. So how to circumvent this issue so that the requiring remains the same i.e. __base + 'app/models/src'?

I know it is a bit late to answer but I think my answer will help some visitors.
In Node.js you can easily get your current running file name and its directory by just using __filename and __dirname variables respectively.
In order to correct the forward and back slash accordingly to your system you can use path module of Node.js
var path = require('path');
Like here is a messed path and I want it to be correct if I want to use it on my server. Here the path module do everything for you
var randomPath = "desktop//my folder/\myfile.txt";
var correctedPath = path.normalize(randomPath); //that's that
console.log(correctedPath);
desktop/my folder/myfile.txt
If you want the absolute path of a file then you can also use resolve function of path module
var somePath = "./img.jpg";
var resolvedPath = path.resolve(somePath);
console.log(resolvedPath);
/Users/vikasbansal/Desktop/temp/img.jpg

it's 2020, 5 years from the question was published, but I hope that for somebody my answer will be useful. I've used the replace method, here is my code(express js project):
const viewPath = (path.join(__dirname, '../views/')).replace(/\\/g, '/')
exports.articlesList = function(req, res) {
res.sendFile(viewPath + 'articlesList.html');
}

I finally did it like this:
var slash = require('slash');
var dirname = __dirname;
if (process.platform === 'win32') dirname = slash(dirname);
global.__base = dirname + '/';
And then to require var Article = require(__base + 'app/models/article');. This uses the npm package slash (which replaces backslashes by slashes in paths and handles some more cases)

The accepted answer doesn't actually answer the question most people come here for.
If you're looking to normalize all path separators (possibly for string work), here's what you need.
All the code segments have the node.js built-in module path imported to the path variable.
They also have the variable they work from stored in the immutable variable str, unless otherwise specified.
If you have a string, here's a quick one-liner normalize the string to a forward slash (/):
const answer = path.resolve(str).split(path.sep).join("/");
You can normalize to any other separator by replacing the forward slash (/).
If you want just an array of the parts of the path, use this:
const answer = path.resolve(str).split(path.sep);
Once you're done with your string work, use this to create a path able to be used:
const answer = path.resolve(str);
From an array, use this:
// assume the array is stored in constant variable arr
const answer = path.join(...arr);

I recommend against this, as it is patching node itself, but... well, no changes in how you require things.
(function() {
"use strict";
var path = require('path');
var oldRequire = require;
require = function(module) {
var fixedModule = path.join.apply(path, module.split(/\/|\\/));
oldRequire(fixedModule);
}
})();

This is the approach I use, to save some processing:
const path = require('path');
// normalize based on the OS
const normalizePath = (value: string): string {
return path.sep === '\'
? value.replace(/\\/g, '/')
: value;
}
console.log('abc/def'); // leaves as is
console.log('abc\def'); // on windows converts to `abc/def`, otherwise leave as is

Windows uses \, Linux and mac use / for path prefixes
For Windows : 'C:\\Results\\user1\\file_23_15_30.xlsx'
For Mac/Linux: /Users/user1/file_23_15_30.xlsx
If the file has \ - it is windows, use fileSeparator as \, else use /
let path=__dirname; // or filePath
fileSeparator=path.includes('\')?"\":"/"
newFilePath = __dirname + fileSeparator + "fileName.csv";

Use path module
const path = require("path");
var str = "test\test1 (1).txt";
console.log(str.split(path.sep)) // This is only on Windows

Related

How to read from a specified file which is in a folder below without knowing the absolute path

So I have my project directory:
Here I read ArticleFile:
function _getDataFromFile() {
var jsonArray = csvjson.toObject(fs.readFileSync('ArticleFile.csv', { encoding: 'utf8' }));
var result = [];
for (var idx = 0; idx < jsonArray.length; idx++) {
var currArt = jsonArray[idx];
// if (!checkIfElementIsArticle(currArt)) throw "loaded object IS NOT an article!";
result.push(new Article(currArt.imageLocation, currArt.title, currArt.description, parseInt(currArt.quantity),parseInt(currArt.price)));
}
return result;
}
The problem is if "ArticleFile.csv" is in lets say contentsKopie I have to know the absolute path such as : C:\Users\noone_000\Desktop\BSD\Hausübungen\WebServer\WebServer\contentsKopie\ArticleFile.csv . How can I set the path like: fs.readFileSync('/ContentsCopie/ArticleFile.csv', { encoding: 'utf8' })
PS: csvjson is a module (require("csvjson"))
When you start the path with / it is interpreted as an absolute path. If you want to open a file in sub directory, you can use ./ContentsCopie/ArticleFile.csv
The . in front of the slash means that the path is relative to the current directory.
Conversely, if you needed to go up a level you can prefix your path with ..
Isn't ./contentsKopie/ArticleFile.csv enough?
When using /contentsKopie/ArticleFile.csv it's actually looking in C:/contentsKopie/ArticleFile.csv. So you have to prepend your path with a . to tell it to start at the working directory (WebServer here).
Otherwise, you can have the absolute path of the current file with __dirname then you could compose your path using the path module from node.
var path = require('path');
var article = path.join(__dirname, './contentsKopie/ArticleFile.csv');
This way, you'll get the absolute path of your file.

Denormalizing path separator in Node.js under Windows

In Windows, path module of Node.js produces all paths with backslash. It seems like it calls its own normalize() function when other functions (like resolve()) are called.
Is there a way to de-normalize the paths (with forward slash), without explicit replacement all over the place?
I tried setting path.sep = '/', but resolve() still produces paths with \\.
You can path.sep or path.parse to disassemble path and then join it as you like.
I had that problem with Windows 10. I resolved it with this script:
var path = require('path');
path.join2 = path.join;
path.sep = '/';
path.join = function(){
var res = path.join2.apply({}, arguments);
res = res.replace(/\\/g, path.sep);
return res;
}
//rest of your code

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 use require("path").join to safely concatenate urls?

Is this safe to use require("path").join to concatenate URLs, for example:
require("path").join("http://example.com", "ok");
//returns 'http://example.com/ok'
require("path").join("http://example.com/", "ok");
//returns 'http://example.com/ok'
If not, what way would you suggest for doing this without writing code full of ifs?
No. path.join() will return incorrect values when used with URLs.
It sounds like you want new URL(). From the WHATWG URL Standard:
new URL('/one', 'http://example.com/').href // 'http://example.com/one'
new URL('/two', 'http://example.com/one').href // 'http://example.com/two'
Note that url.resolve is now marked as deprecated in the Node docs.
As Andreas correctly points out in a comment, url.resolve (also deprecated) would only help if the problem is as simple as the example. url.parse also applies to this question because it returns consistently and predictably formatted fields via the URL object that reduces the need for "code full of ifs". However, new URL() is also the replacement for url.parse.
No, you should not use path.join() to join URL elements.
There's a package for doing that now. So rather than reinvent the wheel, write all your own tests, find bugs, fix them, write more tests, find an edge case where it doesn't work, etc., you could use this package.
url-join
https://github.com/jfromaniello/url-join
Install
npm install url-join
Usage
var urljoin = require('url-join');
var fullUrl = urljoin('http://www.google.com', 'a', '/b/cd', '?foo=123');
console.log(fullUrl);
Prints:
'http://www.google.com/a/b/cd?foo=123'
This can be accomplished by a combination of Node's path and URL:
Require the packages:
const nodeUrl = require('url')
const nodePath = require('path')
Start by making a URL object to work with:
> const myUrl = new nodeUrl.URL('https://example.com')
Use pathname= and path.join to construct any possible combination:
> myUrl.pathname = nodePath.join('/search', 'for', '/something/')
'/search/for/something/'
(you can see how liberal path.join is with arguments)
At this point your URL reflects the ultimate desired result:
> myUrl.toString()
'https://example.com/search/for/something/'
Why this approach?
This technique uses built-in libraries. The less third-party dependencies the better, when it comes to CVEs, maintenance, etc.
Nothing will be more proven or better tested than standard libs.
PS: Never manipulate URLs as strings!
When I review code I'm adamant about never manipulating URLs as strings manually. For one, look how complicated the spec is.
Secondly, the absence/presence of a trailing/prefixed slash (/) should not cause everything to break! You should never do:
const url = `${baseUrl}/${somePath}`
and especially not:
uri: host + '/' + SAT_SERVICE + '/' + CONSTELLATION + '/',
Of which I have seen.
Axios has a helper function that can combine URLs.
function combineURLs(baseURL, relativeURL) {
return relativeURL
? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
: baseURL;
}
Source:
https://github.com/axios/axios/blob/fe7d09bb08fa1c0e414956b7fc760c80459b0a43/lib/helpers/combineURLs.js
The WHATWG URL object constructor has a (input, base) version, and the input can be relative using /, ./, ../. Combine this with path.posix.join and you can do anything:
const {posix} = require ("path");
const withSlash = new URL("https://example.com:8443/something/");
new URL(posix.join("a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/something/a/b/c'
new URL(posix.join("./a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/something/a/b/c'
new URL(posix.join("/a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/a/b/c'
new URL(posix.join("../a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/a/b/c'
const noSlash = new URL("https://example.com:8443/something");
new URL(posix.join("./a", "b", "c"), noSlash).toString(); // 'https://example.com:8443/a/b/c'
No! On Windows path.join will join with backslashes. HTTP urls are always forward slashes.
How about
> ["posts", "2013"].join("/")
'posts/2013'
When I tried PATH for concatenating url parts I run into problems.
PATH.join stripes '//' down to '/' and this way invalidates an absolute url (eg. http://... -> http:/...).
For me a quick fix was:
baseurl.replace(/\/$/,"") + '/' + path.replace(/^\//,"") )
or with the solution posted by Colonel Panic:
[pathA.replace(/^\/|\/$/g,""),pathB.replace(/^\/|\/$/g,"")].join("/")
We do it like this:
var _ = require('lodash');
function urlJoin(a, b) {
return _.trimEnd(a, '/') + '/' + _.trimStart(b, '/');
}
If you're using lodash, you can use this simple oneliner:
// returns part1/part2/part3
['part1/', '/part2', '/part3/'].map((s) => _.trim(s, '/')).join('/')
inspired by #Peter Dotchev's answer
If you use Angular, you can use Location:
import { Location } from '#angular/common';
// ...
Location.joinWithSlash('beginning', 'end');
Works only on 2 arguments though, so you have to chain calls or write a helper function to do that if needed.
This is what I use:
function joinUrlElements() {
var re1 = new RegExp('^\\/|\\/$','g'),
elts = Array.prototype.slice.call(arguments);
return elts.map(function(element){return element.replace(re1,""); }).join('/');
}
example:
url = joinUrlElements(config.mgmtServer, '/v1/o/', config.org, '/apps');
There are other working answers, but I went with the following. A little path.join/URL combo.
const path = require('path');
//
const baseUrl = 'http://ejemplo.mx';
// making odd shaped path pieces to see how they're handled.
const pieces = ['way//', '//over/', 'there/'];
//
console.log(new URL(path.join(...pieces), baseUrl).href);
// http://ejemplo.mx/way/over/there/
// path.join expects strings. Just an example how to ensure your pieces are Strings.
const allString = ['down', 'yonder', 20000].map(String);
console.log(new URL(path.join(...allString), baseUrl).href);
// http://ejemplo.mx/down/yonder/20000
By the time posting this answer url.resolve() is deprecated;
I did following to join to path in Nodejs:
const path = require('path');
const url = require('url');
let myUrl = new URL('http://ignore.com');
myUrl.pathname=path.join(firstpath, secondpath);
console.log(myUrl.pathname)
This approach logs correct url path and it works for my case.
What is your opinion about this approach?
Thanks
Typescript custom solution:
export function pathJoin(parts: string[], sep: string) {
return parts
.map(part => {
const part2 = part.endsWith(sep) ? part.substring(0, part.length - 1) : part;
return part2.startsWith(sep) ? part2.substr(1) : part2;
})
.join(sep);
}
expect(pathJoin(['a', 'b', 'c', 'd'], '/')).toEqual('a/b/c/d');
expect(pathJoin(['a/', '/b/', 'c/', 'd'], '/')).toEqual('a/b/c/d');
expect(pathJoin(['http://abc.de', 'users/login'], '/')).toEqual('http://abc.de/users/login');
My solution
path.join(SERVER_URL, imageAbsolutePath).replace(':/','://');
Edit: if you want to support windows enviroments
path.join(SERVER_URL, imageAbsolutePath).replace(/\\/g,'/').replace(':/','://');
The second solution will replace all the backslashes, so url parts like querystring and hash may be altered too, but the topic is joining just the url path, so I don't consider it an issue.
The combination of the built-in path and URL libraries provides the best solution.
The answers above, however, do not handle the case where you have a relative url (ie: "../foo") that you want to add to an existing URL (ie: "http://example.com/test/bar"). Simply doing new URL("../foo","http://example.com/test/bar").href would yield "http://example.com/foo", erroneously (for me) discarding the remainder of the original path.
A simple solution is:
var base = "http://example.com:8080/foo/bar";
var rel = "../test";
var resolved = new URL( path.resolve(new URL(base).pathname, rel ), base ).href;
// Result: http://example.com:8080/foo/test
Note: If you care about URL Search Params (which seems unlikely in this scenario), you would save each of the pieces above to discrete variables and set the new url.searchParams = oldUrl.searchParams before getting the href output.

Meteor project path from a smartpackage

I was looking for a way to look up the meteor project path from a smart package (e.g.: obtain the path of the directory where the .meteor folder is ...).
I was not able to do it using node's __dirname and __filename because somehow in meteor they are not avaiable.
Any tips ?
As of Meteor 0.6.0 this would be:
var path = Npm.require('path');
var basepath = path.resolve('.');
From a smartpackage (0.6.5+):
var path = Npm.require('path');
var base = path.resolve('.');
base in this case gets you the position of your package ..
/User/username/projects/project/.meteor/local/programm/server/...
.. might even be deeper
but we want
/User/username/projects/project/
.. so split at .meteor
base = base.split('.meteor')[0];
Or as two-liner
var path = Npm.require('path');
var base = path.resolve('.').split('.meteor')[0];;
This works for me in Meteor 0.5.0:
var require = __meteor_bootstrap__.require;
var path = require('path');
var basepath = (path.resolve('.'));
You can actually get access to node:
var __dirname = __meteor_bootstrap__.__dirname;
You could try (only on server side)
process.env.PWD which returns something like that for me (OSX):
'/Users/myusername/Desktop/myproject'
With that command you get the root of meteor project.

Resources