Skip to content

[BUG]: ExportCollapse undefined call expression #148

@wridgeu

Description

@wridgeu

Hi,

I stumbled over the following issue which, while easy to resolve in many ways on the app dev side, I thought I might report - just in case.

It is triggered when all of the following are true:

  • The module has a default export and at least one named export.
  • The default export resolves to a value built from Object.assign(Object.create(null), { ... }).
  • Export collapsing is active (default behavior unless noExportCollapse is enabled).

The stack trace pointed to

  • node_modules/babel-plugin-transform-modules-ui5/dist/modules/helpers/exports.js:77

But could be traced back to actually being a result of:

export function getPropertiesOfObjectAssignOrExtendHelper(
  node,
  blockScopeNode
) {
  // Check all the args and recursively try to get props of identifiers (although they may be imported)
  return flatten(
    node.arguments.map((arg) => {
      if (t.isObjectExpression(arg)) {
        return arg.properties;
      }
      if (t.isIdentifier(arg)) {
        // Recursive, although props will be empty if arg is an imported object
        return getOtherPropertiesOfIdentifier(blockScopeNode, arg.name);
      }
      return [];     // possible fix
    })
  ).filter(Boolean); // possible fix
}

In here, the Object.create(null) of Object.assign(Object.create(null), { ... }) seems to add an undefined entry which later on fails in exports.js during:

if (!defaultExportProperty.key) {
  continue;
}

Quick Repro

const babel = require("@babel/core");
const plugin = require("babel-plugin-transform-modules-ui5");

const cases = [
  [
    "withAsConst",
    "const test=Object.assign(Object.create(null),{a:1}); export const TEST_CONSTANT='test' as const; export default test;",
  ],
  [
    "withoutAsConst",
    "const test=Object.assign(Object.create(null),{a:1}); export const TEST_CONSTANT='test'; export default test;",
  ],
  [
    "typeLiteralAnnotation",
    "const test=Object.assign(Object.create(null),{a:1}); export const TEST_CONSTANT:'test'='test'; export default test;",
  ],
  ["noNamedExport", "const test=Object.assign(Object.create(null),{a:1}); export default test;"],
  [
    "safeObjectAssign",
    "const test=Object.assign({}, {a:1}); export const TEST_CONSTANT='test' as const; export default test;",
  ],
  [
    "twoStepCreateAssign",
    "const test=Object.create(null); Object.assign(test,{a:1}); export const TEST_CONSTANT='test' as const; export default test;",
  ],
];

for (const [name, code] of cases) {
  try {
    babel.transformSync(code, {
      filename: `${name}.ts`,
      plugins: [plugin],
      parserOpts: { plugins: ["typescript"] },
    });
    console.log(`${name}: OK`);
  } catch (error) {
    console.log(`${name}: FAIL -> ${String(error.message).split("\n")[0]}`);
  }
}

One remark on contribution: I ran into several issues on windows in plenty of places in this repo, so I stopped bothering for now. I initially wanted to add a PR as well, as it is a seemingly small change/fix. But I also didn't want to overhaul half the repository just to get things working. I'm open though, maybe it was my mistake/error after all and maybe this isn't even a real issue that needs fixing. So an issue might even be the better way to go in the end. :)

BR

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions