Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
416 views
in Technique[技术] by (71.8m points)

node.js - npm glob pattern not matching subdirectories

In my package.json, I have a scripts block that uses **/*Test.js to match files. When run via npm, they do not match sub-directories more than one level. When executed on the command line directly, they work as expected.

Can anyone explain what is happening, and provide a workaround or solution?

package.json

{
  "name": "immutable-ts",
  "scripts": {
    "test": "echo mocha dist/**/*Test.js",
  }
}

Execution

% npm run test

> immutable-ts@0.0.0 test:unit .../immutable-ts
> echo mocha dist/**/*Test.js

mocha dist/queue/QueueTest.js dist/stack/StackTest.js

% echo mocha dist/**/*Test.js

mocha dist/queue/QueueTest.js dist/stack/StackTest.js dist/tree/binary/BinaryTreeTest.js

% ls dist/**/*                                                                                                                                                                                          

dist/collections.js  dist/queue/QueueTest.js  dist/tree/binary/BinaryTree.js      dist/immutable.js.map        dist/stack/Stack.js.map             dist/tree/binary/BinaryTreeTest.js.map
dist/immutable.js    dist/stack/Stack.js      dist/tree/binary/BinaryTreeTest.js  dist/queue/Queue.js.map      dist/stack/StackTest.js.map
dist/queue/Queue.js  dist/stack/StackTest.js  dist/collections.js.map             dist/queue/QueueTest.js.map  dist/tree/binary/BinaryTree.js.map
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Solution

Change your scripts so that what you pass to Mocha is protected from expansion by the shell:

"scripts": {
    "test": "mocha 'dist/**/*Test.js'",
 }

Note the single quotes around the parameter given to mocha.

Explanation

This issue is fixable without resorting to external tools. The root cause of your problem is that by npm uses sh as the shell that will run your script commands.

It is overwhelmingly the case that when a *nix process starts a shell it will start sh unless there is something telling it to do otherwise. The shell preference you set for logins does not constitute a way to "tell it otherwise". So if you have, say, zsh as your login shell, it does not entail that npm will use zsh.

Those implementations of sh that do not include any extensions beyond what sh should provide do not understand the ** glob in the way you want it to. As far as I can tell, it is interpreted as *. However, Mocha interprets the paths passed to it using its a JavaScript implementation of globs. So you can work around the issue by protecting your globs from being interpreted by sh. Consider the following package.json:

{
  "name": "immutable-ts",
  "scripts": {
    "bad": "mocha test/**/*a.js",
    "good": "mocha 'test/**/*a.js'",
    "shell": "echo $0"
  }
}

The shell script is just so that we can check what shell is running the script. If you run it, you should see sh.

Now, given the following tree:

test/
├── a.js
├── b.js
├── x
│?? ├── a
│?? │?? ├── a.js
│?? │?? └── b.js
│?? ├── a.js
│?? └── b
│??     └── a.js
└── y
    ├── a.js
    └── q

With all a.js and b.js files containing it(__filename);. You get the following results:

$ npm run bad

> immutable-ts@ bad /tmp/t2
> mocha test/**/*a.js

  - /tmp/t2/test/x/a.js
  - /tmp/t2/test/y/a.js

  0 passing (6ms)
  2 pending

$ npm run good

> immutable-ts@ good /tmp/t2
> mocha 'test/**/*a.js'

  - /tmp/t2/test/a.js
  - /tmp/t2/test/x/a.js
  - /tmp/t2/test/x/a/a.js
  - /tmp/t2/test/x/b/a.js
  - /tmp/t2/test/y/a.js

  0 passing (5ms)
  5 pending

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...