forked from yarnpkg/yarn
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbin-links.js
128 lines (113 loc) · 6.34 KB
/
bin-links.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* @flow */
import * as fs from '../../../src/util/fs.js';
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150000;
const request = require('request');
const path = require('path');
import {runInstall} from '../_helpers.js';
async function linkAt(config, ...relativePath): Promise<string> {
const joinedPath = path.join(config.cwd, ...relativePath);
const stat = await fs.lstat(joinedPath);
if (stat.isSymbolicLink()) {
const linkPath = await fs.readlink(joinedPath);
return linkPath;
} else {
const contents = await fs.readFile(joinedPath);
return /node" +"\$basedir\/([^"]*\.js)"/.exec(contents)[1];
}
}
beforeEach(request.__resetAuthedRequests);
afterEach(request.__resetAuthedRequests);
test('install should hoist nested bin scripts', (): Promise<void> => {
return runInstall({binLinks: true}, 'install-nested-bin', async (config) => {
const binScripts = await fs.walk(path.join(config.cwd, 'node_modules', '.bin'));
// need to double the amount as windows makes 2 entries for each dependency
// so for below, there would be an entry for eslint and eslint.cmd on win32
const amount = process.platform === 'win32' ? 20 : 10;
expect(binScripts).toHaveLength(amount);
expect(await linkAt(config, 'node_modules', '.bin', 'standard'))
.toEqual('../standard/bin/cmd.js');
expect(await linkAt(config, 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
});
});
// dependency tree:
// eslint@3.7.0
// standard
// standard -> eslint@3.7.1
// result should be:
// eslint 3.7.0 is linked in /.bin because it takes priority over the transitive 3.7.1
// eslint 3.7.1 is linked in standard/node_modules/.bin
test('direct dependency bin takes priority over transitive bin', (): Promise<void> => {
return runInstall({binLinks: true}, 'install-duplicate-bin', async (config) => {
expect(await linkAt(config, 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
expect(await linkAt(config, 'node_modules', 'standard', 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
});
});
test.concurrent('install should respect --no-bin-links flag', (): Promise<void> => {
return runInstall({binLinks: false}, 'install-nested-bin', async (config) => {
const binExists = await fs.exists(path.join(config.cwd, 'node_modules', '.bin'));
expect(binExists).toBeFalsy();
});
});
// Scenario: Transitive dependency having version that is overridden by newer version as the direct dependency.
// Behavior: eslint@3.12.2 is symlinked in node_modeules/.bin
// and eslint@3.10.1 is symlinked to node_modules/sample-dep-eslint-3.10.1/node_modules/.bin
test('newer transitive dep is overridden by older direct dep', (): Promise<void> => {
return runInstall({binLinks: true}, 'install-bin-links-newer', async (config) => {
expect(await linkAt(config, 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
expect(await linkAt(config, 'node_modules', 'sample-dep-eslint-3.10.1', 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
});
});
// Scenario: Transitive dependency having version that is overridden by older version as the direct dependency.
// Behavior: eslint@3.10.1 is symlinked in node_modeules/.bin
// and eslint@3.12.2 is symlinked to node_modules/sample-dep-eslint-3.12.2/node_modules/.bin
test('newer transitive dep is overridden by older direct dep', (): Promise<void> => {
return runInstall({binLinks: true}, 'install-bin-links-older', async (config) => {
expect(await linkAt(config, 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
expect(await linkAt(config, 'node_modules', 'sample-dep-eslint-3.12.2', 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
});
});
// Scenario: Transitive dependency having version that is overridden by newer version as the dev dependency.
// Behavior: eslint@3.12.2 is symlinked in node_modeules/.bin
// and eslint@3.10.1 dependency for sample-dep-eslint-3.10.1 module is not linked.
// SKIPPED because this seems like an NPM bug more than intentional design.
// Why would it matter if the direct dependency is a dev one or not when linking the transient dep?
test.skip('transitive dep is overridden by dev dep', (): Promise<void> => {
return runInstall({binLinks: true}, 'install-bin-links-dev', async (config) => {
expect(await linkAt(config, 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
expect(await linkAt(config, 'node_modules', 'sample-dep-eslint-3.10.1', 'node_modules', '.bin', 'eslint'))
.not.toBeDefined();
});
});
// Scenario: Transitive dependency having version that is conflicting with another transitive dependency version.
// Behavior: eslint@3.10.1 is symlinked in node_modeules/.bin
// and eslint@3.12.2 is symlinked to node_modules/sample-dep-eslint-3.12.2/node_modules/.bin.
// Here it seems like NPM add the modules in alphabatical order
// and transitive deps of first dependency is installed at top level.
test('first transient dep is installed when same level and reference count', (): Promise<void> => {
return runInstall({binLinks: true}, 'install-bin-links-conflicting', async (config) => {
expect(await linkAt(config, 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
expect(await linkAt(config, 'node_modules', 'sample-dep-eslint-3.12.2', 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
});
});
// Scenario: Transitive dependency having version that is conflicting with another dev transitive dependency version.
// Behavior: eslint@3.10.1 is symlinked in node_modeules/.bin
// and eslint@3.12.2 is symlinked to node_modules/sample-dep-eslint-3.12.2/node_modules/.bin.
// Whether the dependencies are devDependencies or not does not seem to matter to NPM.
test('first dep is installed when same level and reference count and one is a dev dep', (): Promise<void> => {
return runInstall({binLinks: true}, 'install-bin-links-conflicting-dev', async (config) => {
expect(await linkAt(config, 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
expect(await linkAt(config, 'node_modules', 'sample-dep-eslint-3.12.2', 'node_modules', '.bin', 'eslint'))
.toEqual('../eslint/bin/eslint.js');
});
});