From 75e71a431e5be9c7fddf56fa64d029afccf1ed65 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 19 Aug 2020 12:17:55 -0700 Subject: [PATCH] Fixes crash on chained property access on require From the user tests: ```js const x = require('y').z.ka ``` would cause the crash because I forgot to call getLeftMmostPropertyAccessExpression in one place. Note that this doesn't fix the alias, it just stops the crash. --- src/compiler/checker.ts | 2 +- .../reference/requireTwoPropertyAccesses.js | 24 +++++++++++++ .../requireTwoPropertyAccesses.symbols | 30 ++++++++++++++++ .../requireTwoPropertyAccesses.types | 36 +++++++++++++++++++ .../salsa/requireTwoPropertyAccesses.ts | 13 +++++++ 5 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/requireTwoPropertyAccesses.js create mode 100644 tests/baselines/reference/requireTwoPropertyAccesses.symbols create mode 100644 tests/baselines/reference/requireTwoPropertyAccesses.types create mode 100644 tests/cases/conformance/salsa/requireTwoPropertyAccesses.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 242e096ce4e52..fb2ced43757c4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2394,7 +2394,7 @@ namespace ts { function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration | VariableDeclaration, dontResolveAlias: boolean): Symbol | undefined { if (isVariableDeclaration(node) && node.initializer && isPropertyAccessExpression(node.initializer)) { - const name = (node.initializer.expression as CallExpression).arguments[0] as StringLiteral; + const name = (getLeftmostPropertyAccessExpression(node.initializer.expression) as CallExpression).arguments[0] as StringLiteral; return isIdentifier(node.initializer.name) ? getPropertyOfType(resolveExternalModuleTypeByLiteral(name), node.initializer.name.escapedText) : undefined; diff --git a/tests/baselines/reference/requireTwoPropertyAccesses.js b/tests/baselines/reference/requireTwoPropertyAccesses.js new file mode 100644 index 0000000000000..6847ce9e74e33 --- /dev/null +++ b/tests/baselines/reference/requireTwoPropertyAccesses.js @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/salsa/requireTwoPropertyAccesses.ts] //// + +//// [mod.js] +// @declaration +module.exports = { + x: { + y: "value" + } +} +//// [requireTwoPropertyAccesses.js] +const value = require("./mod").x.y +console.log(value) + + +//// [mod.js] +// @declaration +module.exports = { + x: { + y: "value" + } +}; +//// [requireTwoPropertyAccesses.js] +var value = require("./mod").x.y; +console.log(value); diff --git a/tests/baselines/reference/requireTwoPropertyAccesses.symbols b/tests/baselines/reference/requireTwoPropertyAccesses.symbols new file mode 100644 index 0000000000000..9102201a10118 --- /dev/null +++ b/tests/baselines/reference/requireTwoPropertyAccesses.symbols @@ -0,0 +1,30 @@ +=== tests/cases/conformance/salsa/requireTwoPropertyAccesses.js === +const value = require("./mod").x.y +>value : Symbol(value, Decl(requireTwoPropertyAccesses.js, 0, 5)) +>require("./mod").x.y : Symbol(y, Decl(mod.js, 2, 8)) +>require("./mod").x : Symbol(x, Decl(mod.js, 1, 18)) +>require : Symbol(require) +>"./mod" : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0)) +>x : Symbol(x, Decl(mod.js, 1, 18)) +>y : Symbol(y, Decl(mod.js, 2, 8)) + +console.log(value) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>value : Symbol(value, Decl(requireTwoPropertyAccesses.js, 0, 5)) + +=== tests/cases/conformance/salsa/mod.js === +// @declaration +module.exports = { +>module.exports : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0)) +>module : Symbol(export=, Decl(mod.js, 0, 0)) +>exports : Symbol(export=, Decl(mod.js, 0, 0)) + + x: { +>x : Symbol(x, Decl(mod.js, 1, 18)) + + y: "value" +>y : Symbol(y, Decl(mod.js, 2, 8)) + } +} diff --git a/tests/baselines/reference/requireTwoPropertyAccesses.types b/tests/baselines/reference/requireTwoPropertyAccesses.types new file mode 100644 index 0000000000000..c16098568ba0c --- /dev/null +++ b/tests/baselines/reference/requireTwoPropertyAccesses.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/salsa/requireTwoPropertyAccesses.js === +const value = require("./mod").x.y +>value : error +>require("./mod").x.y : string +>require("./mod").x : { y: string; } +>require("./mod") : { x: { y: string; }; } +>require : any +>"./mod" : "./mod" +>x : { y: string; } +>y : string + +console.log(value) +>console.log(value) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>value : error + +=== tests/cases/conformance/salsa/mod.js === +// @declaration +module.exports = { +>module.exports = { x: { y: "value" }} : { x: { y: string; }; } +>module.exports : { x: { y: string; }; } +>module : { "\"tests/cases/conformance/salsa/mod\"": { x: { y: string; }; }; } +>exports : { x: { y: string; }; } +>{ x: { y: "value" }} : { x: { y: string; }; } + + x: { +>x : { y: string; } +>{ y: "value" } : { y: string; } + + y: "value" +>y : string +>"value" : "value" + } +} diff --git a/tests/cases/conformance/salsa/requireTwoPropertyAccesses.ts b/tests/cases/conformance/salsa/requireTwoPropertyAccesses.ts new file mode 100644 index 0000000000000..92ff0df88393d --- /dev/null +++ b/tests/cases/conformance/salsa/requireTwoPropertyAccesses.ts @@ -0,0 +1,13 @@ +// @declaration +// @outdir: out +// @checkjs: true +// @allowjs: true +// @filename: mod.js +module.exports = { + x: { + y: "value" + } +} +// @filename: requireTwoPropertyAccesses.js +const value = require("./mod").x.y +console.log(value)