Why do we write dots (.) in path.resolve()? - node.js

The code shown below are examples used to explain path.resolve() on https://nodejs.org/api/path.html
path.resolve('/foo/bar', './baz');
// Returns: '/foo/bar/baz'
path.resolve('/foo/bar', '/tmp/file/');
// Returns: '/tmp/file'
path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
// If the current working directory is /home/myself/node,
// this returns '/home/myself/node/wwwroot/static_files/gif/image.gif'
I noticed that all dots are just omited.
./baz is converted to baz in the first example.
../gif/image.gif is converted to /gif/image.gif in the 3rd example.
Then, why bother writing these dots?
What would happen if these dots didn't exist in the two examples?
Thx!

The path.resolve() method is used to resolve a sequence of path-segments to an absolute path.
It works by processing the sequence of paths from right to left, prepending each of the paths until the absolute path is created. The resulting path is normalized and trailing slashes are removed as required.
If no path segments are given as parameters, then the absolute path of the current working directory is used.
The passed argument is a series of file paths that would be resolved together to form an absolute path.

Related

Node.js path.join() ignoring parameter

According to the documentation:
The path.join() method joins all given path segments together using
the platform-specific separator as a delimiter, then normalizes the
resulting path.
Zero-length path segments are ignored. If the joined path string is a
zero-length string then '.' will be returned, representing the current
working directory.
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// Returns: '/foo/bar/baz/asdf'
path.join('foo', {}, 'bar');
// Throws 'TypeError: Path must be a string. Received {}'
A TypeError is thrown if any of the path segments is not a string.
Am I missing something? Why is:
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// Returns: '/foo/bar/baz/asdf'
Ignoring 'quux' and '..' ?
They're are not zero length?
Even played around in the REPL (see screenshot)
Path.join isn't ignoring the last two parameters. Path.join takes the parameters you input and outputs a normalized path in string format.
So what's actually going on here is that it's constructing your string to form a path left to right, /foo/bar/baz/asdf/quux/, and the last parameter (..) is instructing path.join to 'go back a directory'. So your final result will be: /foo/bar/baz/asdf/
Part 1: what do you expect to happen when you provide an object instead of a string? To cut it short: It doesn’t make sense and hence doesn’t work.
Part 2: since .. means „up one directory“, this clears the last part of the path, hence it seems to not have any effect. Actually, it doesn’t get ignored - it’s just that the last two parameters clear each other.
With regard to path.join('foo', {}, 'bar');, {} represents an empty object, not a string (empty or not). Therefore, it is an invalid parameter for path.join().
With regard to path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');, .. refers to a parent directory.
Through experimentation in a terminal, you will find that...
/foo/bar/baz/asdf/quux/.. is equivalent to /foo/bar/baz/asdf

Change Image source in Markdown text using Node JS

