From 738e7d70edd4374cd46cf92549d5b1f7d835e4fa Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Tue, 27 Oct 2026 16:53:23 +0100 Subject: [PATCH] test(lexer): cover TypeScript default reexports in extended mode TypeScript emits default reexports with an __importDefault call inside a getter. Default mode excludes the name because the call falls outside its getter patterns. Extended mode must retain the name even after an exports.bar = void 0 declaration. Refs: https://github.com/nodejs/cjs-module-lexer/issues/76 Signed-off-by: Ruben Bridgewater --- README.md | 1 + test/extended.js | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/README.md b/README.md index 7d3305a..7e6f695 100755 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ Both modes use the existing lexer and assume valid JavaScript input. They do not execute the source or validate the complete JavaScript grammar. Extended mode detects literal names in `Object.defineProperty` calls regardless of the descriptor expression or getter body. +This includes TypeScript default reexports whose getters call `__importDefault`. It also detects names in object literals passed to `Object.defineProperties(exports, ...)` or assigned to `module.exports`. Object values can contain arbitrary expressions. Methods, accessors, and computed string literal keys contribute their names. diff --git a/test/extended.js b/test/extended.js index 765909f..bfca4ed 100644 --- a/test/extended.js +++ b/test/extended.js @@ -84,6 +84,31 @@ suite('Extended parsing', () => { 'fixture.cjs', options), { exports: ['name'], reexports: [] }); }); + for (const helper of ['__importDefault', 'tslib_1.__importDefault']) { + for (const predeclare of [false, true]) { + test(`TypeScript default reexports with ${helper} and predeclaration ${predeclare}`, () => { + const source = ` + "use strict"; + var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; + }; + ${helper === '__importDefault' ? '' : 'var tslib_1 = require("tslib");'} + Object.defineProperty(exports, "__esModule", { value: true }); + ${predeclare ? 'exports.bar = void 0;' : ''} + var bar_1 = require("./bar"); + Object.defineProperty(exports, "bar", { + enumerable: true, get: function () { return ${helper}(bar_1).default; } + }); + `; + assert.deepEqual(parse(source, 'typescript.cjs'), { exports: ['__esModule'], reexports: [] }); + assert.deepEqual(parse(source, 'typescript.cjs', options), + { exports: ['__esModule', 'bar'], reexports: [] }); + assert.deepEqual(parse(source, 'typescript.cjs', { mode: 'default' }), + { exports: ['__esModule'], reexports: [] }); + }); + } + } + test('webpack parenthesized descriptors', () => { assert.deepEqual(parse(`Object.defineProperty(exports, 'BaseWatchPlugin', ({ enumerable: true, get: function () { return _BaseWatchPlugin.default; }