Skip to content

Commit 2e7eec1

Browse files
committed
Fix noResolution for named imports
1 parent 3c41892 commit 2e7eec1

File tree

3 files changed

+114
-14
lines changed

3 files changed

+114
-14
lines changed

src/LuaTransformer.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,26 @@ export class LuaTransformer {
376376
throw TSTLErrors.UnsupportedImportType(statement.importClause);
377377
}
378378

379-
const type = this.checker.getTypeAtLocation(imports);
380-
const shouldResolve = !tsHelper.getCustomDecorators(type, this.checker).has(DecoratorKind.NoResolution);
379+
let shouldResolve = true;
380+
if (ts.isNamedImports(imports)) {
381+
for (const importSpecifier of imports.elements) {
382+
const parentModule = tsHelper.getImportSpecifierModuleDeclaration(importSpecifier, this.checker);
383+
if (parentModule) {
384+
const type = this.checker.getTypeAtLocation(parentModule);
385+
const decorators = tsHelper.getCustomDecorators(type, this.checker);
386+
if (decorators.has(DecoratorKind.NoResolution)) {
387+
shouldResolve = false;
388+
break;
389+
}
390+
}
391+
}
392+
} else if (ts.isNamespaceImport(imports)) {
393+
const type = this.checker.getTypeAtLocation(imports);
394+
if (tsHelper.getCustomDecorators(type, this.checker).has(DecoratorKind.NoResolution)) {
395+
shouldResolve = false;
396+
}
397+
}
398+
381399
const requireCall = this.createModuleRequire(statement.moduleSpecifier as ts.StringLiteral, shouldResolve);
382400

383401
if (ts.isNamedImports(imports)) {

src/TSHelper.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ export class TSHelper {
131131
return !((ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Ambient) === 0);
132132
}
133133

134+
public static isNonNamespaceModuleDeclaration(node: ts.Node): node is ts.ModuleDeclaration {
135+
return ts.isModuleDeclaration(node) && (node.flags & ts.NodeFlags.Namespace) === 0;
136+
}
137+
134138
public static isStatic(node: ts.Node): boolean {
135139
return node.modifiers !== undefined && node.modifiers.some(m => m.kind === ts.SyntaxKind.StaticKeyword);
136140
}
@@ -354,6 +358,27 @@ export class TSHelper {
354358
return directivesMap;
355359
}
356360

361+
public static getImportSpecifierModuleDeclaration(
362+
node: ts.ImportSpecifier,
363+
checker: ts.TypeChecker
364+
): ts.ModuleDeclaration | undefined {
365+
const symbol = checker.getSymbolAtLocation(node.name);
366+
if (symbol) {
367+
const originalSymbol = checker.getAliasedSymbol(symbol);
368+
if (originalSymbol.declarations) {
369+
for (const declaration of originalSymbol.declarations) {
370+
const parentAmbientModule = this.findFirstNodeAbove(
371+
declaration,
372+
this.isNonNamespaceModuleDeclaration
373+
);
374+
if (parentAmbientModule) {
375+
return parentAmbientModule;
376+
}
377+
}
378+
}
379+
}
380+
}
381+
357382
// Search up until finding a node satisfying the callback
358383
public static findFirstNodeAbove<T extends ts.Node>(
359384
node: ts.Node,

test/unit/require.spec.ts

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,77 @@ test.each([
9191
}
9292
);
9393

94-
test.each([{ comment: "", expectedPath: "src.fake" }, { comment: "/** @noResolution */", expectedPath: "fake" }])(
95-
"noResolution on ambient modules causes no path alterations (%p)",
96-
({ comment, expectedPath }) => {
97-
const lua = util.transpileString({
98-
"src/main.ts": `import * as fake from "fake"; fake;`,
99-
"module.d.ts": `${comment} declare module "fake" {}`,
100-
});
101-
const match = requireRegex.exec(lua);
94+
test.each([
95+
{
96+
declarationStatement: `
97+
declare module 'fake' {}
98+
`,
99+
mainCode: "import * as fake from 'fake'; fake;",
100+
expectedPath: "src.fake",
101+
},
102+
{
103+
declarationStatement: `
104+
/** @noResolution */
105+
declare module 'fake' {}
106+
`,
107+
mainCode: "import * as fake from 'fake'; fake;",
108+
expectedPath: "fake",
109+
},
110+
{
111+
declarationStatement: `
112+
declare module 'fake' {
113+
export const x: number;
114+
}
115+
`,
116+
mainCode: "import { x } from 'fake'; x;",
117+
expectedPath: "src.fake",
118+
},
119+
{
120+
declarationStatement: `
121+
/** @noResolution */
122+
declare module 'fake' {
123+
export const x: number;
124+
}
125+
`,
126+
mainCode: "import { x } from 'fake'; x;",
127+
expectedPath: "fake",
128+
},
129+
{
130+
declarationStatement: `
131+
/** @noResolution */
132+
declare module 'fake' {
133+
export const x: number;
134+
}
135+
declare module 'fake' {
136+
export const y: number;
137+
}
138+
`,
139+
mainCode: "import { y } from 'fake'; y;",
140+
expectedPath: "fake",
141+
},
142+
{
143+
declarationStatement: `
144+
declare module 'fake' {
145+
export const x: number;
146+
}
147+
declare module 'fake' {
148+
export const y: number;
149+
}
150+
`,
151+
mainCode: "import { y } from 'fake'; y;",
152+
expectedPath: "src.fake",
153+
},
154+
])("noResolution prevents any module path resolution behaviour", ({ declarationStatement, mainCode, expectedPath }) => {
155+
const lua = util.transpileString({
156+
"src/main.ts": mainCode,
157+
"module.d.ts": declarationStatement,
158+
});
159+
const match = requireRegex.exec(lua);
102160

103-
if (util.expectToBeDefined(match)) {
104-
expect(match[1]).toBe(expectedPath);
105-
}
161+
if (util.expectToBeDefined(match)) {
162+
expect(match[1]).toBe(expectedPath);
106163
}
107-
);
164+
});
108165

109166
test("ImportEquals declaration require", () => {
110167
const input = `import foo = require("./foo/bar"); foo;`;

0 commit comments

Comments
 (0)