I have some markdown text containing image references but those are relative paths & I need to modify those to absolute paths using NodeJS script. Is there any way to achieve the same in simple way ?
Example:
Source
![](myImage.png?raw=true)
Result
![](www.example.com/myImage.png?raw=true)
I have multiple images in the markdwon content that I need to modify.
Check this working example: https://repl.it/repls/BlackJuicyCommands
First of all you need the read the file with fs.readFile() and parse the Buffer to a string.
Now you got access to the text of the file, you need the replace every image path with a new image path. One way to capture it is with a regular expression. You could for example look for ](ANY_IMAGE_PATH.ANY_IMAGE_EXTENSION. We're only interested in replacing the ANY_IMAGE_PATH part.
An example regex could be (this could be improved!) (see it live in action here: https://regex101.com/r/xRioBq/1):
const regex = /\]\((.+)(?=(\.(svg|gif|png|jpe?g)))/g
This will look for a literal ] followed by a literal ( followed by any sequence (that's the .+) until it finds a literal . followed by either svg, gif,png, or jpeg / jpg. the g after the regex is necessary to match all occurences, not only the first.
Javascript/node (< version 9) does not support lookbehind. I've used a regex that includes the ]( before the image path and then will filter it out later (or you could use a more complex regex).
The (.+) captures the image path as a group. Then you can use the replace function of the string. The replace function accepts the regex as first argument. The second argument can be a function which receives as first argument the full match (in this case ](image_path_without_extension and as the following arguments any captured group.
Change the url with the node modules path or url and return the captured group (underneath I've called that argument imagePath). Because we're also replacing the ](, that should be included in the return value.
const url = require('url');
const replacedText = data.toString().replace(regex, (fullResult, imagePath) => {
const newImagePath = url.resolve('http://www.example.org', imagePath)
return `](${newImagePath}`;
})
See the repl example to see it live in action. Note: in the repl example it is written to a different file. Use the same file name if you want to overwrite.
I ran into the same issue yesterday, and came up with this solution.
const markdownReplaced = markdown.replace(
/(?<=\]\()(.+)(?=(\)))/g,
(url) => `www.example.com/${url}`,
);
The regex finds anything starts with ]( and ends with ), without including the capturing group, which is the original URL itself.

What's the difference between path.resolve and path.join?

Is there some difference between the following invocations?
path.join(__dirname, 'app')
vs.
path.resolve(__dirname, 'app')
Which one should be preferred?
The two functions deal with segments starting with / in very different ways; join will just concatenate it with the previous argument, however resolve will treat this as the root directory, and ignore all previous paths - think of it as the result of executing cd with each argument:
path.join('/a', '/b') // Outputs '/a/b'
path.resolve('/a', '/b') // Outputs '/b'
Another thing to note is that path.resolve will always result in an absolute URL, and will use your working directory as a base to resolve this path. But as __dirname is an absolute path anyway this doesn't matter in your case.
As for which one you should use, the answer is: it depends on how you want segments starting in / to behave - should they be simply joined or should they act as the new root?
If the other arguments are hard coded it really doesn't matter, in which case you should probably consider (a) how this line might change in future and (b) how consistent is it with other places in the code.
The default operations of file system path vary based on the operating system we need some thing that abstract it.
The path module provides utilities or API for working with file and directory
paths.
you can include it in your project using
const path = require('path');
The path.join and path.resolve are two different methods of the path module.
Both these methods accept a sequence of paths or path segments.
The path.resolve() method resolves a sequence of paths or path segments into an absolute path.
The path.join() method joins all given path segments together using the platform specific separator as a delimiter, then normalizes the resulting path.
In order to better understand and differentiate behaviours, let me explain it with different scenarios.
1. If we don't supply any arguments to or empty string
in my case, my filename is index.js and the current working directory is E:\MyFolder\Pjtz\node
const path = require('path');
console.log("path.join() : ", path.join());
// outputs .
console.log("path.resolve() : ", path.resolve());
// outputs current directory or equalent to __dirname of the node process
and on running result is as below
λ node index.js
path.join() : .
path.resolve() : E:\MyFolder\Pjtz\node
The inference from above experiment is tha path.resolve() method will output the absolute path where as the path.join() returns . representing the current working directory or relative path if nothing is provided
2. Adding a /path as any of arguments.
const path=require('path');
console.log("path.join() : " ,path.join('abc','/bcd'));
console.log("path.resolve() : ",path.resolve('abc','/bcd'));
and the result is
λ node index.js
path.join() : abc\bcd
path.resolve() : E:\bcd
The inference we can found with this experiment is that path.join() only concatenates the input list with platform specific separator while the path.resolve() process the sequence of paths from right to left, with each subsequent path prepended until an absolute path is constructed.
path.join() concatenates each argument with OS specific separators while path.resolve() will resolve each argument with root and produce output.
1) path.resolve creates the absolute path.
The method creates absoulte path from right to left until an absolute path is constructed.
For example:
path.resolve('/a', 'b', 'c'); // C:\a\b\c
path.resolve('/a', '/b', 'c'); // C:\b\c
path.resolve('/a', '/b', '/c'); // C:\c
If absolute path is not generated, the method using current working directory:
For example:
path.resolve('a', 'b', 'c'); // C:\{current_working_directory}\a\b\c
2) path.join joins all path and the normalize the result
For example:
path.join('/a', '/b', '/c'); // \a\b\c
path.join('/a', '/b', 'c'); // \a\b\c
path.join('/a', 'b', 'c'); // \a\b\c
path.join('a', 'b', 'c'); // a\b\c
EDIT: updated example above suggested by #spmdc
In Simplest` Terms:
path.resolve() just does the following
from left to right-
concatenate the right most parameters with / directly with the root path to make an absolute path (check the examples)
and then concatenates anything without / as a directory
using sergey's example
path.resolve('/a', 'b', 'c'); returns C:\a\b\c
path.resolve('/a', '/b', 'c'); returns C:\b\c
path.resolve('/a', '/b', '/c'); returns C:\c
While join simply concatenates every parameter from left to right whether they have / or not
path.join("/a", "b", "/c", "d") simply returns "\a\b\c\d"

Node Path Normalise trailing periods .. and

Can anyone explain to me why this holds true:
Normalize a string path, taking care of '..' and '.' parts.
When multiple slashes are found, they're replaced by a single one;
when the path contains a trailing slash, it is preserved. On Windows
backslashes are used.
Example:
path.normalize('/foo/bar//baz/asdf/quux/..')
// returns '/foo/bar/baz/asdf'
When I would expect it to return
'/foo/bar/baz/asdf/quux'
This is from the Node Documentation
http://nodejs.org/api/path.html#path_path_normalize_p
Edit
After running some test I know "why" this is happening, but do not understand the logic behind it.
Below are three examples with their input and output.
/foo/bar//baz/asdf/quux/.. /foo/bar//baz/asdf
/foo/bar//baz/asdf/quux/. /foo/bar//baz/asdf/quux
/foo/bar//baz/asdf/quux/ /foo/bar//baz/asdf/quux/
So for the original I can see that the double period ".." removed the final folder and the single period "." removes the trailing slash. I understand that when including files in parental folders you would prefix a path with ../ I am assuming that you can actually place this anywhere within a path, although there seems little point to me currently to be able to place it say mid path.
A double colon (..) means the parent directory as is standard in Linux. So, /foo/bar//baz/asdf/quux/.. basically selects the parent directory of /foo/bar//baz/asdf/quux

Difference between path.normalize and path.resolve in Node.js

What is the difference (if any) between path.normalize(your_path) and path.resolve(your_path)?
I know path.resolve(...) can accept multiple arguments, but is the behavior with a single argument the same as calling path.normalize()?
EDIT: If they are supposed to behave the same way, I don't understand the purpose of exposing the path.normalize(...) function when you can simply pass the path into path.resolve(...) Or, maybe, it's for documentation purposes. For example, they say in the documentation for path.resolve(...):
... The resulting path is normalized, and ...
Exposing the path.normalize(...) makes it easier to explain what "normalized" means? I don't know.
path.normalize gets rid of the extra ., .., etc. in the path. path.resolve resolves a path into an absolute path. Example (my current working directory was /Users/mtilley/src/testing):
> path.normalize('../../src/../src/node')
'../../src/node'
> path.resolve('../../src/../src/node')
'/Users/mtilley/src/node'
In other words, path.normalize is "What is the shortest path I can take that will take me to the same place as the input", while path.resolve is "What is my destination if I take this path."
Note however that path.normalize() is much more context-independent than path.resolve(). Had path.normalize() been context-dependent (i.e. if it had taken into consideration the current working directory), the result in the example above would've been ../node, because that's the shortest path one could take from /Users/mtilley/src/testing to /Users/mtilley/src/node.
Ironically, this means that path.resolve() produces a relative path in absolute terms (you could execute it anywhere, and it would produce the same result), whereas path.normalize() produces an absolute path in relative terms (you must execute it in the path relative to which you want to calculate the absolute result).
From the docs:
Another way to think of resolve is as a sequence of cd commands in a shell.
Links to path.resolve and path.normalize in the documentation. I mostly don't want to just provide links in an answer but the Node.js docs are very decent.

Resources