From 6ddd42e7b67be076c64b7ab7015b1262f5853b45 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 33b89b5ae57b0..ffa68f4404f0d 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 fc32f27a90204..85d7e69655455 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 89963e67d27e8..68e94e1ffc37d 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 800b75e9727d6..d70cf2313c540 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 ); } ); } );