@@ -79,6 +79,10 @@ export default class Editor extends Plugin {
7979
8080 this . tsModuleMappings = { }
8181 this . processedPackages = new Set ( )
82+
83+ this . typesLoadingCount = 0
84+ this . shimDisposers = new Map ( )
85+ this . pendingPackagesBatch = new Set ( )
8286 }
8387
8488 setDispatch ( dispatch ) {
@@ -147,8 +151,8 @@ export default class Editor extends Plugin {
147151 const tsDefaults = ts . typescriptDefaults
148152
149153 tsDefaults . setCompilerOptions ( {
150- moduleResolution : ts . ModuleResolutionKind . Bundler ,
151- module : ts . ModuleKind . ESNext ,
154+ moduleResolution : ts . ModuleResolutionKind . NodeNext ,
155+ module : ts . ModuleKind . NodeNext ,
152156 target : ts . ScriptTarget . ES2022 ,
153157 lib : [ 'es2022' , 'dom' , 'dom.iterable' ] ,
154158 allowNonTsExtensions : true ,
@@ -157,7 +161,9 @@ export default class Editor extends Plugin {
157161 baseUrl : 'file:///node_modules/' ,
158162 paths : this . tsModuleMappings ,
159163 } )
160- console . log ( '[DIAGNOSE-SETUP] Initial CompilerOptions set.' )
164+ tsDefaults . setDiagnosticsOptions ( { noSemanticValidation : false , noSyntaxValidation : false } )
165+ ts . typescriptDefaults . setEagerModelSync ( true )
166+ console . log ( '[DIAGNOSE-SETUP] CompilerOptions set to NodeNext and diagnostics enabled' )
161167 } )
162168 this . on ( 'sidePanel' , 'focusChanged' , ( name ) => {
163169 this . keepDecorationsFor ( name , 'sourceAnnotationsPerFile' )
@@ -202,6 +208,67 @@ export default class Editor extends Plugin {
202208 console . log ( '[DIAGNOSE-PATHS] TS compiler options updated.' )
203209 }
204210
211+ toggleTsDiagnostics ( enable ) {
212+ if ( ! this . monaco ) return
213+ const ts = this . monaco . languages . typescript
214+ ts . typescriptDefaults . setDiagnosticsOptions ( {
215+ noSemanticValidation : ! enable ,
216+ noSyntaxValidation : false
217+ } )
218+ console . log ( `[DIAGNOSE-DIAG] Semantic diagnostics ${ enable ? 'enabled' : 'disabled' } ` )
219+ }
220+
221+ addShimForPackage ( pkg ) {
222+ if ( ! this . monaco ) return
223+ const tsDefaults = this . monaco . languages . typescript . typescriptDefaults
224+
225+ const shimMainPath = `file:///__shims__/${ pkg } .d.ts`
226+ const shimWildPath = `file:///__shims__/${ pkg } __wildcard.d.ts`
227+
228+ if ( ! this . shimDisposers . has ( shimMainPath ) ) {
229+ const d1 = tsDefaults . addExtraLib ( `declare module '${ pkg } ' { const _default: any\nexport = _default }` , shimMainPath )
230+ this . shimDisposers . set ( shimMainPath , d1 )
231+ }
232+
233+ if ( ! this . shimDisposers . has ( shimWildPath ) ) {
234+ const d2 = tsDefaults . addExtraLib ( `declare module '${ pkg } /*' { const _default: any\nexport = _default }` , shimWildPath )
235+ this . shimDisposers . set ( shimWildPath , d2 )
236+ }
237+
238+ this . tsModuleMappings [ pkg ] = [ shimMainPath . replace ( 'file:///' , '' ) ]
239+ this . tsModuleMappings [ `${ pkg } /*` ] = [ `${ pkg } /*` ]
240+ }
241+
242+ removeShimsForPackage ( pkg ) {
243+ const keys = [ `file:///__shims__/${ pkg } .d.ts` , `file:///__shims__/${ pkg } __wildcard.d.ts` ]
244+ for ( const k of keys ) {
245+ const disp = this . shimDisposers . get ( k )
246+ if ( disp && typeof disp . dispose === 'function' ) {
247+ disp . dispose ( )
248+ this . shimDisposers . delete ( k )
249+ }
250+ }
251+ }
252+
253+ beginTypesBatch ( ) {
254+ if ( this . typesLoadingCount === 0 ) {
255+ this . toggleTsDiagnostics ( false )
256+ this . triggerEvent ( 'typesLoading' , [ 'start' ] )
257+ console . log ( '[DIAGNOSE-BATCH] Types batch started' )
258+ }
259+ this . typesLoadingCount ++
260+ }
261+
262+ endTypesBatch ( ) {
263+ this . typesLoadingCount = Math . max ( 0 , this . typesLoadingCount - 1 )
264+ if ( this . typesLoadingCount === 0 ) {
265+ this . updateTsCompilerOptions ( )
266+ this . toggleTsDiagnostics ( true )
267+ this . triggerEvent ( 'typesLoading' , [ 'end' ] )
268+ console . log ( '[DIAGNOSE-BATCH] Types batch ended' )
269+ }
270+ }
271+
205272 addExtraLibs ( libs ) {
206273 if ( ! this . monaco || ! libs || libs . length === 0 ) return
207274 console . log ( `[DIAGNOSE-LIBS] Adding ${ libs . length } new files to Monaco...` )
@@ -230,7 +297,11 @@ export default class Editor extends Plugin {
230297 try {
231298 console . log ( '[DIAGNOSE-ONCHANGE] Change detected, analyzing imports...' )
232299 const extractPackageName = ( p ) => p . startsWith ( '@' ) ? p . split ( '/' ) . slice ( 0 , 2 ) . join ( '/' ) : p . split ( '/' ) [ 0 ]
233- const rawImports = [ ...code . matchAll ( / (?: f r o m | i m p o r t ) \s + [ ' " ] ( (? ! \. ) .* ?) [ ' " ] / g) ] . map ( match => match [ 1 ] )
300+ const IMPORT_ANY_RE =
301+ / (?: i m p o r t | e x p o r t ) \s + [ ^ ' " ] * ?f r o m \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] | i m p o r t \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] | r e q u i r e \( \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] \s * \) / g
302+ const rawImports = [ ...code . matchAll ( IMPORT_ANY_RE ) ]
303+ . map ( m => ( m [ 1 ] || m [ 2 ] || m [ 3 ] || '' ) . trim ( ) )
304+ . filter ( Boolean )
234305 const uniquePackages = [ ...new Set ( rawImports . map ( extractPackageName ) ) ]
235306
236307 const newPackages = uniquePackages . filter ( p => ! this . processedPackages . has ( p ) )
@@ -241,33 +312,84 @@ export default class Editor extends Plugin {
241312
242313 console . log ( '[DIAGNOSE-ONCHANGE] New packages to process:' , newPackages )
243314
315+ for ( const pkg of newPackages ) {
316+ this . addShimForPackage ( pkg )
317+ }
318+ this . updateTsCompilerOptions ( )
319+
320+ this . beginTypesBatch ( )
321+
244322 let newPathsFound = false
245- const promises = newPackages . map ( async ( pkg ) => {
246- this . processedPackages . add ( pkg )
247- const result = await startTypeLoadingProcess ( pkg )
248-
249- console . log ( `[DIAGNOSE-ONCHANGE] Result received for "${ pkg } ":` , result ? { mainVirtualPath : result . mainVirtualPath , libsCount : result . libs . length } : 'null' )
250-
251- if ( result && result . libs && result . libs . length > 0 ) {
252- this . addExtraLibs ( result . libs )
253-
254- if ( result . mainVirtualPath ) {
255- this . tsModuleMappings [ pkg ] = [ result . mainVirtualPath . replace ( 'file:///node_modules/' , '' ) ]
323+ await Promise . all ( newPackages . map ( async ( pkg ) => {
324+ try {
325+ this . processedPackages . add ( pkg )
326+
327+ const result = await startTypeLoadingProcess ( pkg )
328+ console . log ( `[DIAGNOSE-ONCHANGE] Result received for "${ pkg } ":` , result ? { mainVirtualPath : result . mainVirtualPath , libsCount : result . libs . length } : 'null' )
329+
330+ if ( result && result . libs && result . libs . length > 0 ) {
331+ this . addExtraLibs ( result . libs )
332+
333+ function cleanupBadPathKeys ( paths , pkg ) {
334+ for ( const k of Object . keys ( paths ) ) {
335+ const badDot = k . startsWith ( `${ pkg } .` )
336+ const noSlash = k . startsWith ( pkg ) && ! k . includes ( '/' ) && k !== pkg
337+ if ( badDot || noSlash ) delete paths [ k ]
338+ }
339+ }
340+
341+ cleanupBadPathKeys ( this . tsModuleMappings , pkg )
342+
343+ if ( result . subpathMap ) {
344+ if ( result . subpathMap ) {
345+ for ( const [ subpath , virtualPath ] of Object . entries ( result . subpathMap ) ) {
346+ this . tsModuleMappings [ subpath ] = [ virtualPath ]
347+ }
348+ }
349+ }
350+
351+ if ( result . mainVirtualPath ) {
352+ this . tsModuleMappings [ pkg ] = [ result . mainVirtualPath . replace ( 'file:///node_modules/' , '' ) ]
353+ } else {
354+ console . warn ( `[DIAGNOSE-ONCHANGE] No mainVirtualPath found for "${ pkg } ", path mapping may be incomplete` )
355+ }
356+
256357 this . tsModuleMappings [ `${ pkg } /*` ] = [ `${ pkg } /*` ]
358+
359+ const libsForPkg = result . libs . filter ( l => l . filePath . includes ( `/node_modules/${ pkg } /` ) )
360+ for ( const lib of libsForPkg ) {
361+ const asPath = lib . filePath . replace ( 'file:///node_modules/' , '' )
362+ if ( asPath . endsWith ( '/index.d.ts' ) ) {
363+ const dirSpec = asPath . replace ( '/index.d.ts' , '' )
364+ if ( dirSpec . startsWith ( `${ pkg } /` ) ) {
365+ this . tsModuleMappings [ dirSpec ] = [ asPath ]
366+ }
367+ }
368+ if ( asPath . endsWith ( '.d.ts' ) ) {
369+ const fileSpec = asPath . replace ( / \. d \. t s $ / , '' )
370+ if ( fileSpec . startsWith ( `${ pkg } /` ) ) {
371+ this . tsModuleMappings [ fileSpec ] = [ asPath ]
372+ }
373+ }
374+ }
375+
376+ this . removeShimsForPackage ( pkg )
257377 newPathsFound = true
258378 } else {
259- console . warn ( `[DIAGNOSE-ONCHANGE] No mainVirtualPath found for "${ pkg } ", path mapping will be incomplete. ` )
379+ console . warn ( `[DIAGNOSE-ONCHANGE] No types found for "${ pkg } ", keeping shim ` )
260380 }
381+ } catch ( e ) {
382+ console . error ( '[DIAGNOSE-ONCHANGE] Type load failed for' , pkg , e )
261383 }
262- } )
263- await Promise . all ( promises )
384+ } ) )
264385
265- if ( newPathsFound ) {
266- this . updateTsCompilerOptions ( )
267- } else {
268- console . log ( '[DIAGNOSE-ONCHANGE] No new paths were mapped.' )
269- }
386+ if ( newPathsFound ) {
387+ this . updateTsCompilerOptions ( )
388+ } else {
389+ console . log ( '[DIAGNOSE-ONCHANGE] No new paths were mapped.' )
390+ }
270391
392+ this . endTypesBatch ( )
271393 } catch ( error ) {
272394 console . error ( '[DIAGNOSE-ONCHANGE] Error during type loading process:' , error )
273395 }
0 commit comments