diff --git a/packages/macros/src/babel/macros-babel-plugin.ts b/packages/macros/src/babel/macros-babel-plugin.ts index f4494f740..59c542815 100644 --- a/packages/macros/src/babel/macros-babel-plugin.ts +++ b/packages/macros/src/babel/macros-babel-plugin.ts @@ -205,9 +205,32 @@ export default function main(context: typeof Babel): unknown { // our getConfig and getOwnConfig macros are supposed to be able to absorb // optional chaining. To make that work we need to see the optional chaining // before preset-env compiles them away. + + function fromGetConfig(path: NodePath | null) { + while (path) { + const obj = path.get('object'); + if (obj.isCallExpression()) { + const callee = obj.get('callee'); + if ( + callee.referencesImport('@embroider/macros', 'getOwnConfig') || + callee.referencesImport('@embroider/macros', 'getGlobalConfig') || + callee.referencesImport('@embroider/macros', 'getConfig') + ) { + return true; + } + } + if (obj.isMemberExpression() || obj.isOptionalMemberExpression()) { + path = obj; + } else { + return false; + } + } + return false; + } + (visitor as any).OptionalMemberExpression = { enter(path: NodePath, state: State) { - if (state.opts.mode === 'compile-time') { + if (state.opts.mode === 'compile-time' && fromGetConfig(path as any)) { let result = new Evaluator({ state }).evaluate(path); if (result.confident) { path.replaceWith(buildLiterals(result.value, context)); diff --git a/packages/macros/tests/babel/get-config.test.ts b/packages/macros/tests/babel/get-config.test.ts index 1995f0354..cc38efe32 100644 --- a/packages/macros/tests/babel/get-config.test.ts +++ b/packages/macros/tests/babel/get-config.test.ts @@ -146,6 +146,15 @@ describe(`getConfig`, function () { expect(code).toMatch(/doSomething\(undefined\)/); }); + buildTimeTest(`does not collapse nullish coalescing for non embroider macros, nullish case`, () => { + let code = transform(` + const aKnownValue = {}; + aKnownValue.foo = true; + result = aKnownValue?.foo; + `); + expect(code).toMatch(`result = aKnownValue`); + }); + runTimeTest(`runtime getConfig is still present in runtime mode when using optional chaining`, () => { let code = transform(` import { getConfig } from '@embroider/macros';