@@ -4,6 +4,8 @@ import { readFile } from 'node:fs/promises';
4
4
import { dirname , resolve } from 'node:path' ;
5
5
import { fileURLToPath } from 'node:url' ;
6
6
import { log , warn } from '../../scripts/log.js' ;
7
+ import semverParse from 'semver/functions/parse.js' ;
8
+ import semverSatisfies from 'semver/functions/satisfies.js' ;
7
9
8
10
const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
9
11
@@ -27,36 +29,101 @@ if (!nodeVersion) {
27
29
log ( `Found node version ${ nodeVersion } in \`.nvmrc\`` ) ;
28
30
}
29
31
32
+ /**
33
+ * @typedef {'major' | 'minor' | 'patch' } MatchLevel
34
+ */
30
35
const requiredNodeVersionMatches =
31
- /** @type {const } @satisfies {ReadonlyArray<{filepath: string, pattern: RegExp}> }*/ ( [
36
+ /** @type {const } @satisfies {ReadonlyArray<{filepath: string, pattern: RegExp, matchLevel: MatchLevel }> }*/ ( [
32
37
{
33
38
filepath : 'Containerfile' ,
34
39
pattern : / ^ F R O M n o d e : ( .+ ) - a l p i n e $ / m,
40
+ matchLevel : 'patch' ,
35
41
} ,
36
42
{
37
43
filepath : 'scripts/deploy/riff-raff.yaml' ,
38
44
pattern : / ^ + R e c i p e : d o t c o m - r e n d e r i n g .* - n o d e - ( \d + \. \d + \. \d + ) .* ?$ / m,
45
+ matchLevel : 'patch' ,
39
46
} ,
40
47
{
41
48
filepath : '../apps-rendering/riff-raff.yaml' ,
42
49
pattern : / ^ + R e c i p e : a p p s - r e n d e r i n g .* - n o d e - ( \d + \. \d + \. \d + ) .* ?$ / m,
50
+ matchLevel : 'patch' ,
51
+ } ,
52
+ {
53
+ filepath : 'package.json' ,
54
+ pattern : / ^ \t + " @ t y p e s \/ n o d e " \: " ( .+ ) " , $ / m,
55
+ /*
56
+ Definitely Typed packages only match the major and minor
57
+ versions of the corresponding library/node release.
58
+ https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.md#how-do-definitely-typed-package-versions-relate-to-versions-of-the-corresponding-library
59
+
60
+ Note: Given this rule, this should be set to 'minor'. It's currently
61
+ set to 'major' because the latest node release doesn't yet have
62
+ types available for it (v22.18.0, latest types package is v22.17.x).
63
+ */
64
+ matchLevel : 'major' ,
65
+ } ,
66
+ {
67
+ filepath : '../apps-rendering/package.json' ,
68
+ pattern : / ^ \t + " @ t y p e s \/ n o d e " \: " ( .+ ) " , $ / m,
69
+ /*
70
+ Definitely Typed packages only match the major and minor
71
+ versions of the corresponding library/node release.
72
+ https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.md#how-do-definitely-typed-package-versions-relate-to-versions-of-the-corresponding-library
73
+
74
+ Note: Given this rule, this should be set to 'minor'. It's currently
75
+ set to 'major' because the latest node release doesn't yet have
76
+ types available for it (v22.18.0, latest types package is v22.17.x).
77
+ */
78
+ matchLevel : 'major' ,
43
79
} ,
44
80
] ) ;
45
81
82
+ /**
83
+ *
84
+ * @param {string } a
85
+ * @param {string } b
86
+ * @param {MatchLevel } matchLevel
87
+ * @returns boolean
88
+ */
89
+ const versionMatches = ( a , b , matchLevel ) => {
90
+ const semverA = semverParse ( a ) ;
91
+
92
+ switch ( matchLevel ) {
93
+ case 'major' :
94
+ return semverSatisfies ( b , `${ semverA ?. major } .x.x` ) ;
95
+ case 'minor' :
96
+ return semverSatisfies ( b , `${ semverA ?. major } .${ semverA ?. minor } .x` ) ;
97
+ case 'patch' :
98
+ return semverSatisfies ( b , a ) ;
99
+ }
100
+ } ;
101
+
46
102
const problems = (
47
103
await Promise . all (
48
- requiredNodeVersionMatches . map ( async ( { filepath, pattern } ) => {
49
- const fileContents = await readFile (
50
- resolve ( ...filepath . split ( '/' ) ) ,
51
- 'utf-8' ,
52
- ) ;
53
- const foundNodeVersion =
54
- fileContents . match ( pattern ) ?. [ 1 ] ?? undefined ;
104
+ requiredNodeVersionMatches . map (
105
+ async ( { filepath, pattern, matchLevel } ) => {
106
+ const fileContents = await readFile (
107
+ resolve ( ...filepath . split ( '/' ) ) ,
108
+ 'utf-8' ,
109
+ ) ;
110
+ const foundNodeVersion =
111
+ fileContents . match ( pattern ) ?. [ 1 ] ?? undefined ;
112
+
113
+ const matches =
114
+ foundNodeVersion === undefined
115
+ ? false
116
+ : versionMatches (
117
+ nodeVersion ,
118
+ foundNodeVersion ,
119
+ matchLevel ,
120
+ ) ;
55
121
56
- return foundNodeVersion === nodeVersion
57
- ? undefined
58
- : `Node version in ${ filepath } (${ foundNodeVersion } ) does not match \`.nvmrc\` (${ nodeVersion } )` ;
59
- } ) ,
122
+ return matches
123
+ ? undefined
124
+ : `Node version in ${ filepath } (${ foundNodeVersion } ) does not match \`.nvmrc\` (${ nodeVersion } ), expected them to match versions to the ${ matchLevel } level` ;
125
+ } ,
126
+ ) ,
60
127
)
61
128
) . filter (
62
129
/** @type {(problem?: string) => problem is string } */
0 commit comments