/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ import {parse} from '@babel/parser'; import {transformFromAstSync} from '@babel/core'; import {default as generate} from '@babel/generator'; const flipperRequires = require('../plugin-flipper-requires'); const babelOptions = { ast: true, plugins: [flipperRequires], filename: 'index.js', }; const babelOptionsPlugin = { ...babelOptions, root: 'plugins/randomPlugin/', filename: 'plugins/randomPlugin/index.js', }; test('transform react requires to global object', () => { const src = 'require("react")'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, babelOptionsPlugin)!.ast; const {code} = generate(transformed!); expect(code).toBe('global.React;'); }); test('transform react-dom requires to global object', () => { const src = 'require("react-dom")'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, babelOptionsPlugin)!.ast; const {code} = generate(transformed!); expect(code).toBe('global.ReactDOM;'); }); test('transform react-dom/client requires to global object', () => { const src = 'require("react-dom/client")'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, babelOptionsPlugin)!.ast; const {code} = generate(transformed!); expect(code).toBe('global.ReactDOMClient;'); }); test('transform flipper requires to global object', () => { const src = 'require("flipper")'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, babelOptionsPlugin)!.ast; const {code} = generate(transformed!); expect(code).toBe('global.Flipper;'); }); test('do NOT transform flipper requires outside of plugins folder', () => { const src = 'require("flipper");'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, babelOptions)!.ast; const {code} = generate(transformed!); expect(code).toBe('require("flipper");'); }); test('transform React identifier to global.React', () => { const src = 'React;'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, babelOptionsPlugin)!.ast; const {code} = generate(transformed!); expect(code).toBe('global.React;'); }); test('do NOT transform React identifier to global.React outside of plugins folder', () => { const src = 'React;'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, babelOptions)!.ast; const {code} = generate(transformed!); expect(code).toBe('React;'); }); test('do NOT transform local React namespace import to global.React', () => { const src = `import * as React from 'react';`; const ast = parse(src, {sourceType: 'module'}); const transformed = transformFromAstSync(ast, src, babelOptions)!.ast; const {code} = generate(transformed!); expect(code).toMatchInlineSnapshot(`"import * as React from 'react';"`); }); test('throw error when requiring outside the plugin', () => { const src = 'require("../test.js")'; const ast = parse(src); expect(() => { transformFromAstSync(ast, src, babelOptionsPlugin); }).toThrow(); }); test('allow requiring from parent folder as long as we stay in plugin folder', () => { const src = 'require("../test.js")'; const ast = parse(src); const transformed = transformFromAstSync(ast, src, { ...babelOptions, root: '/path/to/plugin', filename: '/path/to/plugin/subfolder/index.js', })!.ast; const {code} = generate(transformed!); expect(code).toBe('require("../test.js");'); });