3
3
ManifestFieldNames as PackageManifestFieldNames ,
4
4
ManifestDependencyFieldNames as PackageManifestDependenciesFieldNames ,
5
5
} from '@metamask/action-utils' ;
6
+ import { isPlainObject } from '@metamask/utils' ;
6
7
import { readJsonObjectFile } from './fs' ;
7
8
import { isTruthyString } from './misc-utils' ;
8
9
import { isValidSemver , SemVer } from './semver' ;
@@ -29,6 +30,11 @@ export type ValidatedPackageManifest = {
29
30
readonly [ PackageManifestFieldNames . Version ] : SemVer ;
30
31
readonly [ PackageManifestFieldNames . Private ] : boolean ;
31
32
readonly [ PackageManifestFieldNames . Workspaces ] : string [ ] ;
33
+ readonly [ PackageManifestDependenciesFieldNames . Production ] : Record <
34
+ string ,
35
+ string
36
+ > ;
37
+ readonly [ PackageManifestDependenciesFieldNames . Peer ] : Record < string , string > ;
32
38
} ;
33
39
34
40
/**
@@ -83,6 +89,14 @@ const schemata = {
83
89
validate : isValidPackageManifestPrivateField ,
84
90
errorMessage : 'must be true or false (if present)' ,
85
91
} ,
92
+ [ PackageManifestDependenciesFieldNames . Production ] : {
93
+ validate : isValidPackageManifestDependenciesField ,
94
+ errorMessage : 'must be a valid dependencies field' ,
95
+ } ,
96
+ [ PackageManifestDependenciesFieldNames . Peer ] : {
97
+ validate : isValidPackageManifestDependenciesField ,
98
+ errorMessage : 'must be a valid peerDependencies field' ,
99
+ } ,
86
100
} ;
87
101
88
102
/**
@@ -256,6 +270,61 @@ export function readPackageManifestPrivateField(
256
270
return value ?? false ;
257
271
}
258
272
273
+ /**
274
+ * Type guard to ensure that the value of the "dependencies" or "peerDependencies" field of a manifest is
275
+ * valid.
276
+ *
277
+ * @param depsValue - The value to check.
278
+ * @returns Whether the value is has valid values.
279
+ */
280
+ function isValidPackageManifestDependenciesField (
281
+ depsValue : unknown ,
282
+ ) : depsValue is Record < string , string > {
283
+ return (
284
+ depsValue === undefined ||
285
+ ( isPlainObject ( depsValue ) &&
286
+ Object . entries ( depsValue ) . every ( ( [ pkgName , version ] ) => {
287
+ return (
288
+ isTruthyString ( pkgName ) && isValidPackageManifestVersionField ( version )
289
+ ) ;
290
+ } ) )
291
+ ) ;
292
+ }
293
+
294
+ /**
295
+ * Retrieves and validates the "dependencies" or "peerDependencies" fields within the package manifest
296
+ * object.
297
+ *
298
+ * @param manifest - The manifest object.
299
+ * @param parentDirectory - The directory in which the manifest lives.
300
+ * @param fieldName - The field name "dependencies" or "peerDependencies".
301
+ * @returns The value of the "dependencies" or "peerDependencies" field.
302
+ * @throws If the value of the field is not valid.
303
+ */
304
+ export function readPackageManifestDependenciesField (
305
+ manifest : UnvalidatedPackageManifest ,
306
+ parentDirectory : string ,
307
+ fieldName :
308
+ | PackageManifestDependenciesFieldNames . Production
309
+ | PackageManifestDependenciesFieldNames . Peer ,
310
+ ) : Record < string , string > {
311
+ const value = manifest [ fieldName ] ;
312
+ const schema = schemata [ fieldName ] ;
313
+
314
+ if ( ! schema . validate ( value ) ) {
315
+ throw new Error (
316
+ buildPackageManifestFieldValidationErrorMessage ( {
317
+ manifest,
318
+ parentDirectory,
319
+ fieldName,
320
+ verbPhrase : schema . errorMessage ,
321
+ } ) ,
322
+ ) ;
323
+ }
324
+
325
+ return value || { } ;
326
+ }
327
+
259
328
/**
260
329
* Reads the package manifest at the given path, verifying key data within the
261
330
* manifest.
@@ -281,12 +350,24 @@ export async function readPackageManifest(manifestPath: string): Promise<{
281
350
unvalidated ,
282
351
parentDirectory ,
283
352
) ;
353
+ const dependencies = readPackageManifestDependenciesField (
354
+ unvalidated ,
355
+ parentDirectory ,
356
+ PackageManifestDependenciesFieldNames . Production ,
357
+ ) ;
358
+ const peerDependencies = readPackageManifestDependenciesField (
359
+ unvalidated ,
360
+ parentDirectory ,
361
+ PackageManifestDependenciesFieldNames . Peer ,
362
+ ) ;
284
363
285
364
const validated = {
286
365
[ PackageManifestFieldNames . Name ] : name ,
287
366
[ PackageManifestFieldNames . Version ] : version ,
288
367
[ PackageManifestFieldNames . Workspaces ] : workspaces ,
289
368
[ PackageManifestFieldNames . Private ] : privateValue ,
369
+ [ PackageManifestDependenciesFieldNames . Production ] : dependencies ,
370
+ [ PackageManifestDependenciesFieldNames . Peer ] : peerDependencies ,
290
371
} ;
291
372
292
373
return { unvalidated, validated } ;
0 commit comments