While using glob patterns to find files with gulp.src, I could not see any difference in files found between ./src/**/*.js and src/**/*.js globs. What is the purpose of the ./ if there is any at all?
It's being explicit about the path beginning from the local directory. It's usually redundant, but for some shells, with certain commands, they may allow it to use different behaviors if the ./ isn't supplied, e.g. with zsh and the cd command, it will treat cd ./foo as "only go to foo if it is a subdirectory of the current directory", while cd foo will check CDPATH for alternate targets.
Related
I want use ./src/**/*.js to match every js file in ./src folder,no matter how deep the file path is.
so I run ls ./src/**/*.js in the shell and the wildcards behave as I expected, js files like ./src/path1/a.js ./src/path1/path2/b.js and both matched.
And then I add npm script in package.json
{
scripts: {
"test": "ls ./src/**/*.js"
}
}
run npm run test. But now only files like ./src/pah1/a.js are matched.
I don't know why same wildcards behave differently.Can anyone tell me what is the right wildcards that I can use to match every js files in one folder.
Thank you.
They're just different. Shells don't expand **. Try find ./src -name '*.js', instead.
If you run this command in a Linux terminal:
mkdir -p ./dist/{articles,scripts,stylesheets}
It'll create the following folder tree (in the current directory):
dist
|- articles
|- scripts
|- stylesheets
The problem occurs when I try to do the same using the shelljs npm package.
For example, calling the following function:
shell.mkdir("-p", "./dist/{articles,scripts,stylesheets}");
Results in the following file tree being created:
dist
|- {articles,scripts,stylesheets}
In other words, it's a folder called dist that contains a subfolder called {articles,scripts,stylesheets}.
I've tried escaping the curly braces, like this:
shell.mkdir("-p", "./dist/\{articles,scripts,stylesheets\}");
It didn't work, so I doubled down and escaped the backslash:
shell.mkdir("-p", "./dist/\\{articles,scripts,stylesheets\\}");
That didn't work either, so I doubled down again and added an escaped backslash before the escaped backslash:
shell.mkdir("-p", "./dist/\\\\{articles,scripts,stylesheets\\\\}");
Which didn't work, but it did create a folder with a different name:
\\{articles,scripts,stylesheets\\}
How can I fix this problem?
The correct way is to rewrite brace expansion using loops or similar:
const shell = require('shelljs')
for(var dir of ["articles", "scripts", "stylesheets"]) {
shelljs.mkdir("-p", "./dist/" + dir)
}
This is fast, robust and portable.
Equivalently, you can use a third party library that expands them for you:
const shell = require('shelljs')
const braces = require('braces')
shell.mkdir("-p", braces("./dist/{articles,scripts,stylesheets}", {expand: true}))
The literal way is to explicitly invoke Bash, since brace expansion is a bash feature:
shelljs.exec("bash -c 'mkdir -p ./dist/{articles,scripts,stylesheets}'")
This is slow, fragile and non-portable because it requires two invocations of two Unix shells and two corresponding levels of escaping.
The point of shelljs is to replace such code with pure JS implementations so that it requires zero invocations of zero shells, so this entirely defeats the purpose of using it in the first place.
shelljs mkdir() command takes as parameter a list or an array of directory names. It will not attempt to execute any command or sequence builder utility provided by bash, as we can see in source code. So there is no point to try to escape the braces.
Instead you could send the raw command with exec():
shell.exec("bash -c 'mkdir -p ./dist/{articles,scripts,stylesheets}'")
I made a React app using Create-React-App. I have a testing script in my React app's package.json like this:
"test": "node -r #babel/register -r #babel/polyfill **/*.test.js | tap-color",
This catches and executes the files in src/ like src/App.test.js, but not header.test.js in src/layout/header/header.test.js. And what if I add even more layers of folders? Is there a regex that will catch all folders in src/ and their subfolders no matter how nested with a file ending of .test.js?
Edit: I found this question on StackOverflow. According to that answer you would have to write:
"test": "node -r #babel/register -r #babel/polyfill 'src/**/*.test.js' | tap-color",
which unfortunately matches nothing for me. I'm on Mac.
The question you refer to is not especially useful for your case. My answer there works because Mocha has been designed to pass the patterns you give to it to the glob library for interpretation. So when you do mocha 'src/app/**/*.tests.js' the quotes prevent the shell from interpreting the pattern, Mocha gets src/app/**/*.tests.js as the first pattern given to it, which it gives to glob to get a list of files to actually run. Your case is different at least one crucial way: glob is not involved so there is nothing that can correctly interpret **.
Your first attempt is consistent with what happens when you are using a shell that does not understand **. It is interpreted exactly the same as *. So the shell interprets **/*.test.js as */*.test.js, expands this pattern and passes the result to node.
In your second attempt, you quote the pattern but that does not help you because node does not do pattern interpretation. It tries to load a file at path src/**/*.test.js, interpreted literally. This is not what you want.
I'm not sure what the compatibility implication with Windows are, but you could replace 'src/**/*.test.js' with $(find src -type f -name '*.test.js'). (See the man page for details.) At run-time, the shell will replace this with the result of the find command.
Or for greater simplicity, and less risk of platform issues creeping up, you could use babel-tap like this:
babel-tap 'src/**/*.test.js' | tap-color
If you use babel-tap, there's actually no need for using find because internally babel-tap calls on facilities that use the glob library to interpret the file names passed to it.
I've focused on the file pattern issue but I'm not seeing how what you're trying to do would work, even without the pattern issue. Consider this command, and assume that the files exist:
node -r #babel/register -r #babel/polyfill src/a.test.js src/b.test.js
This is not telling Node to run src/a.test.js and src/b.test.js. Rather, it tells node "run the script src/a.test.js and pass to it the parameter src/b.test.js". I've not used tap very much but I don't recall it working this way. Using babel-tap like I show above also avoids the problem here.
In my npm package, I would like to emulate the pattern Meteor follows: a source file (named client.js) has a test file (named client.tests.js) live in a src/ folder. Tests run with the npm test command.
I'm following the usage docs to the 't'. I do not want to use a find in my package test command.
I understand that mocha can recursively execute tests:
mocha --recursive
I understand that mocha can execute tests in a specific subfolder using the --recursive flag:
mocha src --recursive
I also understand that I can specify a glob to filter files by passing *.tests.js:
mocha *.tests.js
But, I want all three. I want mocha to test only files ending in tests.js in the src folder, recursively checking subdirectories.
mocha --recursive *.tests.js
// See the files?
$ > ll ./src/app/
total 168
-rw-r--r-- ... client.js
-rw-r--r-- ... client.tests.js
// Option A
$ > mocha --recursive *.tests.js
Warning: Could not find any test files matching pattern: *.tests.js
No test files found
// Option B
$ > mocha *.tests.js --recursive
Warning: Could not find any test files matching pattern: *.tests.js
No test files found.
// Option C
$ > mocha --recursive src/app/*.tests.js
3 passing (130ms)
3 failing
So...
Why is mocha not picking up the *.tests.js files in the subfolders?
Why DOES it work if I specify the full path to the file?
How do I make it work as desired?
The --recursive flag is meant to operate on directories. If you were to pass a glob that matches directories, then these directories would be examined recursively but if you pass a glob that matches files, like you are doing, then --recursive is ineffective. I would suggest not using --recursive with a glob because globs already have the capability to look recursively in subdirectories. You could do:
mocha 'src/app/**/*.tests.js'
This would match all files that match *.tests.js recursively in src/app. Note how I'm using single quotes around the pattern. This is to quote the pattern so that it is passed as-is to Mocha's globbing code. Otherwise, your shell might interpret it. Some shells, depending on options, will translate ** into * and you won't get the results you want.
I have some nodejs code running in a module somewhere. From this module, I would like to load a module located in a completely different place in the file system -- for example, given the path "/another/dir" and the module name "foo", I would like Node to act as if a module running in /another/dir had called require("foo"), rather than my own module.
My code is running here
/some/folder/node_modules/mine/my_module.js
I have the path "/another/dir/", the string "foo",
and want to load this module
/another/dir/node_modules/foo/index.js
In other words, the module documentation refers to the process "require(X) from module at path Y", and I would like to specify my own value for Y
Can this be accomplished? If so, how? If not, why not?
The simplest, is just to resolve the path into an absolute path, this will be the recommended approach for most if not all cases.
var path = require('path');
var basedir = '/another/dir';
var filename = 'foo'; // renamed from dirname
var filepath = path.join(basedir, 'node_modules', filename);
var imports = require(filepath);
If you really need to make require act as if it is in a different directory,
you can push the base directory to module.paths
module.paths.unshift('/another/dir/node_modules');
var imports = require('foo');
module.paths.shift();
module.paths can also be modified externally via the environment variable NODE_PATH, tho that would be the least recommended approach but this does apply it globally across all modules.
A symlink with npm link
To avoid problems or modify source code I would use npm link, from your example:
First:
cd /another/dir/node_modules/foo # go into the package directory
npm link # creates global link
This will create a global link for the foo module, on Linux you need root permissions to do this.
Then:
cd /some/folder/ # go into some other package directory.
npm link foo # link-install the package
/some/folder/package.json should contain foo as a dep, is not mandatory, without it you get an extraneous warning with npm ls:
"dependencies": {
[...]
"foo": "*"
}
No symlink with local NODE_PATH
You don't like symlinks ? You can still use NODE_PATH but locally instead setting a global variable as #rocketspacer suggested, because as he rightly stated, it's not recommended to use it globally.
Note: In any case I would use a User variable and not a System-wide variable, a co-worker could log with a different username on the same machine and still get a modified NODE_PATH.
But to do this locally for just one invocation on Linux you can simply call:
NODE_PATH=$NODE_PATH:/another/dir/node_modules npm start
It will use that NODE_PATH only for that invocation.
Same one time invocation on Windows:
#ECHO OFF
SET BASE_NODE_PATH=%NODE_PATH%
SET NODE_PATH=%BASE_NODE_PATH%;C:\another\dir\node_modules\
node index.js
SET NODE_PATH=%BASE_NODE_PATH%
And...
You could also use a local dep like:
"dependencies": {
"foo": "file:/another/dir/node_modules/foo"
}
But would require an npm install and it would copy the content of foo in the current package node_modules folder.
It's quite easy to achieve, just add absolute paths to module object
in your current script /some/folder/node_modules/mine/my_module.js add this
module.paths.push('/another/dir/node_modules');
//this must be absolute, like /Users/John/another/dir/node_modules
var foo = require('foo');
For demo, open node in terminal, and type module.paths, it will show all the path node will search for require, you just add your path
"require(X) from module at path Y"
Means calling require(X) from within a file located at path Y. So you practically can't change Y.
Although the above solutions work (modifying module.paths & requiring absolute path), you'll have to add those snippets to every file in your project where you need requiring the foreign modules.
Even more, modifying module.paths is not officially supported. So it's not guaranteed to work in future updates of node
Introducing NODE_PATH
NODE_PATH is an environment variable that is set to a colon-delimited list of absolute paths.
Within those absolute paths, Node.js will search for a module that matches your require statement when all else has failed (Having indexed node_modules up to File System Root and still no match was found)
It is officially supported, although not recommended as it goes against convention (Your co-worker may not be aware of the NODE_PATH usage as there is no descriptive way of telling that in your project itself)
Notes:
On Windows, NODE_PATH is delimited by semicolons instead of
colons.
Node doesn't look for node_modules within those paths like
its default behavior, so your paths should be exactly where you
contain needed modules. For example: "/another/dir/node_modules"
Detailed information can be found on NodeJs official document:
https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
For those of you who are unaware of what environment variables is and how to set them, I have a windows screenshot that will get you started
In simple lines, u can call your own folder as module :
For that we need: global and app-module-path module
here "App-module-path" is the module ,it enables you to add additional directories to the Node.js module search path And "global" is, anything that you attach to this object will b available everywhere in your app.
Now take a look at this snippet:
global.appBasePath = __dirname;
require('app-module-path').addPath(appBasePath);
__dirname is current running directory of node.You can give your own path here to search the path for module.