npq 2.5.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/main.yml +1 -1
- package/.husky/commit-msg +4 -0
- package/.husky/post-merge +4 -0
- package/.husky/pre-commit +4 -0
- package/.husky/pre-push +4 -0
- package/__tests__/__fixtures__/test.marshall.js +7 -7
- package/__tests__/marshalls.classMethods.test.js +9 -9
- package/__tests__/marshalls.provenance.test.js +206 -0
- package/__tests__/marshalls.repo.test.js +4 -7
- package/__tests__/marshalls.signatures.test.js +2 -6
- package/__tests__/marshalls.tasks.test.js +2 -2
- package/__tests__/packageManager.test.js +1 -1
- package/__tests__/packageRepoUtils.test.js +6 -8
- package/lib/cliCommons.js +2 -2
- package/lib/helpers/cliSupportHandler.js +2 -6
- package/lib/helpers/packageRepoUtils.js +9 -10
- package/lib/marshall.js +11 -11
- package/lib/marshalls/age.marshall.js +3 -3
- package/lib/marshalls/author.marshall.js +4 -4
- package/lib/marshalls/baseMarshall.js +7 -7
- package/lib/marshalls/downloads.marshall.js +3 -3
- package/lib/marshalls/expiredDomains.marshall.js +7 -7
- package/lib/marshalls/index.js +11 -21
- package/lib/marshalls/license.marshall.js +3 -3
- package/lib/marshalls/provenance.marshall.js +16 -8
- package/lib/marshalls/readme.marshall.js +3 -3
- package/lib/marshalls/repo.marshall.js +4 -5
- package/lib/marshalls/scripts.marshall.js +5 -5
- package/lib/marshalls/signatures.marshall.js +5 -6
- package/lib/marshalls/snyk.marshall.js +8 -9
- package/lib/packageManager.js +4 -4
- package/package.json +39 -55
- package/scripts/postinstall.js +4 -4
- package/scripts/scriptHelpers.js +3 -2
package/.husky/pre-push
ADDED
|
@@ -5,16 +5,16 @@ const BaseMarshall = require('../../lib/marshalls/baseMarshall')
|
|
|
5
5
|
const MARSHALL_NAME = 'test.marshall'
|
|
6
6
|
|
|
7
7
|
class TestMarshall extends BaseMarshall {
|
|
8
|
-
constructor
|
|
8
|
+
constructor(options) {
|
|
9
9
|
super(options)
|
|
10
10
|
this.name = MARSHALL_NAME
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
title
|
|
13
|
+
title() {
|
|
14
14
|
return 'A test marshall'
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
run
|
|
17
|
+
run(ctx, task) {
|
|
18
18
|
const tasks = ctx.pkgs.reduce((prevPkg, currPkg) => {
|
|
19
19
|
return prevPkg.concat(this.mockCheck(currPkg, ctx, task))
|
|
20
20
|
}, [])
|
|
@@ -22,7 +22,7 @@ class TestMarshall extends BaseMarshall {
|
|
|
22
22
|
return Promise.all(tasks)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
mockCheck
|
|
25
|
+
mockCheck(pkg, ctx, task) {
|
|
26
26
|
return this.validateSomething(pkg)
|
|
27
27
|
.then(() => {
|
|
28
28
|
const data = 'mock data check'
|
|
@@ -33,13 +33,13 @@ class TestMarshall extends BaseMarshall {
|
|
|
33
33
|
})
|
|
34
34
|
.catch((err) => {
|
|
35
35
|
this.setMessage({
|
|
36
|
-
pkg
|
|
36
|
+
pkg,
|
|
37
37
|
message: err.message
|
|
38
38
|
})
|
|
39
39
|
})
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
validateSomething
|
|
42
|
+
validateSomething(pkg) {
|
|
43
43
|
if (pkg === 'express' || pkg === 'semver') {
|
|
44
44
|
return Promise.resolve()
|
|
45
45
|
} else {
|
|
@@ -47,7 +47,7 @@ class TestMarshall extends BaseMarshall {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
validate
|
|
50
|
+
validate(pkg) {
|
|
51
51
|
if (pkg === 'express' || pkg === 'semver') {
|
|
52
52
|
return Promise.resolve('validation-result')
|
|
53
53
|
} else {
|
|
@@ -2,15 +2,15 @@ beforeEach(() => {
|
|
|
2
2
|
jest.resetModules()
|
|
3
3
|
})
|
|
4
4
|
|
|
5
|
+
jest.mock('glob', () => {
|
|
6
|
+
return {
|
|
7
|
+
glob: jest.fn().mockResolvedValue(['file1', 'file2'])
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
|
|
5
11
|
test('collecting marshalls resolves with files array', async () => {
|
|
6
12
|
const marshalls = require('../lib/marshalls')
|
|
7
13
|
|
|
8
|
-
jest.mock('glob', () => {
|
|
9
|
-
return jest.fn((pattern, options, callback) => {
|
|
10
|
-
return callback(null, ['file1', 'file2'])
|
|
11
|
-
})
|
|
12
|
-
})
|
|
13
|
-
|
|
14
14
|
const marshallFiles = await marshalls.collectMarshalls()
|
|
15
15
|
expect(marshallFiles).toEqual(['file1', 'file2'])
|
|
16
16
|
})
|
|
@@ -19,9 +19,9 @@ test('collecting marshalls resolves with error if unable to process files', () =
|
|
|
19
19
|
const marshalls = require('../lib/marshalls')
|
|
20
20
|
|
|
21
21
|
jest.mock('glob', () => {
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
}
|
|
22
|
+
return {
|
|
23
|
+
glob: jest.fn().mockRejectedValue(new Error('error'))
|
|
24
|
+
}
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
expect(marshalls.collectMarshalls()).rejects.toEqual(expect.any(Error))
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
jest.mock('pacote')
|
|
2
|
+
|
|
3
|
+
const ProvenanceMarshall = require('../lib/marshalls/provenance.marshall')
|
|
4
|
+
const pacote = require('pacote')
|
|
5
|
+
|
|
6
|
+
describe('Provenance test suites', () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
jest.clearAllMocks()
|
|
9
|
+
jest.resetAllMocks()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('has the right title', async () => {
|
|
13
|
+
const testMarshall = new ProvenanceMarshall({
|
|
14
|
+
packageRepoUtils: {
|
|
15
|
+
getPackageInfo: (pkgInfo) => {
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
resolve(pkgInfo)
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
expect(testMarshall.title()).toEqual('Verifying package provenance')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('should successfully validate a package with verified attestations', async () => {
|
|
27
|
+
// Mock the response from fetch
|
|
28
|
+
const mockResponse = {
|
|
29
|
+
json: jest.fn().mockResolvedValue({
|
|
30
|
+
keys: [
|
|
31
|
+
{
|
|
32
|
+
key: 'publicKey1'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: 'publicKey2'
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.resolve(mockResponse))
|
|
41
|
+
|
|
42
|
+
pacote.manifest = jest.fn().mockResolvedValue({
|
|
43
|
+
name: 'packageName',
|
|
44
|
+
version: '1.0.0',
|
|
45
|
+
_attestations: {
|
|
46
|
+
url: 'https://registry.npmjs.org/-/npm/v1/attestations/pacote@17.0.4',
|
|
47
|
+
provenance: { predicateType: 'https://slsa.dev/provenance/v1' }
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// Call the validate method with a package object
|
|
52
|
+
const pkg = {
|
|
53
|
+
packageName: 'packageName',
|
|
54
|
+
packageVersion: '1.0.0'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const testMarshall = new ProvenanceMarshall({
|
|
58
|
+
packageRepoUtils: {
|
|
59
|
+
getPackageInfo: (pkgInfo) => {
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
resolve({
|
|
62
|
+
name: pkg.packageName,
|
|
63
|
+
version: pkg.packageVersion
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
parsePackageVersion: (pkgVersion) => {
|
|
68
|
+
return {
|
|
69
|
+
version: pkgVersion
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// We assert that the validate method didn't throw an error,
|
|
76
|
+
// because the keys match the signature
|
|
77
|
+
await testMarshall.validate(pkg)
|
|
78
|
+
|
|
79
|
+
// Assert that the fetch method is called with the correct URL
|
|
80
|
+
// eslint-disable-next-line no-undef
|
|
81
|
+
expect(fetch).toHaveBeenCalledWith('https://registry.npmjs.org/-/npm/v1/keys')
|
|
82
|
+
|
|
83
|
+
// Assert that the pacote.manifest method is called with the correct arguments
|
|
84
|
+
expect(pacote.manifest).toHaveBeenCalledWith('packageName@1.0.0', {
|
|
85
|
+
verifyAttestations: true,
|
|
86
|
+
registry: 'https://registry.npmjs.org',
|
|
87
|
+
'//registry.npmjs.org/:_keys': [
|
|
88
|
+
{
|
|
89
|
+
key: 'publicKey1',
|
|
90
|
+
pemkey: '-----BEGIN PUBLIC KEY-----\npublicKey1\n-----END PUBLIC KEY-----'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: 'publicKey2',
|
|
94
|
+
pemkey: '-----BEGIN PUBLIC KEY-----\npublicKey2\n-----END PUBLIC KEY-----'
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('should throw an error if attestation verification fails and manifest() throws an error', async () => {
|
|
101
|
+
// Mock the response from fetch
|
|
102
|
+
const mockResponse = {
|
|
103
|
+
json: jest.fn().mockResolvedValue({
|
|
104
|
+
keys: [
|
|
105
|
+
{
|
|
106
|
+
key: 'publicKey1'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
key: 'publicKey2'
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.resolve(mockResponse))
|
|
115
|
+
|
|
116
|
+
const pkg = {
|
|
117
|
+
packageName: 'packageName',
|
|
118
|
+
packageVersion: '1.0.0'
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// the manifest() method should throw an error
|
|
122
|
+
// in this jest mock to simulate a problem:
|
|
123
|
+
pacote.manifest = jest.fn().mockRejectedValue(new Error('mocked manifest error'))
|
|
124
|
+
|
|
125
|
+
const testMarshall = new ProvenanceMarshall({
|
|
126
|
+
packageRepoUtils: {
|
|
127
|
+
getPackageInfo: (pkgInfo) => {
|
|
128
|
+
return new Promise((resolve) => {
|
|
129
|
+
resolve({
|
|
130
|
+
name: pkg.packageName,
|
|
131
|
+
version: pkg.packageVersion
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
},
|
|
135
|
+
parsePackageVersion: (pkgVersion) => {
|
|
136
|
+
return {
|
|
137
|
+
version: pkgVersion
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
// We assert that the validate method didn't throw an error,
|
|
144
|
+
// because the keys match the signature
|
|
145
|
+
await expect(testMarshall.validate(pkg)).rejects.toThrow('mocked manifest error')
|
|
146
|
+
|
|
147
|
+
// Assert that the fetch method is called with the correct URL
|
|
148
|
+
// eslint-disable-next-line no-undef
|
|
149
|
+
expect(fetch).toHaveBeenCalledWith('https://registry.npmjs.org/-/npm/v1/keys')
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
test('should throw a warning if attestations cant be found for the package', async () => {
|
|
153
|
+
// Mock the response from fetch
|
|
154
|
+
const mockResponse = {
|
|
155
|
+
json: jest.fn().mockResolvedValue({
|
|
156
|
+
keys: [
|
|
157
|
+
{
|
|
158
|
+
key: 'publicKey1'
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
key: 'publicKey2'
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.resolve(mockResponse))
|
|
167
|
+
|
|
168
|
+
const pkg = {
|
|
169
|
+
packageName: 'packageName',
|
|
170
|
+
packageVersion: '1.0.0'
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
pacote.manifest = jest.fn().mockResolvedValue({
|
|
174
|
+
name: 'packageName',
|
|
175
|
+
version: '1.0.0'
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
const testMarshall = new ProvenanceMarshall({
|
|
179
|
+
packageRepoUtils: {
|
|
180
|
+
getPackageInfo: (pkgInfo) => {
|
|
181
|
+
return new Promise((resolve) => {
|
|
182
|
+
resolve({
|
|
183
|
+
name: pkg.packageName,
|
|
184
|
+
version: pkg.packageVersion
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
},
|
|
188
|
+
parsePackageVersion: (pkgVersion) => {
|
|
189
|
+
return {
|
|
190
|
+
version: pkgVersion
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
// We assert that the validate method didn't throw an error,
|
|
197
|
+
// because the keys match the signature
|
|
198
|
+
await expect(testMarshall.validate(pkg)).rejects.toThrow(
|
|
199
|
+
'the package was published without any attestations. Proceed with care.'
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
// Assert that the fetch method is called with the correct URL
|
|
203
|
+
// eslint-disable-next-line no-undef
|
|
204
|
+
expect(fetch).toHaveBeenCalledWith('https://registry.npmjs.org/-/npm/v1/keys')
|
|
205
|
+
})
|
|
206
|
+
})
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
const RepoMarshall = require('../lib/marshalls/repo.marshall')
|
|
2
|
-
const fetch = require('node-fetch')
|
|
3
|
-
|
|
4
|
-
jest.mock('node-fetch')
|
|
5
2
|
|
|
6
3
|
const testMarshall = new RepoMarshall({
|
|
7
4
|
packageRepoUtils: {
|
|
@@ -81,7 +78,7 @@ describe('Repo test suites', () => {
|
|
|
81
78
|
})
|
|
82
79
|
|
|
83
80
|
test('throws the right error when the repository url does not exist', async () => {
|
|
84
|
-
fetch.mockImplementationOnce(() => Promise.reject(new Error('error')))
|
|
81
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error')))
|
|
85
82
|
|
|
86
83
|
await expect(testMarshall.validate(fullPkgData)).rejects.toThrow(
|
|
87
84
|
'no valid repository is associated with the package'
|
|
@@ -89,7 +86,7 @@ describe('Repo test suites', () => {
|
|
|
89
86
|
})
|
|
90
87
|
|
|
91
88
|
test('throws the right error when the repository url is unreachable', async () => {
|
|
92
|
-
fetch.mockImplementationOnce(() => Promise.reject(new Error('error')))
|
|
89
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error')))
|
|
93
90
|
|
|
94
91
|
fullPkgData.packageName.versions['1.0.0'].repository.url =
|
|
95
92
|
'https://dsfsdfsdfs.abcdeugwecwekjasda.com/'
|
|
@@ -99,7 +96,7 @@ describe('Repo test suites', () => {
|
|
|
99
96
|
})
|
|
100
97
|
|
|
101
98
|
test('throws the right error when the homepage url does not exist', async () => {
|
|
102
|
-
fetch.mockImplementationOnce(() => Promise.reject(new Error('error')))
|
|
99
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error')))
|
|
103
100
|
|
|
104
101
|
const pkgData = {
|
|
105
102
|
packageName: {
|
|
@@ -121,7 +118,7 @@ describe('Repo test suites', () => {
|
|
|
121
118
|
})
|
|
122
119
|
|
|
123
120
|
test('does not throw any errors if the url exists', async () => {
|
|
124
|
-
fetch.mockImplementationOnce(() => Promise.resolve('success'))
|
|
121
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.resolve('success'))
|
|
125
122
|
|
|
126
123
|
fullPkgData.packageName.versions['1.0.0'].repository.url = 'https://google.com'
|
|
127
124
|
await expect(testMarshall.validate(fullPkgData)).resolves.toEqual(expect.anything())
|
|
@@ -9,10 +9,6 @@ jest.mock('pacote', () => {
|
|
|
9
9
|
}
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
jest.mock('node-fetch')
|
|
13
|
-
|
|
14
|
-
const fetch = require('node-fetch')
|
|
15
|
-
|
|
16
12
|
const SignaturesMarshall = require('../lib/marshalls/signatures.marshall')
|
|
17
13
|
const pacote = require('pacote')
|
|
18
14
|
|
|
@@ -50,7 +46,7 @@ describe('Signature test suites', () => {
|
|
|
50
46
|
]
|
|
51
47
|
})
|
|
52
48
|
}
|
|
53
|
-
fetch.mockImplementationOnce(() => Promise.resolve(mockResponse))
|
|
49
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.resolve(mockResponse))
|
|
54
50
|
|
|
55
51
|
const testMarshall = new SignaturesMarshall({
|
|
56
52
|
packageRepoUtils: {
|
|
@@ -107,7 +103,7 @@ describe('Signature test suites', () => {
|
|
|
107
103
|
]
|
|
108
104
|
})
|
|
109
105
|
}
|
|
110
|
-
fetch.mockImplementationOnce(() => Promise.resolve(mockResponse))
|
|
106
|
+
global.fetch = jest.fn().mockImplementationOnce(() => Promise.resolve(mockResponse))
|
|
111
107
|
|
|
112
108
|
// the manifest() method should throw an error
|
|
113
109
|
// in this jest mock to simulate a problem:
|
|
@@ -2,7 +2,7 @@ const path = require('path')
|
|
|
2
2
|
const marshalls = require('../lib/marshalls')
|
|
3
3
|
|
|
4
4
|
const PackageRepoUtilsMock = class Fake {
|
|
5
|
-
getPackageInfo
|
|
5
|
+
getPackageInfo() {
|
|
6
6
|
return Promise.resolve(true)
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -53,6 +53,6 @@ test('running marshall tasks fails', async () => {
|
|
|
53
53
|
|
|
54
54
|
await expect(marshalls.tasks(config)).rejects.toMatchObject({
|
|
55
55
|
message: 'Something went wrong',
|
|
56
|
-
context
|
|
56
|
+
context
|
|
57
57
|
})
|
|
58
58
|
})
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
const PackageRepoUtils = require('../lib/helpers/packageRepoUtils')
|
|
2
|
-
const fetch = require('node-fetch')
|
|
3
2
|
|
|
4
|
-
jest.
|
|
5
|
-
fetch.mockImplementation(() =>
|
|
3
|
+
global.fetch = jest.fn().mockImplementation(() =>
|
|
6
4
|
Promise.resolve({
|
|
7
5
|
json: () => require('./mocks/registryPackageOk.mock.json')
|
|
8
6
|
})
|
|
@@ -64,7 +62,7 @@ test('repo utils retrieves package README information', async () => {
|
|
|
64
62
|
|
|
65
63
|
test('repo utils retrieves package latest version as null if not exists', async () => {
|
|
66
64
|
const PackageRepoUtils = require('../lib/helpers/packageRepoUtils')
|
|
67
|
-
fetch.
|
|
65
|
+
global.fetch = jest.fn().mockImplementation(() =>
|
|
68
66
|
Promise.resolve({
|
|
69
67
|
json: () => require('./mocks/registryPackageUnpublished.mock.json')
|
|
70
68
|
})
|
|
@@ -78,7 +76,7 @@ test('repo utils retrieves package latest version as null if not exists', async
|
|
|
78
76
|
|
|
79
77
|
test('repo utils retrieves package download count', async () => {
|
|
80
78
|
const PackageRepoUtils = require('../lib/helpers/packageRepoUtils')
|
|
81
|
-
fetch.
|
|
79
|
+
global.fetch = jest.fn().mockImplementation(() =>
|
|
82
80
|
Promise.resolve({
|
|
83
81
|
json: () => ({
|
|
84
82
|
downloads: 1950,
|
|
@@ -97,7 +95,7 @@ test('repo utils retrieves package download count', async () => {
|
|
|
97
95
|
|
|
98
96
|
test('repo utils retrieves package README information even when not available', async () => {
|
|
99
97
|
const PackageRepoUtils = require('../lib/helpers/packageRepoUtils')
|
|
100
|
-
fetch.
|
|
98
|
+
global.fetch = jest.fn().mockImplementation(() =>
|
|
101
99
|
Promise.resolve({
|
|
102
100
|
json: () => require('./mocks/registryPackageUnpublished.mock.json')
|
|
103
101
|
})
|
|
@@ -111,7 +109,7 @@ test('repo utils retrieves package README information even when not available',
|
|
|
111
109
|
|
|
112
110
|
test('repo utils retrieves package LICENSE information', async () => {
|
|
113
111
|
const PackageRepoUtils = require('../lib/helpers/packageRepoUtils')
|
|
114
|
-
fetch.
|
|
112
|
+
global.fetch = jest.fn().mockImplementation(() =>
|
|
115
113
|
Promise.resolve({
|
|
116
114
|
json: () => require('./mocks/registryPackageOk.mock.json')
|
|
117
115
|
})
|
|
@@ -125,7 +123,7 @@ test('repo utils retrieves package LICENSE information', async () => {
|
|
|
125
123
|
|
|
126
124
|
test('repo utils parses package version', async () => {
|
|
127
125
|
const PackageRepoUtils = require('../lib/helpers/packageRepoUtils')
|
|
128
|
-
fetch.
|
|
126
|
+
global.fetch = jest.fn().mockImplementation(() =>
|
|
129
127
|
Promise.resolve({
|
|
130
128
|
json: () => require('./mocks/registryPackageOk.mock.json')
|
|
131
129
|
})
|
package/lib/cliCommons.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const npa = require('npm-package-arg')
|
|
2
2
|
class cliCommons {
|
|
3
|
-
static getInstallCommand
|
|
3
|
+
static getInstallCommand() {
|
|
4
4
|
return {
|
|
5
5
|
command: 'install [package...]',
|
|
6
6
|
aliases: [
|
|
@@ -31,7 +31,7 @@ class cliCommons {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
static getOptions
|
|
34
|
+
static getOptions() {
|
|
35
35
|
return {
|
|
36
36
|
P: {
|
|
37
37
|
alias: ['save-prod', 'peer'],
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const color = require('kleur')
|
|
4
4
|
// eslint-disable-next-line security/detect-child-process
|
|
5
5
|
const childProcess = require('child_process')
|
|
6
6
|
const semver = require('semver')
|
|
7
|
-
const updateNotifier = require('update-notifier')
|
|
8
|
-
const pkg = require('../../package.json')
|
|
9
7
|
|
|
10
8
|
const DEFAULT_PKGMGR = process.env.NPQ_PKG_MGR || 'npm'
|
|
11
9
|
|
|
12
10
|
const nodeVersion = process.versions.node
|
|
13
11
|
|
|
14
|
-
updateNotifier({ pkg }).notify()
|
|
15
|
-
|
|
16
12
|
module.exports.isEnvSupport = function () {
|
|
17
13
|
if (!semver.satisfies(nodeVersion, '>=7.6.0')) {
|
|
18
14
|
return false
|
|
@@ -23,7 +19,7 @@ module.exports.isEnvSupport = function () {
|
|
|
23
19
|
|
|
24
20
|
module.exports.noSupportError = function (failFast) {
|
|
25
21
|
// eslint-disable-next-line no-console
|
|
26
|
-
console.error(
|
|
22
|
+
console.error(color.red('error:'), 'npq suppressed due to old node version')
|
|
27
23
|
|
|
28
24
|
if (failFast === true) {
|
|
29
25
|
process.exit(-1)
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const fetch = require('node-fetch')
|
|
4
3
|
const semver = require('semver')
|
|
5
4
|
const NPM_REGISTRY = 'http://registry.npmjs.org'
|
|
6
5
|
const NPM_REGISTRY_API = 'https://api.npmjs.org'
|
|
7
6
|
|
|
8
7
|
class PackageRepoUtils {
|
|
9
|
-
constructor
|
|
8
|
+
constructor(options = {}) {
|
|
10
9
|
this.registryUrl = options.registryUrl ? options.registryUrl : NPM_REGISTRY
|
|
11
10
|
this.registryApiUrl = options.registryApiUrl ? options.registryApiUrl : NPM_REGISTRY_API
|
|
12
11
|
this.pkgInfoCache = {}
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
formatPackageForUrl
|
|
14
|
+
formatPackageForUrl(pkg) {
|
|
16
15
|
return pkg.replace(/\//g, '%2F')
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
getPackageInfo
|
|
18
|
+
getPackageInfo(pkg) {
|
|
20
19
|
if (this.pkgInfoCache[pkg]) {
|
|
21
20
|
return Promise.resolve(this.pkgInfoCache[pkg])
|
|
22
21
|
} else {
|
|
@@ -29,27 +28,27 @@ class PackageRepoUtils {
|
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
getLatestVersion
|
|
31
|
+
getLatestVersion(pkg) {
|
|
33
32
|
return this.getPackageInfo(pkg).then((data) => {
|
|
34
|
-
return data['dist-tags'] && data['dist-tags']
|
|
33
|
+
return data['dist-tags'] && data['dist-tags'].latest ? data['dist-tags'].latest : null
|
|
35
34
|
})
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
getDownloadInfo
|
|
37
|
+
getDownloadInfo(pkg) {
|
|
39
38
|
return fetch(`${this.registryApiUrl}/downloads/point/last-month/${pkg}`)
|
|
40
39
|
.then((response) => response.json())
|
|
41
40
|
.then(({ downloads }) => downloads)
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
getReadmeInfo
|
|
43
|
+
getReadmeInfo(pkg) {
|
|
45
44
|
return this.getPackageInfo(pkg).then(({ readme }) => readme)
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
getLicenseInfo
|
|
47
|
+
getLicenseInfo(pkg) {
|
|
49
48
|
return this.getPackageInfo(pkg).then(({ license }) => license)
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
parsePackageVersion
|
|
51
|
+
parsePackageVersion(version) {
|
|
53
52
|
return semver.coerce(version)
|
|
54
53
|
}
|
|
55
54
|
}
|
package/lib/marshall.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const color = require('kleur')
|
|
5
5
|
|
|
6
6
|
const Marshalls = require('./marshalls')
|
|
7
7
|
const PackageRepoUtils = require('./helpers/packageRepoUtils')
|
|
@@ -12,12 +12,12 @@ const MESSAGE_TYPE = {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
class Marshall {
|
|
15
|
-
constructor
|
|
15
|
+
constructor(options = {}) {
|
|
16
16
|
this.pkgs = options ? options.pkgs : null
|
|
17
17
|
this.packageRepoUtils = new PackageRepoUtils()
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
process
|
|
20
|
+
process() {
|
|
21
21
|
// nothing to do? move on
|
|
22
22
|
if (!this.pkgs) {
|
|
23
23
|
return Promise.resolve()
|
|
@@ -37,7 +37,7 @@ class Marshall {
|
|
|
37
37
|
})
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
createPackageVersionMaps
|
|
40
|
+
createPackageVersionMaps(packages) {
|
|
41
41
|
const packageVersionMapping = packages.reduce((prev, curr) => {
|
|
42
42
|
const versionSymbolPosition = curr.lastIndexOf('@')
|
|
43
43
|
const versionPosition =
|
|
@@ -57,7 +57,7 @@ class Marshall {
|
|
|
57
57
|
return packageVersionMapping
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
report
|
|
60
|
+
report(marshalls) {
|
|
61
61
|
const messages = this.collectPackageMessages(marshalls)
|
|
62
62
|
|
|
63
63
|
if (!messages) {
|
|
@@ -67,13 +67,13 @@ class Marshall {
|
|
|
67
67
|
console.log('Detected possible issues with the following packages:')
|
|
68
68
|
for (const packageName in messages) {
|
|
69
69
|
const packageMessages = messages[packageName]
|
|
70
|
-
console.log(` [${
|
|
70
|
+
console.log(` [${color.red(packageName)}]`)
|
|
71
71
|
|
|
72
72
|
packageMessages.forEach((message) => {
|
|
73
73
|
if (message.type === MESSAGE_TYPE.ERROR) {
|
|
74
|
-
console.log(` - ${
|
|
74
|
+
console.log(` - ${color.red(message.text)}`)
|
|
75
75
|
} else {
|
|
76
|
-
console.log(` - ${
|
|
76
|
+
console.log(` - ${color.yellow(message.text)}`)
|
|
77
77
|
}
|
|
78
78
|
})
|
|
79
79
|
}
|
|
@@ -81,7 +81,7 @@ class Marshall {
|
|
|
81
81
|
return { error: true, data: messages }
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
collectPackageMessages
|
|
84
|
+
collectPackageMessages(marshalls) {
|
|
85
85
|
const allPackageMessages = {}
|
|
86
86
|
for (const key in marshalls) {
|
|
87
87
|
this.prepareMessages(allPackageMessages, marshalls[key].errors)
|
|
@@ -91,7 +91,7 @@ class Marshall {
|
|
|
91
91
|
return allPackageMessages
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
prepareMessages
|
|
94
|
+
prepareMessages(allPackageMessages, messages, isWarning) {
|
|
95
95
|
if (Array.isArray(messages) && messages.length > 0) {
|
|
96
96
|
messages.forEach((msg) => {
|
|
97
97
|
this.appendPackageMessage(allPackageMessages, msg.pkg, {
|
|
@@ -102,7 +102,7 @@ class Marshall {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
appendPackageMessage
|
|
105
|
+
appendPackageMessage(packages, packageName, packageMessage) {
|
|
106
106
|
packages[packageName]
|
|
107
107
|
? packages[packageName].push(packageMessage)
|
|
108
108
|
: (packages[packageName] = [packageMessage])
|