UNPKG

babel-plugin-transform-cx-jsx

Version:

Transpile JSX into Cx config objects

554 lines (404 loc) 15 kB
"use strict"; let babel = require("@babel/core"); let plugin = require("./index"); let assert = require('assert'); function unwrap(code) { return code.substring(0, code.length - 1); //return code.substring(15, code.length-1); } describe('JSCX', function () { it("doesn't touch non-wrapped code", function () { let code = `<div id="123" />`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal(unwrap(output), '<div id="123" />'); }); it('converts <cx></cx> to null', function () { let code = `<cx></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal(unwrap(output), 'null'); }); it('trims whitespace within <cx>', function () { let Container = {}; let code = `<cx> <Container /> </cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Container }); }); it('trims whitespace if the trimWhitespace flag is set', function () { let Container = {}; let code = `<cx> <Container> <Container /> </Container> </cx>`; let output = babel.transform(code, { plugins: [[plugin, { trimWhitespace: true }], '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Container, children: [{ $type: Container }] }); }); it('preserves whitespace if ws flag is set', function () { let Container = {}; let code = `<cx> <Container> <Container ws> Text </Container> </Container> </cx>`; let output = babel.transform(code, { plugins: [[plugin, { trimWhitespace: true }], '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Container, children: [{ $type: Container, children: ['\n Text\n '], jsxAttributes: ["ws"], ws: true }] }) }); it('converts jsx like to config', function () { let Component = {}; let code = `<cx><Component></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component}); }); it('converts jsx attributes to config properties', function () { let Component = {}; let code = `<cx><Component id="123"></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component, id: "123", jsxAttributes: ['id']}); }); it('converts jsx literal attributes to config properties', function () { let code = `<cx><Component id={123}></Component></cx>`; let Component = {}; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component, id: 123, jsxAttributes: ['id']}); }); it('converts jsx object attributes to config properties', function () { let Component = {}; let code = `<cx><Component value={{ x: 1 }}></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component, value: {x: 1}, jsxAttributes: ['value']}); }); it('converts jsx function attributes to config properties', function () { let Component = {}; let code = `<cx><Component onClick={e=>{}}></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(typeof eval(output).onClick, "function"); }); it('converts jsx children into children array', function () { let Component = {}, Child = {}, GrandChild = {}; let code = `<cx><Component><Child><GrandChild></GrandChild></Child></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, children: [{$type: Child, children: [{$type: GrandChild}]}] }); }); it('allows namespaces', function () { let ui = {Component: {}}; let code = `<cx><ui.Component/></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: ui.Component }); }); it('converts jsx text child into text widget', function () { let Component = {}; let code = `<cx><Component>Text</Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, children: ['Text'] }); }); it('converts namespaced attributes into data binding objects', function () { let Component = {}; let code = `<cx><Component value:bind="name" /></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, value: {bind: "name"}, jsxAttributes: ['value'] }); }); it('converts dash attributes into data binding objects', function () { let Component = {}; let code = `<cx><Component value-bind="name" text-tpl="123" visible-expr="false" data-id="5" /></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, value: {bind: "name"}, text: {tpl: '123'}, visible: {expr: 'false'}, "data-id": "5", jsxAttributes: ['value', 'text', 'visible', 'data-id'] }); }); it('multiple root elements are converted to a config array', function () { let Component = {}, Component2 = {}; let code = `<cx><Component /><Component2></Component2></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), [{$type: Component}, {$type: Component2}]); }); it('allows expressions as children', function () { let Component = {}; let code = `<cx><Component>{true}</Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component, children: [true]}); }); it('allows props', function () { let Component = {}; let code = `<cx><Component disabled /></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component, disabled: true, jsxAttributes: ['disabled']}); }); it('allows spread', function () { let Component = {}; let test = {a: 1, b: 2}; let code = `<cx><Component {...test} /></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component, jsxSpread: [test]}); }); it('allows namespaced components', function () { let Component = {Nested: {}}; let code = `<cx><Component.Nested /></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: Component.Nested}); }); it('converts lowercase tags into HtmlElement with tag prop', function () { let HtmlElement = {}; let code = `<cx><div></div></cx>`; let output = babel.transform(code, { plugins: [[plugin, {autoImportHtmlElement: false}], '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), {$type: HtmlElement, tag: 'div'}); }); it('converts jsx elements in attributes', function () { let Component = {}; let Layout = {}; let code = `<cx><Component layout={<Layout type="1" />}></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, jsxAttributes: ['layout'], layout: { $type: Layout, jsxAttributes: ['type'], type: "1" } }); }); it('converts jsx element arrays in attributes', function () { let Component = {}; let Layout = {}; let code = `<cx><Component layout={<cx><Layout type="1" /><Layout type="2" /></cx>}></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, jsxAttributes: ['layout'], layout: [{ $type: Layout, jsxAttributes: ['type'], type: "1" }, { $type: Layout, jsxAttributes: ['type'], type: "2" }] }); }); it('converts jsx elements in structured attributes', function () { let Component = {}; let Layout = {}; let code = `<cx><Component layout={{ x: <Layout type="1" />}}></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, jsxAttributes: ['layout'], layout: { x: { $type: Layout, jsxAttributes: ['type'], type: "1" } } }); }); it('converts jsx elements within arrays', function () { let Component = {}; let Column = {}; let code = `<cx><Component columns={[ <Column type="1" /> ]}></Component></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.deepEqual(eval(output), { $type: Component, jsxAttributes: ['columns'], columns: [{ $type: Column, jsxAttributes: ['type'], type: "1" }] }); }); it("doesn't touch empty Cx element", function () { let code = `<Cx id="123" />`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal(unwrap(output), '<Cx id="123" />'); }); it("converts only inner content of Cx elements", function () { let code = `<Cx><Container class="test" /></Cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal(unwrap(output).replace(/\n/g, '').replace(/\s\s/g, ' '), '<Cx items={[{ $type: Container, class: "test", jsxAttributes: ["class"]}]}></Cx>'); }); it("registers functional Cx components", function () { let code = `let x = props => <cx><Container /></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal( unwrap(output).replace(/\n/g, '').replace(/\s\s/g, ' '), 'import { createFunctionalComponent } from "cx/ui";let x = createFunctionalComponent(props => ({ $type: Container}))'); }); it("multiple functional components add only one import", function () { let code = `let X = props => <cx><Container /></cx>;let Y = props => <cx><Container /></cx>;`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal( unwrap(output).replace(/\n/g, '').replace(/\s\s/g, ' '), [ 'import { createFunctionalComponent } from "cx/ui";', 'let X = createFunctionalComponent(props => ({ $type: Container}));', 'let Y = createFunctionalComponent(props => ({ $type: Container}))' ].join('') ); }); it("import for HtmlElement is automatically added", function () { let code = `let x = <cx><div></div></cx>`; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal( unwrap(output).replace(/\n/g, '').replace(/\s\s/g, ' '), [ 'import { HtmlElement } from "cx/widgets";', 'let x = { $type: HtmlElement, tag: "div"}', ].join('') ); }); it("does not auto import HtmlElement if it's already there", function () { let code = ` import { HtmlElement } from "cx/widgets"; let x = <cx><div></div></cx> `; let output = babel.transform(code, { plugins: [plugin, '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert.equal( unwrap(output).replace(/\n/g, '').replace(/\s\s/g, ' '), [ 'import { HtmlElement } from "cx/widgets";', 'let x = { $type: HtmlElement, tag: "div"}', ].join('') ); }); it("expands fat arrows in string based expressions if expandFatArrows is set", function () { let code = `<cx> <Repeater records-expr="{data}.filter(a=>a.enabled)" /> </cx>`; let output = babel.transform(code, { plugins: [[plugin, { expandFatArrows: true }], '@babel/plugin-syntax-jsx'] //presets: ['es2015'] }).code; assert(output.indexOf("function (a){return a.enabled}") > 0); }); });