@@ -3,13 +3,37 @@ import { execSync } from "child_process";
33import { outputFile , readFile , readJSON } from "fs-extra" ;
44import { getVersionInformation } from "./util/vscode-versions" ;
55import { fetchJson } from "./util/fetch" ;
6+ import { SemVer } from "semver" ;
67
78const extensionDirectory = resolve ( __dirname , ".." ) ;
89
910interface Release {
1011 tag_name : string ;
1112}
1213
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+
1337async function updateNodeVersion ( ) {
1438 const latestVsCodeRelease = await fetchJson < Release > (
1539 "https://api.github.com/repos/microsoft/vscode/releases/latest" ,
@@ -49,20 +73,64 @@ async function updateNodeVersion() {
4973 "utf8" ,
5074 ) ;
5175
76+ const nodeVersion = new SemVer ( versionInformation . nodeVersion ) ;
77+
5278 // The @types /node version needs to match the first two parts of the Node
5379 // version, e.g. if the Node version is 18.17.3, the @types/node version
5480 // should be 18.17.*. This corresponds with the documentation at
5581 // https://github.com/definitelytyped/definitelytyped#how-do-definitely-typed-package-versions-relate-to-versions-of-the-corresponding-library
5682 // "The patch version of the type declaration package is unrelated to the library patch version. This allows
5783 // Definitely Typed to safely update type declarations for the same major/minor version of a library."
5884 // 18.17.* is equivalent to >=18.17.0 <18.18.0
59- const typesNodeVersion = versionInformation . nodeVersion
60- . split ( "." )
61- . slice ( 0 , 2 )
62- . join ( "." ) ;
85+ // In some cases, the @types/node version matching the exact Node version may not exist, in which case we'll try
86+ // the next lower minor version, and so on, until we find a version that exists.
87+ const typesNodeSemver = new SemVer ( nodeVersion ) ;
88+ typesNodeSemver . patch = 0 ;
89+
90+ // eslint-disable-next-line no-constant-condition
91+ while ( true ) {
92+ const typesNodeVersion = `${ typesNodeSemver . major } .${ typesNodeSemver . minor } .*` ;
93+
94+ try {
95+ // Check that this version actually exists
96+ console . log ( `Checking if @types/node@${ typesNodeVersion } exists` ) ;
97+
98+ execSync ( `npm view --json "@types/node@${ typesNodeVersion } "` , {
99+ encoding : "utf-8" ,
100+ stdio : "pipe" ,
101+ } ) ;
102+
103+ console . log ( `@types/node@${ typesNodeVersion } exists` ) ;
104+
105+ // If it exists, we can break out of this loop
106+ break ;
107+ } catch ( e : unknown ) {
108+ if ( ! isExecError ( e ) ) {
109+ throw e ;
110+ }
111+
112+ const error = JSON . parse ( e . stdout ) as NpmViewError ;
113+ if ( error . error . code !== "E404" ) {
114+ throw new Error ( error . error . detail ) ;
115+ }
116+
117+ console . log (
118+ `@types/node package doesn't exist for ${ typesNodeVersion } , trying a lower version (${ error . error . summary } )` ,
119+ ) ;
120+
121+ // This means the version doesn't exist, so we'll try decrementing the minor version
122+ typesNodeSemver . minor -= 1 ;
123+ if ( typesNodeSemver . minor < 0 ) {
124+ throw new Error (
125+ `Could not find a suitable @types/node version for Node ${ nodeVersion . format ( ) } ` ,
126+ ) ;
127+ }
128+ }
129+ }
63130
64131 packageJson . engines . node = `^${ versionInformation . nodeVersion } ` ;
65- packageJson . devDependencies [ "@types/node" ] = `${ typesNodeVersion } .*` ;
132+ packageJson . devDependencies [ "@types/node" ] =
133+ `${ typesNodeSemver . major } .${ typesNodeSemver . minor } .*` ;
66134
67135 await outputFile (
68136 join ( extensionDirectory , "package.json" ) ,
0 commit comments