From 927995cd6f8dd8fa6f4602a10d6083e32208b2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= Date: Fri, 22 Feb 2019 20:44:38 +0100 Subject: [PATCH] Make Babel import JSX pragma plugin aware of `wp.element.createElement` (#13809) * Test: Add test which verifies wheter JSX pragma detects WP global * Update packages/babel-plugin-import-jsx-pragma/test/index.js Co-Authored-By: gziolo * Skip import when the scope variable is already defined * Add failing tests for inner scope variable defined verification * Add import statement when there is any undefined scope variable * Docs: Add details about changes introduced to Babel plugin --- .../CHANGELOG.md | 6 +++ .../babel-plugin-import-jsx-pragma/README.md | 2 +- .../src/index.js | 9 ++++- .../test/index.js | 40 ++++++++++++++++++- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md index 33b89b5ae57b01..ffa68f4404f0d4 100644 --- a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md +++ b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.0 (Unreleased) + +### Breaking Change + +- Plugin skips now adding import JSX pragma when the scope variable is defined for all JSX elements ([#13809](https://github.com/WordPress/gutenberg/pull/13809)). + ## 1.1.0 (2018-09-05) ### New Feature diff --git a/packages/babel-plugin-import-jsx-pragma/README.md b/packages/babel-plugin-import-jsx-pragma/README.md index fc32f27a90204e..85d7e69655455a 100644 --- a/packages/babel-plugin-import-jsx-pragma/README.md +++ b/packages/babel-plugin-import-jsx-pragma/README.md @@ -4,7 +4,7 @@ Babel transform plugin for automatically injecting an import to be used as the p [JSX](https://reactjs.org/docs/jsx-in-depth.html) is merely a syntactic sugar for a function call, typically to `React.createElement` when used with [React](https://reactjs.org/). As such, it requires that the function referenced by this transform be within the scope of the file where the JSX occurs. In a typical React project, this means React must be imported in any file where JSX exists. -**Babel Plugin Import JSX Pragma** automates this process by introducing the necessary import automatically wherever JSX exists, allowing you to use JSX in your code without thinking to ensure the transformed function is within scope. +**Babel Plugin Import JSX Pragma** automates this process by introducing the necessary import automatically wherever JSX exists, allowing you to use JSX in your code without thinking to ensure the transformed function is within scope. It respects existing import statements, as well as scope variable declarations. ## Installation diff --git a/packages/babel-plugin-import-jsx-pragma/src/index.js b/packages/babel-plugin-import-jsx-pragma/src/index.js index 89963e67d27e80..68e94e1ffc37d6 100644 --- a/packages/babel-plugin-import-jsx-pragma/src/index.js +++ b/packages/babel-plugin-import-jsx-pragma/src/index.js @@ -44,6 +44,13 @@ export default function( babel ) { visitor: { JSXElement( path, state ) { state.hasJSX = true; + if ( state.hasUndeclaredScopeVariable ) { + return; + } + + const { scopeVariable } = getOptions( state ); + + state.hasUndeclaredScopeVariable = ! path.scope.hasBinding( scopeVariable ); }, ImportDeclaration( path, state ) { if ( state.hasImportedScopeVariable ) { @@ -71,7 +78,7 @@ export default function( babel ) { }, Program: { exit( path, state ) { - if ( ! state.hasJSX || state.hasImportedScopeVariable ) { + if ( ! state.hasJSX || state.hasImportedScopeVariable || ! state.hasUndeclaredScopeVariable ) { return; } diff --git a/packages/babel-plugin-import-jsx-pragma/test/index.js b/packages/babel-plugin-import-jsx-pragma/test/index.js index 800b75e9727d65..d70cf2313c540a 100644 --- a/packages/babel-plugin-import-jsx-pragma/test/index.js +++ b/packages/babel-plugin-import-jsx-pragma/test/index.js @@ -35,11 +35,18 @@ describe( 'babel-plugin-import-jsx-pragma', () => { expect( string ).toBe( original ); } ); + it( 'does nothing if the scope variable is already defined', () => { + const original = 'const React = require("react");\n\nlet foo = ;'; + const string = getTransformedCode( original ); + + expect( string ).toBe( original ); + } ); + it( 'adds import for scope variable', () => { const original = 'let foo = ;'; const string = getTransformedCode( original ); - expect( string ).toBe( 'import React from "react";\nlet foo = ;' ); + expect( string ).toBe( 'import React from "react";\n' + original ); } ); it( 'allows options customization', () => { @@ -50,6 +57,35 @@ describe( 'babel-plugin-import-jsx-pragma', () => { isDefault: false, } ); - expect( string ).toBe( 'import { createElement } from "@wordpress/element";\nlet foo = ;' ); + expect( string ).toBe( 'import { createElement } from "@wordpress/element";\n' + original ); + } ); + + it( 'adds import for scope variable even when defined inside the local scope', () => { + const original = 'let foo = ;\n\nfunction local() {\n const createElement = wp.element.createElement;\n}'; + const string = getTransformedCode( original, { + scopeVariable: 'createElement', + source: '@wordpress/element', + isDefault: false, + } ); + + expect( string ).toBe( 'import { createElement } from "@wordpress/element";\n' + original ); + } ); + + it( 'does nothing if the outer scope variable is already defined when using custom options', () => { + const original = 'const {\n createElement\n} = wp.element;\nlet foo = ;'; + const string = getTransformedCode( original, { + scopeVariable: 'createElement', + } ); + + expect( string ).toBe( original ); + } ); + + it( 'does nothing if the inner scope variable is already defined when using custom options', () => { + const original = '(function () {\n const {\n createElement\n } = wp.element;\n let foo = ;\n})();'; + const string = getTransformedCode( original, { + scopeVariable: 'createElement', + } ); + + expect( string ).toBe( original ); } ); } );