1
1
import { join , resolve } from "path" ;
2
2
import { execSync } from "child_process" ;
3
- import { outputFile , readFile , readJSON } from "fs-extra" ;
3
+ import { outputFile , readJSON } from "fs-extra" ;
4
4
import { getVersionInformation } from "./util/vscode-versions" ;
5
5
import { fetchJson } from "./util/fetch" ;
6
+ import { SemVer } from "semver" ;
6
7
7
8
const extensionDirectory = resolve ( __dirname , ".." ) ;
8
9
9
10
interface Release {
10
11
tag_name : string ;
11
12
}
12
13
14
+ interface NpmViewError {
15
+ error : {
16
+ code : string ;
17
+ summary : string ;
18
+ detail : string ;
19
+ } ;
20
+ }
21
+
22
+ interface ExecError extends Error {
23
+ status : number ;
24
+ stdout : string ;
25
+ }
26
+
27
+ function isExecError ( e : unknown ) : e is ExecError {
28
+ return (
29
+ e instanceof Error &&
30
+ "status" in e &&
31
+ typeof e . status === "number" &&
32
+ "stdout" in e &&
33
+ typeof e . stdout === "string"
34
+ ) ;
35
+ }
36
+
13
37
async function updateNodeVersion ( ) {
14
38
const latestVsCodeRelease = await fetchJson < Release > (
15
39
"https://api.github.com/repos/microsoft/vscode/releases/latest" ,
@@ -23,19 +47,7 @@ async function updateNodeVersion() {
23
47
`VS Code ${ versionInformation . vscodeVersion } uses Electron ${ versionInformation . electronVersion } and Node ${ versionInformation . nodeVersion } ` ,
24
48
) ;
25
49
26
- let currentNodeVersion = (
27
- await readFile ( join ( extensionDirectory , ".nvmrc" ) , "utf8" )
28
- ) . trim ( ) ;
29
- if ( currentNodeVersion . startsWith ( "v" ) ) {
30
- currentNodeVersion = currentNodeVersion . slice ( 1 ) ;
31
- }
32
-
33
- if ( currentNodeVersion === versionInformation . nodeVersion ) {
34
- console . log ( "Node version is already up to date" ) ;
35
- return ;
36
- }
37
-
38
- console . log ( "Node version needs to be updated, updating now" ) ;
50
+ console . log ( "Updating files related to the Node version" ) ;
39
51
40
52
await outputFile (
41
53
join ( extensionDirectory , ".nvmrc" ) ,
@@ -49,20 +61,64 @@ async function updateNodeVersion() {
49
61
"utf8" ,
50
62
) ;
51
63
64
+ const nodeVersion = new SemVer ( versionInformation . nodeVersion ) ;
65
+
52
66
// The @types /node version needs to match the first two parts of the Node
53
67
// version, e.g. if the Node version is 18.17.3, the @types/node version
54
68
// should be 18.17.*. This corresponds with the documentation at
55
69
// https://github.com/definitelytyped/definitelytyped#how-do-definitely-typed-package-versions-relate-to-versions-of-the-corresponding-library
56
70
// "The patch version of the type declaration package is unrelated to the library patch version. This allows
57
71
// Definitely Typed to safely update type declarations for the same major/minor version of a library."
58
72
// 18.17.* is equivalent to >=18.17.0 <18.18.0
59
- const typesNodeVersion = versionInformation . nodeVersion
60
- . split ( "." )
61
- . slice ( 0 , 2 )
62
- . join ( "." ) ;
73
+ // In some cases, the @types/node version matching the exact Node version may not exist, in which case we'll try
74
+ // the next lower minor version, and so on, until we find a version that exists.
75
+ const typesNodeSemver = new SemVer ( nodeVersion ) ;
76
+ typesNodeSemver . patch = 0 ;
77
+
78
+ // eslint-disable-next-line no-constant-condition
79
+ while ( true ) {
80
+ const typesNodeVersion = `${ typesNodeSemver . major } .${ typesNodeSemver . minor } .*` ;
81
+
82
+ try {
83
+ // Check that this version actually exists
84
+ console . log ( `Checking if @types/node@${ typesNodeVersion } exists` ) ;
85
+
86
+ execSync ( `npm view --json "@types/node@${ typesNodeVersion } "` , {
87
+ encoding : "utf-8" ,
88
+ stdio : "pipe" ,
89
+ } ) ;
90
+
91
+ console . log ( `@types/node@${ typesNodeVersion } exists` ) ;
92
+
93
+ // If it exists, we can break out of this loop
94
+ break ;
95
+ } catch ( e : unknown ) {
96
+ if ( ! isExecError ( e ) ) {
97
+ throw e ;
98
+ }
99
+
100
+ const error = JSON . parse ( e . stdout ) as NpmViewError ;
101
+ if ( error . error . code !== "E404" ) {
102
+ throw new Error ( error . error . detail ) ;
103
+ }
104
+
105
+ console . log (
106
+ `@types/node package doesn't exist for ${ typesNodeVersion } , trying a lower version (${ error . error . summary } )` ,
107
+ ) ;
108
+
109
+ // This means the version doesn't exist, so we'll try decrementing the minor version
110
+ typesNodeSemver . minor -= 1 ;
111
+ if ( typesNodeSemver . minor < 0 ) {
112
+ throw new Error (
113
+ `Could not find a suitable @types/node version for Node ${ nodeVersion . format ( ) } ` ,
114
+ ) ;
115
+ }
116
+ }
117
+ }
63
118
64
119
packageJson . engines . node = `^${ versionInformation . nodeVersion } ` ;
65
- packageJson . devDependencies [ "@types/node" ] = `${ typesNodeVersion } .*` ;
120
+ packageJson . devDependencies [ "@types/node" ] =
121
+ `${ typesNodeSemver . major } .${ typesNodeSemver . minor } .*` ;
66
122
67
123
await outputFile (
68
124
join ( extensionDirectory , "package.json" ) ,
0 commit comments