Skip to content

Commit 8cbc576

Browse files
ShuiRuTianorta
andauthored
* fix as suggestion. * Update moduleSpecifiers.ts * compare symbol rather than string * fix typo. * fix * fix lint. * better name and more clear code * fix comment. Co-authored-by: Orta Therox <[email protected]>
1 parent b217f22 commit 8cbc576

8 files changed

+260
-37
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5494,6 +5494,7 @@ namespace ts {
54945494
const specifierCompilerOptions = isBundle ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions;
54955495
specifier = first(moduleSpecifiers.getModuleSpecifiers(
54965496
symbol,
5497+
checker,
54975498
specifierCompilerOptions,
54985499
contextFile,
54995500
moduleResolverHost,

src/compiler/moduleNameResolver.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,8 +1422,7 @@ namespace ts {
14221422
export function getPackageNameFromTypesPackageName(mangledName: string): string {
14231423
const withoutAtTypePrefix = removePrefix(mangledName, "@types/");
14241424
if (withoutAtTypePrefix !== mangledName) {
1425-
const withoutAtTypeNodePrefix = removePrefix(withoutAtTypePrefix, "node/");
1426-
return unmangleScopedPackageName(withoutAtTypeNodePrefix);
1425+
return unmangleScopedPackageName(withoutAtTypePrefix);
14271426
}
14281427
return mangledName;
14291428
}

src/compiler/moduleSpecifiers.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,13 @@ namespace ts.moduleSpecifiers {
9292
/** Returns an import for each symlink and for the realpath. */
9393
export function getModuleSpecifiers(
9494
moduleSymbol: Symbol,
95+
checker: TypeChecker,
9596
compilerOptions: CompilerOptions,
9697
importingSourceFile: SourceFile,
9798
host: ModuleSpecifierResolutionHost,
9899
userPreferences: UserPreferences,
99100
): readonly string[] {
100-
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
101+
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol, checker);
101102
if (ambient) return [ambient];
102103

103104
const info = getInfo(importingSourceFile.path, host);
@@ -369,13 +370,49 @@ namespace ts.moduleSpecifiers {
369370
return sortedPaths;
370371
}
371372

372-
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
373+
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol, checker: TypeChecker): string | undefined {
373374
const decl = find(moduleSymbol.declarations,
374375
d => isNonGlobalAmbientModule(d) && (!isExternalModuleAugmentation(d) || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name)))
375376
) as (ModuleDeclaration & { name: StringLiteral }) | undefined;
376377
if (decl) {
377378
return decl.name.text;
378379
}
380+
381+
// the module could be a namespace, which is export through "export=" from an ambient module.
382+
/**
383+
* declare module "m" {
384+
* namespace ns {
385+
* class c {}
386+
* }
387+
* export = ns;
388+
* }
389+
*/
390+
// `import {c} from "m";` is valid, in which case, `moduleSymbol` is "ns", but the module name should be "m"
391+
const ambientModuleDeclareCandidates = mapDefined(moduleSymbol.declarations,
392+
d => {
393+
if (!isModuleDeclaration(d)) return;
394+
const topNamespace = getTopNamespace(d);
395+
if (!(topNamespace?.parent?.parent
396+
&& isModuleBlock(topNamespace.parent) && isAmbientModule(topNamespace.parent.parent) && isSourceFile(topNamespace.parent.parent.parent))) return;
397+
const exportAssignment = ((topNamespace.parent.parent.symbol.exports?.get("export=" as __String)?.valueDeclaration as ExportAssignment)?.expression as PropertyAccessExpression | Identifier);
398+
if (!exportAssignment) return;
399+
const exportSymbol = checker.getSymbolAtLocation(exportAssignment);
400+
if (!exportSymbol) return;
401+
const originalExportSymbol = exportSymbol?.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(exportSymbol) : exportSymbol;
402+
if (originalExportSymbol === d.symbol) return topNamespace.parent.parent;
403+
404+
function getTopNamespace(namespaceDeclaration: ModuleDeclaration) {
405+
while (namespaceDeclaration.flags & NodeFlags.NestedNamespace) {
406+
namespaceDeclaration = namespaceDeclaration.parent as ModuleDeclaration;
407+
}
408+
return namespaceDeclaration;
409+
}
410+
}
411+
);
412+
const ambientModuleDeclare = ambientModuleDeclareCandidates[0] as (AmbientModuleDeclaration & { name: StringLiteral }) | undefined;
413+
if (ambientModuleDeclare) {
414+
return ambientModuleDeclare.name.text;
415+
}
379416
}
380417

381418
function tryGetModuleNameFromPaths(relativeToBaseUrlWithIndex: string, relativeToBaseUrl: string, paths: MapLike<readonly string[]>): string | undefined {

src/services/codefixes/importFixes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ namespace ts.codefix {
404404
const { allowsImportingSpecifier } = createAutoImportFilter(sourceFile, program, host);
405405

406406
const choicesForEachExportingModule = flatMap(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) =>
407-
moduleSpecifiers.getModuleSpecifiers(moduleSymbol, compilerOptions, sourceFile, createModuleSpecifierResolutionHost(program, host) , preferences)
407+
moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getTypeChecker(), compilerOptions, sourceFile, createModuleSpecifierResolutionHost(program, host), preferences)
408408
.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
409409
// `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
410410
exportedSymbolIsTypeOnly && isJs

tests/baselines/reference/importDeclFromTypeNodeInJsSource.js

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,73 @@ declare module "events" {
1111
}
1212
export = EventEmitter;
1313
}
14+
declare module "nestNamespaceModule" {
15+
namespace a1.a2 {
16+
class d { }
17+
}
18+
19+
namespace a1.a2.n3 {
20+
class c { }
21+
}
22+
export = a1.a2;
23+
}
24+
declare module "renameModule" {
25+
namespace a.b {
26+
class c { }
27+
}
28+
import d = a.b;
29+
export = d;
30+
}
1431

1532
//// [b.js]
1633
import { EventEmitter } from 'events';
17-
class Foo extends EventEmitter {
18-
constructor() {
19-
super();
20-
}
34+
import { n3, d } from 'nestNamespaceModule';
35+
import { c } from 'renameModule';
36+
37+
export class Foo extends EventEmitter {
38+
}
39+
40+
export class Foo2 extends n3.c {
41+
}
42+
43+
export class Foo3 extends d {
2144
}
22-
export default Foo;
45+
46+
export class Foo4 extends c {
47+
48+
}
2349

2450
//// [b.js]
2551
"use strict";
2652
Object.defineProperty(exports, "__esModule", { value: true });
53+
exports.Foo4 = exports.Foo3 = exports.Foo2 = exports.Foo = void 0;
2754
const events_1 = require("events");
55+
const nestNamespaceModule_1 = require("nestNamespaceModule");
56+
const renameModule_1 = require("renameModule");
2857
class Foo extends events_1.EventEmitter {
29-
constructor() {
30-
super();
31-
}
3258
}
33-
exports.default = Foo;
59+
exports.Foo = Foo;
60+
class Foo2 extends nestNamespaceModule_1.n3.c {
61+
}
62+
exports.Foo2 = Foo2;
63+
class Foo3 extends nestNamespaceModule_1.d {
64+
}
65+
exports.Foo3 = Foo3;
66+
class Foo4 extends renameModule_1.c {
67+
}
68+
exports.Foo4 = Foo4;
3469

3570

3671
//// [b.d.ts]
37-
export default Foo;
38-
declare class Foo extends EventEmitter {
72+
export class Foo extends EventEmitter {
73+
}
74+
export class Foo2 extends n3.c {
75+
}
76+
export class Foo3 extends d {
77+
}
78+
export class Foo4 extends c {
3979
}
4080
import { EventEmitter } from "events";
81+
import { n3 } from "nestNamespaceModule";
82+
import { d } from "nestNamespaceModule";
83+
import { c } from "renameModule";

tests/baselines/reference/importDeclFromTypeNodeInJsSource.symbols

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,79 @@ declare module "events" {
1616
export = EventEmitter;
1717
>EventEmitter : Symbol(EventEmitter, Decl(events.d.ts, 0, 25))
1818
}
19+
declare module "nestNamespaceModule" {
20+
>"nestNamespaceModule" : Symbol("nestNamespaceModule", Decl(events.d.ts, 7, 1))
21+
22+
namespace a1.a2 {
23+
>a1 : Symbol(a1, Decl(events.d.ts, 8, 38), Decl(events.d.ts, 11, 5))
24+
>a2 : Symbol(a2, Decl(events.d.ts, 9, 17), Decl(events.d.ts, 13, 17))
25+
26+
class d { }
27+
>d : Symbol(d, Decl(events.d.ts, 9, 21))
28+
}
29+
30+
namespace a1.a2.n3 {
31+
>a1 : Symbol(a1, Decl(events.d.ts, 8, 38), Decl(events.d.ts, 11, 5))
32+
>a2 : Symbol(a2, Decl(events.d.ts, 9, 17), Decl(events.d.ts, 13, 17))
33+
>n3 : Symbol(n3, Decl(events.d.ts, 13, 20))
34+
35+
class c { }
36+
>c : Symbol(c, Decl(events.d.ts, 13, 24))
37+
}
38+
export = a1.a2;
39+
>a1.a2 : Symbol(a1.a2, Decl(events.d.ts, 9, 17), Decl(events.d.ts, 13, 17))
40+
>a1 : Symbol(a1, Decl(events.d.ts, 8, 38), Decl(events.d.ts, 11, 5))
41+
>a2 : Symbol(a1.a2, Decl(events.d.ts, 9, 17), Decl(events.d.ts, 13, 17))
42+
}
43+
declare module "renameModule" {
44+
>"renameModule" : Symbol("renameModule", Decl(events.d.ts, 17, 1))
45+
46+
namespace a.b {
47+
>a : Symbol(a, Decl(events.d.ts, 18, 31))
48+
>b : Symbol(b, Decl(events.d.ts, 19, 16))
49+
50+
class c { }
51+
>c : Symbol(c, Decl(events.d.ts, 19, 19))
52+
}
53+
import d = a.b;
54+
>d : Symbol(d, Decl(events.d.ts, 21, 5))
55+
>a : Symbol(a, Decl(events.d.ts, 18, 31))
56+
>b : Symbol(d, Decl(events.d.ts, 19, 16))
57+
58+
export = d;
59+
>d : Symbol(d, Decl(events.d.ts, 21, 5))
60+
}
1961

2062
=== /src/b.js ===
2163
import { EventEmitter } from 'events';
2264
>EventEmitter : Symbol(EventEmitter, Decl(b.js, 0, 8))
2365

24-
class Foo extends EventEmitter {
25-
>Foo : Symbol(Foo, Decl(b.js, 0, 38))
66+
import { n3, d } from 'nestNamespaceModule';
67+
>n3 : Symbol(n3, Decl(b.js, 1, 8))
68+
>d : Symbol(d, Decl(b.js, 1, 12))
69+
70+
import { c } from 'renameModule';
71+
>c : Symbol(c, Decl(b.js, 2, 8))
72+
73+
export class Foo extends EventEmitter {
74+
>Foo : Symbol(Foo, Decl(b.js, 2, 33))
2675
>EventEmitter : Symbol(EventEmitter, Decl(b.js, 0, 8))
76+
}
2777

28-
constructor() {
29-
super();
30-
>super : Symbol(EventEmitter, Decl(events.d.ts, 1, 28))
31-
}
78+
export class Foo2 extends n3.c {
79+
>Foo2 : Symbol(Foo2, Decl(b.js, 5, 1))
80+
>n3.c : Symbol(n3.c, Decl(events.d.ts, 13, 24))
81+
>n3 : Symbol(n3, Decl(b.js, 1, 8))
82+
>c : Symbol(n3.c, Decl(events.d.ts, 13, 24))
83+
}
84+
85+
export class Foo3 extends d {
86+
>Foo3 : Symbol(Foo3, Decl(b.js, 8, 1))
87+
>d : Symbol(d, Decl(b.js, 1, 12))
3288
}
33-
export default Foo;
34-
>Foo : Symbol(Foo, Decl(b.js, 0, 38))
3589

90+
export class Foo4 extends c {
91+
>Foo4 : Symbol(Foo4, Decl(b.js, 11, 1))
92+
>c : Symbol(c, Decl(b.js, 2, 8))
93+
94+
}

tests/baselines/reference/importDeclFromTypeNodeInJsSource.types

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,79 @@ declare module "events" {
1616
export = EventEmitter;
1717
>EventEmitter : typeof EventEmitter
1818
}
19+
declare module "nestNamespaceModule" {
20+
>"nestNamespaceModule" : typeof import("nestNamespaceModule")
21+
22+
namespace a1.a2 {
23+
>a1 : typeof a1
24+
>a2 : typeof a2
25+
26+
class d { }
27+
>d : d
28+
}
29+
30+
namespace a1.a2.n3 {
31+
>a1 : typeof a1
32+
>a2 : typeof a2
33+
>n3 : typeof n3
34+
35+
class c { }
36+
>c : c
37+
}
38+
export = a1.a2;
39+
>a1.a2 : typeof a1.a2
40+
>a1 : typeof a1
41+
>a2 : typeof a1.a2
42+
}
43+
declare module "renameModule" {
44+
>"renameModule" : typeof import("renameModule")
45+
46+
namespace a.b {
47+
>a : typeof a
48+
>b : typeof b
49+
50+
class c { }
51+
>c : c
52+
}
53+
import d = a.b;
54+
>d : typeof d
55+
>a : typeof a
56+
>b : typeof d
57+
58+
export = d;
59+
>d : typeof d
60+
}
1961

2062
=== /src/b.js ===
2163
import { EventEmitter } from 'events';
2264
>EventEmitter : typeof EventEmitter
2365

24-
class Foo extends EventEmitter {
66+
import { n3, d } from 'nestNamespaceModule';
67+
>n3 : typeof n3
68+
>d : typeof d
69+
70+
import { c } from 'renameModule';
71+
>c : typeof c
72+
73+
export class Foo extends EventEmitter {
2574
>Foo : Foo
2675
>EventEmitter : EventEmitter
76+
}
2777

28-
constructor() {
29-
super();
30-
>super() : void
31-
>super : typeof EventEmitter
32-
}
78+
export class Foo2 extends n3.c {
79+
>Foo2 : Foo2
80+
>n3.c : n3.c
81+
>n3 : typeof n3
82+
>c : typeof n3.c
83+
}
84+
85+
export class Foo3 extends d {
86+
>Foo3 : Foo3
87+
>d : d
3388
}
34-
export default Foo;
35-
>Foo : Foo
3689

90+
export class Foo4 extends c {
91+
>Foo4 : Foo4
92+
>c : c
93+
94+
}

tests/cases/compiler/importDeclFromTypeNodeInJsSource.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,38 @@ declare module "events" {
1515
}
1616
export = EventEmitter;
1717
}
18+
declare module "nestNamespaceModule" {
19+
namespace a1.a2 {
20+
class d { }
21+
}
22+
23+
namespace a1.a2.n3 {
24+
class c { }
25+
}
26+
export = a1.a2;
27+
}
28+
declare module "renameModule" {
29+
namespace a.b {
30+
class c { }
31+
}
32+
import d = a.b;
33+
export = d;
34+
}
1835

1936
// @filename: /src/b.js
2037
import { EventEmitter } from 'events';
21-
class Foo extends EventEmitter {
22-
constructor() {
23-
super();
24-
}
38+
import { n3, d } from 'nestNamespaceModule';
39+
import { c } from 'renameModule';
40+
41+
export class Foo extends EventEmitter {
42+
}
43+
44+
export class Foo2 extends n3.c {
2545
}
26-
export default Foo;
46+
47+
export class Foo3 extends d {
48+
}
49+
50+
export class Foo4 extends c {
51+
52+
}

0 commit comments

Comments
 (0)