From dbc29d038de85267152667abddf9a4623951f11c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 24 Aug 2020 10:13:47 -0700 Subject: [PATCH] Fix commonjs require of ES export The commonjs-specific code for resolving access expressions on `require` assumes a fake commonjs export. For real exports, it needs to call resolveSymbol since it's outside the normal alias-resolving infrastructure. --- src/compiler/checker.ts | 2 +- .../requireOfESWithPropertyAccess.errors.txt | 16 +++++++++ .../requireOfESWithPropertyAccess.js | 36 +++++++++++++++++++ .../requireOfESWithPropertyAccess.symbols | 29 +++++++++++++++ .../requireOfESWithPropertyAccess.types | 36 +++++++++++++++++++ .../salsa/requireOfESWithPropertyAccess.ts | 16 +++++++++ 6 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/requireOfESWithPropertyAccess.errors.txt create mode 100644 tests/baselines/reference/requireOfESWithPropertyAccess.js create mode 100644 tests/baselines/reference/requireOfESWithPropertyAccess.symbols create mode 100644 tests/baselines/reference/requireOfESWithPropertyAccess.types create mode 100644 tests/cases/conformance/salsa/requireOfESWithPropertyAccess.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9d9364a12f6d7..1eb750c8939ba 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2412,7 +2412,7 @@ namespace ts { if (isVariableDeclaration(node) && node.initializer && isPropertyAccessExpression(node.initializer)) { const name = (getLeftmostPropertyAccessExpression(node.initializer.expression) as CallExpression).arguments[0] as StringLiteral; return isIdentifier(node.initializer.name) - ? getPropertyOfType(resolveExternalModuleTypeByLiteral(name), node.initializer.name.escapedText) + ? resolveSymbol(getPropertyOfType(resolveExternalModuleTypeByLiteral(name), node.initializer.name.escapedText)) : undefined; } if (isVariableDeclaration(node) || node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { diff --git a/tests/baselines/reference/requireOfESWithPropertyAccess.errors.txt b/tests/baselines/reference/requireOfESWithPropertyAccess.errors.txt new file mode 100644 index 0000000000000..22d07045f1a84 --- /dev/null +++ b/tests/baselines/reference/requireOfESWithPropertyAccess.errors.txt @@ -0,0 +1,16 @@ +tests/cases/conformance/salsa/main.js(4,3): error TS2339: Property 'x' does not exist on type '{ grey: {}; }'. + + +==== tests/cases/conformance/salsa/main.js (1 errors) ==== + const x = require('./ch').x + x + x.grey + x.x.grey + ~ +!!! error TS2339: Property 'x' does not exist on type '{ grey: {}; }'. +==== tests/cases/conformance/salsa/ch.js (0 errors) ==== + const x = { + grey: {} + } + export { x } + \ No newline at end of file diff --git a/tests/baselines/reference/requireOfESWithPropertyAccess.js b/tests/baselines/reference/requireOfESWithPropertyAccess.js new file mode 100644 index 0000000000000..37a48dab177cb --- /dev/null +++ b/tests/baselines/reference/requireOfESWithPropertyAccess.js @@ -0,0 +1,36 @@ +//// [tests/cases/conformance/salsa/requireOfESWithPropertyAccess.ts] //// + +//// [main.js] +const x = require('./ch').x +x +x.grey +x.x.grey +//// [ch.js] +const x = { + grey: {} +} +export { x } + + +//// [ch.js] +"use strict"; +exports.__esModule = true; +exports.x = void 0; +var x = { + grey: {} +}; +exports.x = x; +//// [main.js] +"use strict"; +var x = require('./ch').x; +x; +x.grey; +x.x.grey; + + +//// [ch.d.ts] +export namespace x { + const grey: {}; +} +//// [main.d.ts] +export {}; diff --git a/tests/baselines/reference/requireOfESWithPropertyAccess.symbols b/tests/baselines/reference/requireOfESWithPropertyAccess.symbols new file mode 100644 index 0000000000000..04d0e841875e3 --- /dev/null +++ b/tests/baselines/reference/requireOfESWithPropertyAccess.symbols @@ -0,0 +1,29 @@ +=== tests/cases/conformance/salsa/main.js === +const x = require('./ch').x +>x : Symbol(x, Decl(main.js, 0, 5)) +>require('./ch').x : Symbol(x, Decl(ch.js, 3, 8)) +>require : Symbol(require) +>'./ch' : Symbol("tests/cases/conformance/salsa/ch", Decl(ch.js, 0, 0)) +>x : Symbol(x, Decl(ch.js, 3, 8)) + +x +>x : Symbol(x, Decl(main.js, 0, 5)) + +x.grey +>x.grey : Symbol(grey, Decl(ch.js, 0, 11)) +>x : Symbol(x, Decl(main.js, 0, 5)) +>grey : Symbol(grey, Decl(ch.js, 0, 11)) + +x.x.grey +>x : Symbol(x, Decl(main.js, 0, 5)) + +=== tests/cases/conformance/salsa/ch.js === +const x = { +>x : Symbol(x, Decl(ch.js, 0, 5)) + + grey: {} +>grey : Symbol(grey, Decl(ch.js, 0, 11)) +} +export { x } +>x : Symbol(x, Decl(ch.js, 3, 8)) + diff --git a/tests/baselines/reference/requireOfESWithPropertyAccess.types b/tests/baselines/reference/requireOfESWithPropertyAccess.types new file mode 100644 index 0000000000000..77dc133001544 --- /dev/null +++ b/tests/baselines/reference/requireOfESWithPropertyAccess.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/salsa/main.js === +const x = require('./ch').x +>x : { grey: {}; } +>require('./ch').x : { grey: {}; } +>require('./ch') : typeof import("tests/cases/conformance/salsa/ch") +>require : any +>'./ch' : "./ch" +>x : { grey: {}; } + +x +>x : { grey: {}; } + +x.grey +>x.grey : {} +>x : { grey: {}; } +>grey : {} + +x.x.grey +>x.x.grey : any +>x.x : any +>x : { grey: {}; } +>x : any +>grey : any + +=== tests/cases/conformance/salsa/ch.js === +const x = { +>x : { grey: {}; } +>{ grey: {}} : { grey: {}; } + + grey: {} +>grey : {} +>{} : {} +} +export { x } +>x : { grey: {}; } + diff --git a/tests/cases/conformance/salsa/requireOfESWithPropertyAccess.ts b/tests/cases/conformance/salsa/requireOfESWithPropertyAccess.ts new file mode 100644 index 0000000000000..2b21461f84202 --- /dev/null +++ b/tests/cases/conformance/salsa/requireOfESWithPropertyAccess.ts @@ -0,0 +1,16 @@ +// @allowJs: true +// @checkJs: true +// @strict: true +// @outDir: out +// @declaration: true + +// @filename: main.js +const x = require('./ch').x +x +x.grey +x.x.grey +// @filename: ch.js +const x = { + grey: {} +} +export { x }