@@ -12,7 +12,14 @@ import { Stream } from 'stream';
12
12
import { Config } from '../config-manager' ;
13
13
import FileReader from './file-reader' ;
14
14
import Logger , { ILogger } from './logger' ;
15
- import { required , sortObjectKeys } from './utility-functions' ;
15
+ import {
16
+ isObject ,
17
+ isObjectEmpty ,
18
+ limitFn ,
19
+ pluginName ,
20
+ required ,
21
+ sortObjectKeys ,
22
+ } from './utility-functions' ;
16
23
17
24
18
25
export type PackageManager = 'yarn' | 'npm' ;
@@ -39,13 +46,16 @@ export interface DependenciesInstallerDefaults {
39
46
managers : PackageManagersList ;
40
47
}
41
48
49
+ export type DependenciesSubscriber = ( manifest : DependenciesManifest , name : string ) => void ;
50
+
42
51
export interface DependenciesInstaller {
43
52
add ( manifest : DependenciesManifest ) : Promise < void > ;
44
53
run ( ) : Promise < void > ;
45
54
/* test:start */
46
55
checkForManagers ?( ) : Promise < void > ;
47
56
hasNoManagers ?( ) : boolean ;
48
57
isManagerInstalled ?( manager : PackageManager ) : Promise < boolean > ;
58
+ isManifestValid ?( manifest : DependenciesManifest ) : boolean ;
49
59
logError ?( stream : Stream ) : void ;
50
60
logOutput ?( stream : Stream ) : void ;
51
61
/* test:end */
@@ -57,7 +67,9 @@ const MESSAGES = {
57
67
INSTALLING : 'Installing dependencies using' ,
58
68
LOOKING_FOR_MANAGERS : 'Looking for package managers\u2026' ,
59
69
MANAGER_FOUND : 'Package manager found' ,
70
+ MANIFEST_SCHEMA : 'When registering your plugin dependencies use the "package.json" schema' ,
60
71
MANUAL_VERSION_CHANGE_REQUIRED : 'Unexpected behaviour or errors might occur. Please change the version of the package manually!' ,
72
+ REGISTERING_PLUGIN_DEPS : 'Registering dependencies' ,
61
73
} ;
62
74
63
75
// Custom error messages
@@ -66,6 +78,7 @@ export const ERRORS = {
66
78
DEPENDENCY_ALREADY_ADDED : 'Package already exists' ,
67
79
DEPENDENCY_VERSION_MISMATCH : 'Package already exists with different version' ,
68
80
MANAGERS_REQUIRED : 'You need at least one package manager on your system (e.g. \'yarn\', \'npm\')' ,
81
+ MANIFEST_INVALID : 'Dependencies <manifest> object is invalid' ,
69
82
NO_MANAGERS : 'Wow, no package managers were found on your system' ,
70
83
} ;
71
84
@@ -80,7 +93,7 @@ export async function Installer(
80
93
options ?: DependenciesInstallerOptions ,
81
94
) : Promise < DependenciesInstaller > {
82
95
const defaultOptions : DependenciesInstallerDefaults = {
83
- logChannel : 'PackageInstaller ' ,
96
+ logChannel : 'DepsInstaller ' ,
84
97
managers : [ 'yarn' , 'npm' ] ,
85
98
} ;
86
99
@@ -111,11 +124,96 @@ export async function Installer(
111
124
let availableManagers : PackageManagersList = [ ] ;
112
125
113
126
127
+ /**
128
+ * Check validity of <manifest> object
129
+ * @param manifest Dependencies manifest object
130
+ */
131
+ function isManifestValid ( manifest : DependenciesManifest ) {
132
+ if ( ! isObject ( manifest ) ) {
133
+ logger . error ( `${ ERRORS . MANIFEST_INVALID } : not an object` ) ;
134
+ return false ;
135
+ }
136
+
137
+ if ( isObjectEmpty ( manifest ) ) {
138
+ logger . error ( `${ ERRORS . MANIFEST_INVALID } : object is empty` ) ;
139
+ return false ;
140
+ }
141
+
142
+ // Not valid if both "devDependencies" and "dependencies" keys are missing
143
+ if ( ! Object . keys ( manifest ) . some ( key => [ 'dependencies' , 'devDependencies' ] . includes ( key ) ) ) {
144
+ logger . error ( `${ ERRORS . MANIFEST_INVALID } : object should have at least one of the following keys: 'dependencies', 'devDependencies'` ) ;
145
+ return false ;
146
+ }
147
+
148
+ // If "dependencies" or "devDependencies" are not objects
149
+ if (
150
+ ( typeof manifest . dependencies !== 'undefined' && ! isObject ( manifest . dependencies ) ) ||
151
+ ( typeof manifest . devDependencies !== 'undefined' && ! isObject ( manifest . devDependencies ) )
152
+ ) {
153
+ logger . error ( `${ ERRORS . MANIFEST_INVALID } : manifest's 'dependencies' and 'devDependencies' should be objects` ) ;
154
+ return false ;
155
+ }
156
+
157
+ // If manifest contains "devDependencies" or "dependencies" keys, but are empty
158
+ if (
159
+ // Has "devDependencies", but is empty
160
+ (
161
+ typeof manifest . dependencies === 'undefined' &&
162
+ (
163
+ typeof manifest . devDependencies !== 'undefined' &&
164
+ isObject ( manifest . devDependencies ) &&
165
+ isObjectEmpty ( manifest . devDependencies )
166
+ )
167
+ ) ||
168
+ // Has "dependencies", but is empty
169
+ (
170
+ typeof manifest . devDependencies === 'undefined' &&
171
+ (
172
+ typeof manifest . dependencies !== 'undefined' &&
173
+ isObject ( manifest . dependencies ) &&
174
+ isObjectEmpty ( manifest . dependencies )
175
+ )
176
+ ) ||
177
+ // Has both "dependencies" and "devDependencies" empty
178
+ (
179
+ typeof manifest . dependencies !== 'undefined' &&
180
+ isObject ( manifest . dependencies ) &&
181
+ isObjectEmpty ( manifest . dependencies ) &&
182
+ typeof manifest . devDependencies !== 'undefined' &&
183
+ isObject ( manifest . devDependencies ) &&
184
+ isObjectEmpty ( manifest . devDependencies )
185
+ )
186
+ ) {
187
+ logger . error (
188
+ `${ ERRORS . MANIFEST_INVALID } : manifest's 'dependencies' or 'devDependencies' objects should not be empty` ,
189
+ ) ;
190
+ return false ;
191
+ }
192
+
193
+ return true ;
194
+ }
195
+
196
+
114
197
/**
115
198
* Add dependencies to package.json
116
199
* @param dependencies Object with "dependencies" and "devDependencies"
117
200
*/
118
201
async function add ( manifest : DependenciesManifest ) : Promise < void > {
202
+ // Validate manifest parameter
203
+ if ( ! isManifestValid ( manifest ) ) {
204
+ const schema = {
205
+ dependencies : {
206
+ package : '^1.0.1' ,
207
+ package2 : '^2.2.0' ,
208
+ } ,
209
+ devDependencies : {
210
+ 'dev-package' : '~3.1.4' ,
211
+ } ,
212
+ } ;
213
+ logger . warn ( `${ MESSAGES . MANIFEST_SCHEMA } :\n${ JSON . stringify ( schema , null , 2 ) } ` ) ;
214
+ return undefined ;
215
+ }
216
+
119
217
try {
120
218
// Get current dependencies
121
219
const projectConfig = await fileReader . read ( ) ;
@@ -306,6 +404,7 @@ export async function Installer(
306
404
checkForManagers,
307
405
hasNoManagers,
308
406
isManagerInstalled,
407
+ isManifestValid,
309
408
logError,
310
409
logOutput,
311
410
} ;
0 commit comments