diff --git a/packages/metro-transform-plugins/src/__tests__/inline-plugin-test.js b/packages/metro-transform-plugins/src/__tests__/inline-plugin-test.js index fe2fb8d154..77708a5356 100644 --- a/packages/metro-transform-plugins/src/__tests__/inline-plugin-test.js +++ b/packages/metro-transform-plugins/src/__tests__/inline-plugin-test.js @@ -410,6 +410,34 @@ describe('inline constants', () => { }); }); + test('does not discard impure Platform.select initializers', () => { + const code = ` + var value = Platform.select({ + ios: selected(), + android: discarded(), + }); + `; + + compare([inlinePlugin], code, code, { + inlinePlatform: true, + platform: 'ios', + }); + }); + + test('does not mutate ObjectMethod when bailing out on impure initializers', () => { + const code = ` + var value = Platform.select({ + ios() { return 1; }, + android: sideEffect(), + }); + `; + + compare([inlinePlugin], code, code, { + inlinePlatform: true, + platform: 'ios', + }); + }); + test('inlines Platform.select in the code when using an ObjectMethod', () => { const code = ` function a() { diff --git a/packages/metro-transform-plugins/src/inline-plugin.js b/packages/metro-transform-plugins/src/inline-plugin.js index 4fc5dfb49d..7faf68d48b 100644 --- a/packages/metro-transform-plugins/src/inline-plugin.js +++ b/packages/metro-transform-plugins/src/inline-plugin.js @@ -138,7 +138,9 @@ export default function inlinePlugin( if (isObjectProperty(p)) { return p.value; } else if (isObjectMethod(p)) { - return t.toExpression(p); + // Clone: toExpression mutates in place, e.g. `ios() {}` would be + // left mutated if the purity check below bails out. + return t.toExpression(t.cloneNode(p)); } } } @@ -200,8 +202,17 @@ export default function inlinePlugin( findProperty(arg, 'native', () => findProperty(arg, 'default', () => t.identifier('undefined')), ); - - path.replaceWith(findProperty(arg, opts.platform, fallback)); + const selected = findProperty(arg, opts.platform, fallback); + + if ( + arg.properties.every( + property => + (isObjectProperty(property) && property.value === selected) || + scope.isPure(property), + ) + ) { + path.replaceWith(selected); + } } } },