diff --git a/__mocks__/Examples.tsx b/__mocks__/Examples.tsx index 23f05f2..1718ac7 100644 --- a/__mocks__/Examples.tsx +++ b/__mocks__/Examples.tsx @@ -20,6 +20,25 @@ export const MockNoInlineWithComponent = () => { ) } +export const MockNoInlineWithBackticks = () => { + return ( + + {() => { + const DemoComponent = () => { + const more = '456' + return `123${more}` + `789` + } + + return ( +
+ +
+ ) + }} +
+ ) +} + export const MockNoInlineWithText = () => { return ( diff --git a/__tests__/babelPluginReactLive.test.ts b/__tests__/babelPluginReactLive.test.ts index 15fc432..a76380f 100644 --- a/__tests__/babelPluginReactLive.test.ts +++ b/__tests__/babelPluginReactLive.test.ts @@ -16,108 +16,124 @@ const pluginOptions = { prettierPath, } -it('babelPluginReactLive', async () => { - const babelFileResult = await transformFileAsync(targetFile, { - code: true, - presets: [ - [ - '@babel/preset-env', - { - modules: false, - targets: { firefox: '100' }, - }, +describe('transformFileAsync', () => { + it('should convert Examples.tsx with all exported examples', async () => { + const babelFileResult = await transformFileAsync(targetFile, { + code: true, + presets: [ + [ + '@babel/preset-env', + { + modules: false, + targets: { firefox: '100' }, + }, + ], ], - ], - plugins: [[babelPluginReactLive, pluginOptions]], - }) + plugins: [[babelPluginReactLive, pluginOptions]], + }) - const code = removeConsoleNinja(String(babelFileResult?.code)) + const code = removeConsoleNinja(String(babelFileResult?.code)) - const formattedCode = prettier.format(code, { - filepath: 'file.tsx', - semi: false, - }) + const formattedCode = prettier.format(code, { + filepath: 'file.tsx', + semi: false, + }) - expect(formattedCode).toMatchInlineSnapshot(` - "const ComponentBox = ({ children }) => children - export const MockNoInlineWithComponent = () => { - return ( - {\`const DemoComponent = () => { - return <>content - } - render( -
- -
- ) - \`}
+ expect(formattedCode).toMatchInlineSnapshot(` + "const ComponentBox = ({ children }) => children + export const MockNoInlineWithComponent = () => { + return ( + {\`const DemoComponent = () => { + return <>content + } + render( +
+ +
) - } - export const MockNoInlineWithText = () => { - return ( - {\`render(<>content) - \`} + \`}
+ ) + } + export const MockNoInlineWithBackticks = () => { + return ( + {\`const DemoComponent = () => { + const more = '456' + return \\\`123\\\${more}\\\` + \\\`789\\\` + } + render( +
+ +
) - } - export const MockOneChilds = () => { - return ( - {\`
content
- \`}
- ) - } - export const MockManyChilds = () => { - return ( - {\` -
content 1
-
content 2
-
content 3
+ \`}
+ ) + } + export const MockNoInlineWithText = () => { + return ( + {\`render(<>content) + \`} + ) + } + export const MockOneChilds = () => { + return ( + {\`
content
+ \`}
+ ) + } + export const MockManyChilds = () => { + return ( + {\` +
content 1
+
content 2
+
content 3
- \`}
- ) - } - export const MockFragment = () => { - return ( - {\`<> - content 1 - content 2 - content 3 - - \`} - ) - } - export const MockText = () => { - return ( - {\` - text - {'text'} - content - text - {'text'} + \`} + ) + } + export const MockFragment = () => { + return ( + {\`<> + content 1 + content 2 + content 3 + + \`} + ) + } + export const MockText = () => { + return ( + {\` + text + {'text'} + content + text + {'text'} - \`} - ) - } - export const MockEvents = () => { - return ( - {\` { - // comment - console.log(e) - }} - onOpen={(e) => 'console.log(e)'} - onFocus={(e) => { - const cleaned = 'console.log(e)' - }} - /> - \`} - ) - } - " - `) + \`}
+ ) + } + export const MockEvents = () => { + return ( + {\` { + // comment + console.log(e) + }} + onOpen={(e) => 'console.log(e)'} + onFocus={(e) => { + const cleaned = 'console.log(e)' + }} + /> + \`} + ) + } + " + `) - expect(formattedCode.match(/noInline/g)).toHaveLength(2) - expect(formattedCode.match(/\{`/g)).toHaveLength(7) - expect(formattedCode.match(/`\}/g)).toHaveLength(7) + expect(formattedCode.match(/noInline/g)).toHaveLength(3) + expect(formattedCode.match(/\{`/g)).toHaveLength(8) + expect(formattedCode.match(/`\}/g)).toHaveLength(8) + }) }) function removeConsoleNinja(code) { diff --git a/babelPluginReactLive.js b/babelPluginReactLive.js index 4ab0069..d0dd4c1 100644 --- a/babelPluginReactLive.js +++ b/babelPluginReactLive.js @@ -24,16 +24,21 @@ function babelPluginReactLive(babel, options) { }) // Prettier adds a leading ; - // And we also escape ` - code = code.replace(/^;/, '').replace(/`/g, '\\`') + code = code.replace(/^;/, '') + + // Also escape backticks (`) + code = code.replace(/`/g, '\\`') // Remove fragments we added in the first place if (children.length > 1) { code = code.replace(/^<>|<\/>$|^\s{2}/gm, '') } + const raw = code.replace(/\$\{/g, '\\${') + const templateElement = t.templateElement({ raw, cooked: code }, true) + return t.jsxExpressionContainer( - t.templateLiteral([t.templateElement({ raw: code })], []) + t.templateLiteral([templateElement], []) ) }