11import { join , resolve } from "path" ;
22import { execSync } from "child_process" ;
3- import { outputFile , readFile , readJSON } from "fs-extra" ;
3+ import { outputFile , 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" ,
@@ -23,19 +47,7 @@ async function updateNodeVersion() {
2347 `VS Code ${ versionInformation . vscodeVersion } uses Electron ${ versionInformation . electronVersion } and Node ${ versionInformation . nodeVersion } ` ,
2448 ) ;
2549
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" ) ;
3951
4052 await outputFile (
4153 join ( extensionDirectory , ".nvmrc" ) ,
@@ -49,20 +61,64 @@ async function updateNodeVersion() {
4961 "utf8" ,
5062 ) ;
5163
64+ const nodeVersion = new SemVer ( versionInformation . nodeVersion ) ;
65+
5266 // The @types /node version needs to match the first two parts of the Node
5367 // version, e.g. if the Node version is 18.17.3, the @types/node version
5468 // should be 18.17.*. This corresponds with the documentation at
5569 // https://github.com/definitelytyped/definitelytyped#how-do-definitely-typed-package-versions-relate-to-versions-of-the-corresponding-library
5670 // "The patch version of the type declaration package is unrelated to the library patch version. This allows
5771 // Definitely Typed to safely update type declarations for the same major/minor version of a library."
5872 // 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+ }
63118
64119 packageJson . engines . node = `^${ versionInformation . nodeVersion } ` ;
65- packageJson . devDependencies [ "@types/node" ] = `${ typesNodeVersion } .*` ;
120+ packageJson . devDependencies [ "@types/node" ] =
121+ `${ typesNodeSemver . major } .${ typesNodeSemver . minor } .*` ;
66122
67123 await outputFile (
68124 join ( extensionDirectory , "package.json" ) ,
0 commit comments