@@ -245,9 +245,12 @@ func (t *parseTask) start(loader *fileLoader) {
245
245
loader .wg .Queue (func () {
246
246
file := loader .parseSourceFile (t .normalizedFilePath )
247
247
t .file = file
248
- loader .wg .Queue (func () {
249
- t .metadata = loader .loadSourceFileMetaData (file .Path ())
250
- })
248
+ t .metadata = loader .loadSourceFileMetaData (file .Path ())
249
+
250
+ fileWithMetadata := & fileWithMetadata {
251
+ file : file ,
252
+ meta : t .metadata ,
253
+ }
251
254
252
255
// !!! if noResolve, skip all of this
253
256
t .subTasks = make ([]* parseTask , 0 , len (file .ReferencedFiles )+ len (file .Imports )+ len (file .ModuleAugmentations ))
@@ -258,7 +261,8 @@ func (t *parseTask) start(loader *fileLoader) {
258
261
}
259
262
260
263
for _ , ref := range file .TypeReferenceDirectives {
261
- resolved := loader .resolver .ResolveTypeReferenceDirective (ref .FileName , file .FileName (), core .ModuleKindCommonJS /* !!! */ , nil )
264
+ resolutionMode := getModeForTypeReferenceDirectiveInFile (ref , fileWithMetadata , loader .compilerOptions )
265
+ resolved := loader .resolver .ResolveTypeReferenceDirective (ref .FileName , file .FileName (), resolutionMode , nil )
262
266
if resolved .IsResolved () {
263
267
t .addSubTask (resolved .ResolvedFileName , false )
264
268
}
@@ -274,7 +278,7 @@ func (t *parseTask) start(loader *fileLoader) {
274
278
}
275
279
}
276
280
277
- toParse , resolutionsInFile , importHelpersImportSpecifier , jsxRuntimeImportSpecifier := loader .resolveImportsAndModuleAugmentations (file )
281
+ toParse , resolutionsInFile , importHelpersImportSpecifier , jsxRuntimeImportSpecifier := loader .resolveImportsAndModuleAugmentations (fileWithMetadata )
278
282
for _ , imp := range toParse {
279
283
t .addSubTask (imp , false )
280
284
}
@@ -319,12 +323,13 @@ func (p *fileLoader) resolveTripleslashPathReference(moduleName string, containi
319
323
320
324
const externalHelpersModuleNameText = "tslib" // TODO(jakebailey): dedupe
321
325
322
- func (p * fileLoader ) resolveImportsAndModuleAugmentations (file * ast. SourceFile ) (
326
+ func (p * fileLoader ) resolveImportsAndModuleAugmentations (item * fileWithMetadata ) (
323
327
toParse []string ,
324
328
resolutionsInFile module.ModeAwareCache [* module.ResolvedModule ],
325
329
importHelpersImportSpecifier * ast.Node ,
326
330
jsxRuntimeImportSpecifier_ * jsxRuntimeImportSpecifier ,
327
331
) {
332
+ file := item .file
328
333
moduleNames := make ([]* ast.Node , 0 , len (file .Imports )+ len (file .ModuleAugmentations )+ 2 )
329
334
moduleNames = append (moduleNames , file .Imports ... )
330
335
for _ , imp := range file .ModuleAugmentations {
@@ -358,16 +363,17 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile)
358
363
if len (moduleNames ) != 0 {
359
364
toParse = make ([]string , 0 , len (moduleNames ))
360
365
361
- resolutions := p .resolveModuleNames (moduleNames , file )
366
+ resolutions := p .resolveModuleNames (moduleNames , item )
367
+ optionsForFile := p .getCompilerOptionsForFile (file )
362
368
363
369
resolutionsInFile = make (module.ModeAwareCache [* module.ResolvedModule ], len (resolutions ))
364
370
365
- for i , resolution := range resolutions {
366
- resolvedFileName := resolution .ResolvedFileName
371
+ for _ , resolution := range resolutions {
372
+ resolvedFileName := resolution .resolvedModule . ResolvedFileName
367
373
// TODO(ercornel): !!!: check if from node modules
368
374
369
- mode := core . ModuleKindCommonJS // !!!
370
- resolutionsInFile [module.ModeAwareCacheKey {Name : moduleNames [ i ]. Text (), Mode : mode }] = resolution
375
+ mode := getModeForUsageLocation ( item , resolution . node , optionsForFile )
376
+ resolutionsInFile [module.ModeAwareCacheKey {Name : resolution . node . Text (), Mode : mode }] = resolution . resolvedModule
371
377
372
378
// add file to program only if:
373
379
// - resolution was successful
@@ -387,7 +393,7 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile)
387
393
} else {
388
394
hasAllowedExtension = tspath .FileExtensionIsOneOf (resolvedFileName , tspath .SupportedTSExtensionsFlat )
389
395
}
390
- shouldAddFile := resolution .IsResolved () && hasAllowedExtension
396
+ shouldAddFile := resolution .resolvedModule . IsResolved () && hasAllowedExtension
391
397
// TODO(ercornel): !!!: other checks on whether or not to add the file
392
398
393
399
if shouldAddFile {
@@ -400,20 +406,20 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile)
400
406
return toParse , resolutionsInFile , importHelpersImportSpecifier , jsxRuntimeImportSpecifier_
401
407
}
402
408
403
- func (p * fileLoader ) resolveModuleNames (entries []* ast.Node , file * ast. SourceFile ) []* module. ResolvedModule {
409
+ func (p * fileLoader ) resolveModuleNames (entries []* ast.Node , item * fileWithMetadata ) []* resolution {
404
410
if len (entries ) == 0 {
405
411
return nil
406
412
}
407
413
408
- resolvedModules := make ([]* module. ResolvedModule , 0 , len (entries ))
414
+ resolvedModules := make ([]* resolution , 0 , len (entries ))
409
415
410
416
for _ , entry := range entries {
411
417
moduleName := entry .Text ()
412
418
if moduleName == "" {
413
419
continue
414
420
}
415
- resolvedModule := p .resolver .ResolveModuleName (moduleName , file .FileName (), core . ModuleKindCommonJS /* !!! */ , nil )
416
- resolvedModules = append (resolvedModules , resolvedModule )
421
+ resolvedModule := p .resolver .ResolveModuleName (moduleName , item . file .FileName (), item . meta . ImpliedNodeFormat , nil )
422
+ resolvedModules = append (resolvedModules , & resolution { node : entry , resolvedModule : resolvedModule } )
417
423
}
418
424
419
425
return resolvedModules
@@ -431,3 +437,116 @@ func (p *fileLoader) createSyntheticImport(text string, file *ast.SourceFile) *a
431
437
// !!! importDecl.Flags &^= ast.NodeFlagsSynthesized
432
438
return externalHelpersModuleReference
433
439
}
440
+
441
+ type fileWithMetadata struct {
442
+ file * ast.SourceFile
443
+ meta * ast.SourceFileMetaData
444
+ }
445
+
446
+ type resolution struct {
447
+ node * ast.Node
448
+ resolvedModule * module.ResolvedModule
449
+ }
450
+
451
+ func (p * fileLoader ) getCompilerOptionsForFile (file * ast.SourceFile ) * core.CompilerOptions {
452
+ // !!! return getRedirectReferenceForResolution(file)?.commandLine.options || options;
453
+ return p .compilerOptions
454
+ }
455
+
456
+ func getModeForTypeReferenceDirectiveInFile (ref * ast.FileReference , item * fileWithMetadata , options * core.CompilerOptions ) core.ResolutionMode {
457
+ if ref .ResolutionMode != core .ResolutionModeNone {
458
+ return ref .ResolutionMode
459
+ } else {
460
+ return getDefaultResolutionModeForFile (item , options )
461
+ }
462
+ }
463
+
464
+ func getDefaultResolutionModeForFile (item * fileWithMetadata , options * core.CompilerOptions ) core.ResolutionMode {
465
+ if importSyntaxAffectsModuleResolution (options ) {
466
+ return ast .GetImpliedNodeFormatForEmitWorker (item .file .FileName (), options , item .meta )
467
+ } else {
468
+ return core .ResolutionModeNone
469
+ }
470
+ }
471
+
472
+ func getModeForUsageLocation (item * fileWithMetadata , usage * ast.Node , options * core.CompilerOptions ) core.ResolutionMode {
473
+ if ast .IsImportDeclaration (usage .Parent ) || ast .IsExportDeclaration (usage .Parent ) || ast .IsJSDocImportTag (usage .Parent ) {
474
+ isTypeOnly := ast .IsExclusivelyTypeOnlyImportOrExport (usage .Parent )
475
+ if isTypeOnly {
476
+ var override core.ResolutionMode
477
+ var ok bool
478
+ switch usage .Parent .Kind {
479
+ case ast .KindImportDeclaration :
480
+ override , ok = usage .Parent .AsImportDeclaration ().Attributes .GetResolutionModeOverride ()
481
+ case ast .KindExportDeclaration :
482
+ override , ok = usage .Parent .AsExportDeclaration ().Attributes .GetResolutionModeOverride ()
483
+ case ast .KindJSDocImportTag :
484
+ override , ok = usage .Parent .AsJSDocImportTag ().Attributes .GetResolutionModeOverride ()
485
+ }
486
+ if ok {
487
+ return override
488
+ }
489
+ }
490
+ }
491
+ if usage .Parent .Parent != nil && ast .IsImportTypeNode (usage .Parent .Parent ) {
492
+ if override , ok := usage .Parent .Parent .AsImportTypeNode ().Attributes .GetResolutionModeOverride (); ok {
493
+ return override
494
+ }
495
+ }
496
+
497
+ if options != nil && importSyntaxAffectsModuleResolution (options ) {
498
+ return getEmitSyntaxForUsageLocationWorker (item , usage , options )
499
+ }
500
+
501
+ return core .ResolutionModeNone
502
+ }
503
+
504
+ func importSyntaxAffectsModuleResolution (options * core.CompilerOptions ) bool {
505
+ moduleResolution := options .ModuleResolution
506
+ return core .ModuleResolutionKindNode16 <= moduleResolution && moduleResolution <= core .ModuleResolutionKindNodeNext ||
507
+ options .ResolvePackageJsonExports .IsTrue () || options .ResolvePackageJsonImports .IsTrue ()
508
+ }
509
+
510
+ func getEmitSyntaxForUsageLocationWorker (item * fileWithMetadata , usage * ast.Node , options * core.CompilerOptions ) core.ResolutionMode {
511
+ if options == nil {
512
+ // This should always be provided, but we try to fail somewhat
513
+ // gracefully to allow projects like ts-node time to update.
514
+ return core .ResolutionModeNone
515
+ }
516
+
517
+ exprParentParent := ast .WalkUpParenthesizedExpressions (usage .Parent ).Parent
518
+ if exprParentParent != nil && ast .IsImportEqualsDeclaration (exprParentParent ) || ast .IsRequireCall (usage .Parent ) {
519
+ return core .ModuleKindCommonJS
520
+ }
521
+ if ast .IsImportCall (ast .WalkUpParenthesizedExpressions (usage .Parent )) {
522
+ if shouldTransformImportCallWorker (item , options ) {
523
+ return core .ModuleKindCommonJS
524
+ } else {
525
+ return core .ModuleKindESNext
526
+ }
527
+ }
528
+ // If we're in --module preserve on an input file, we know that an import
529
+ // is an import. But if this is a declaration file, we'd prefer to use the
530
+ // impliedNodeFormat. Since we want things to be consistent between the two,
531
+ // we need to issue errors when the user writes ESM syntax in a definitely-CJS
532
+ // file, until/unless declaration emit can indicate a true ESM import. On the
533
+ // other hand, writing CJS syntax in a definitely-ESM file is fine, since declaration
534
+ // emit preserves the CJS syntax.
535
+ fileEmitMode := ast .GetEmitModuleFormatOfFileWorker (item .file , options , item .meta )
536
+ if fileEmitMode == core .ModuleKindCommonJS {
537
+ return core .ModuleKindCommonJS
538
+ } else {
539
+ if fileEmitMode .IsNonNodeESM () || fileEmitMode == core .ModuleKindPreserve {
540
+ return core .ModuleKindESNext
541
+ }
542
+ }
543
+ return core .ModuleKindNone
544
+ }
545
+
546
+ func shouldTransformImportCallWorker (item * fileWithMetadata , options * core.CompilerOptions ) bool {
547
+ moduleKind := options .GetEmitModuleKind ()
548
+ if core .ModuleKindNode16 <= moduleKind && moduleKind <= core .ModuleKindNodeNext || moduleKind == core .ModuleKindPreserve {
549
+ return false
550
+ }
551
+ return ast .GetImpliedNodeFormatForEmitWorker (item .file .FileName (), options , item .meta ) < core .ModuleKindES2015
552
+ }
0 commit comments