From d7eb94426009969331b9ea9b486374fb4034ac8c Mon Sep 17 00:00:00 2001 From: Oskar Eichler Date: Mon, 31 Aug 2026 02:43:15 +0300 Subject: [PATCH] Complete deep import warning coverage --- .../plugin-warn-on-deep-imports-test.js | 34 +++++++++++++++++++ .../src/plugin-warn-on-deep-imports.js | 23 ++++++++----- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/packages/react-native-babel-preset/src/__tests__/plugin-warn-on-deep-imports-test.js b/packages/react-native-babel-preset/src/__tests__/plugin-warn-on-deep-imports-test.js index 66f247d7112a..85ee7c69c5a7 100644 --- a/packages/react-native-babel-preset/src/__tests__/plugin-warn-on-deep-imports-test.js +++ b/packages/react-native-babel-preset/src/__tests__/plugin-warn-on-deep-imports-test.js @@ -46,6 +46,30 @@ test('deep cjs import', () => { `); }); +test('does not warn for a shadowed require function', () => { + const code = ` + function load(require) { + return require('react-native/Libraries/Components/View/View'); + } + `; + + expect(transform(code, [rnDeepImportsWarningPlugin])).not.toContain( + 'console.warn', + ); +}); + +test('warns for a dynamic import when require is shadowed', () => { + const code = ` + function load(require) { + return import('react-native/Libraries/Utilities/Platform'); + } + `; + + expect(transform(code, [rnDeepImportsWarningPlugin])).toContain( + "Deep imports from the 'react-native' package are deprecated ('react-native/Libraries/Utilities/Platform').", + ); +}); + test('multiple deep imports', () => { const code = ` import View from 'react-native/Libraries/Components/View/View'; @@ -73,6 +97,16 @@ test('deep reexport', () => { `); }); +test('deep export all', () => { + const code = ` + export * from 'react-native/Libraries/Utilities/Platform'; + `; + + expect(transform(code, [rnDeepImportsWarningPlugin])).toContain( + "console.warn(\"Deep imports from the 'react-native' package are deprecated ('react-native/Libraries/Utilities/Platform'). Source: path/to/project/foo.js 2:4\");", + ); +}); + test('import from other package', () => { const code = ` import {foo} from 'react-native-foo'; diff --git a/packages/react-native-babel-preset/src/plugin-warn-on-deep-imports.js b/packages/react-native-babel-preset/src/plugin-warn-on-deep-imports.js index 5e98ed59ad74..68f1b5b27acb 100644 --- a/packages/react-native-babel-preset/src/plugin-warn-on-deep-imports.js +++ b/packages/react-native-babel-preset/src/plugin-warn-on-deep-imports.js @@ -45,6 +45,15 @@ function withLocation(node, loc) { return node; } +function recordDeepExport(path, state) { + const source = path.node.source; + + if (source && isDeepReactNativeImport(source.value)) { + const loc = path.node.loc; + state.export.push({source: source.value, loc}); + } +} + module.exports = ({types: t}) => ({ name: 'warn-on-deep-imports', visitor: { @@ -61,7 +70,9 @@ module.exports = ({types: t}) => ({ const args = path.get('arguments'); if ( - callee.isIdentifier({name: 'require'}) && + ((callee.isIdentifier({name: 'require'}) && + path.scope.getBinding('require') == null) || + callee.node.type === 'Import') && args.length === 1 && args[0].isStringLiteral() ) { @@ -73,14 +84,8 @@ module.exports = ({types: t}) => ({ } } }, - ExportNamedDeclaration(path, state) { - const source = path.node.source; - - if (source && isDeepReactNativeImport(source.value)) { - const loc = path.node.loc; - state.export.push({source: source.value, loc}); - } - }, + ExportNamedDeclaration: recordDeepExport, + ExportAllDeclaration: recordDeepExport, Program: { enter(path, state) { state.require = [];