diff --git a/packages/babel-plugin-jsx/src/index.ts b/packages/babel-plugin-jsx/src/index.ts index d829ca0..b45738d 100644 --- a/packages/babel-plugin-jsx/src/index.ts +++ b/packages/babel-plugin-jsx/src/index.ts @@ -41,9 +41,13 @@ export default () => ({ .filter((specifier) => { if (t.isImportSpecifier(specifier)) { const { imported, local } = specifier; - specifierNames.add(imported.name); - return local.name !== imported.name; - } if (t.isImportNamespaceSpecifier(specifier)) { + if (local.name === imported.name) { + specifierNames.add(imported.name); + return false; + } + return true; + } + if (t.isImportNamespaceSpecifier(specifier)) { // should keep when `import * as Vue from 'vue'` shouldKeep = true; } diff --git a/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap b/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000..cc088ac --- /dev/null +++ b/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,159 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MereProps Order: MereProps Order 1`] = ` +"import { createTextVNode, mergeProps, createVNode } from \\"vue\\"; +createVNode(\\"button\\", mergeProps({ + \\"loading\\": true +}, x, { + \\"type\\": \\"submit\\" +}), [createTextVNode(\\"btn\\")], 16, [\\"loading\\"]);" +`; + +exports[`Merge class/ style attributes into array: Merge class/ style attributes into array 1`] = ` +"import { createVNode } from \\"vue\\"; +createVNode(\\"div\\", { + \\"class\\": [\\"a\\", b], + \\"style\\": [\\"color: red\\", s] +}, null, 6);" +`; + +exports[`Without JSX should work: Without JSX should work 1`] = ` +"import { createVNode } from 'vue'; +createVNode('div', null, ['Without JSX should work']);" +`; + +exports[`Without props: Without props 1`] = ` +"import { createTextVNode, createVNode } from \\"vue\\"; +createVNode(\\"a\\", null, [createTextVNode(\\"a\\")]);" +`; + +exports[`custom directive: custom directive 1`] = ` +"import { resolveComponent, resolveDirective, createVNode, withDirectives } from \\"vue\\"; +withDirectives(createVNode(resolveComponent(\\"A\\"), null, null, 512), [[resolveDirective(\\"cus\\"), x]]);" +`; + +exports[`dynamic type in input: dynamic type in input 1`] = ` +"import { vModelDynamic, createVNode, withDirectives } from \\"vue\\"; +withDirectives(createVNode(\\"input\\", { + \\"type\\": type, + \\"onUpdate:modelValue\\": $event => test = $event +}, null, 8, [\\"type\\", \\"onUpdate:modelValue\\"]), [[vModelDynamic, test]]);" +`; + +exports[`input[type="checkbox"]: input[type="checkbox"] 1`] = ` +"import { vModelCheckbox, createVNode, withDirectives } from \\"vue\\"; +withDirectives(createVNode(\\"input\\", { + \\"type\\": \\"checkbox\\", + \\"onUpdate:modelValue\\": $event => test = $event +}, null, 8, [\\"onUpdate:modelValue\\"]), [[vModelCheckbox, test]]);" +`; + +exports[`input[type="radio"]: input[type="radio"] 1`] = ` +"import { Fragment, vModelRadio, createVNode, withDirectives } from \\"vue\\"; +createVNode(Fragment, null, [withDirectives(createVNode(\\"input\\", { + \\"type\\": \\"radio\\", + \\"value\\": \\"1\\", + \\"onUpdate:modelValue\\": $event => test = $event, + \\"name\\": \\"test\\" +}, null, 8, [\\"onUpdate:modelValue\\"]), [[vModelRadio, test]]), withDirectives(createVNode(\\"input\\", { + \\"type\\": \\"radio\\", + \\"value\\": \\"2\\", + \\"onUpdate:modelValue\\": $event => test = $event, + \\"name\\": \\"test\\" +}, null, 8, [\\"onUpdate:modelValue\\"]), [[vModelRadio, test]])]);" +`; + +exports[`input[type="text"] .lazy modifier: input[type="text"] .lazy modifier 1`] = ` +"import { vModelText, createVNode, withDirectives } from \\"vue\\"; +withDirectives(createVNode(\\"input\\", { + \\"onUpdate:modelValue\\": $event => test = $event +}, null, 8, [\\"onUpdate:modelValue\\"]), [[vModelText, test, void 0, { + lazy: true +}]]);" +`; + +exports[`input[type="text"]: input[type="text"] 1`] = ` +"import { vModelText, createVNode, withDirectives } from \\"vue\\"; +withDirectives(createVNode(\\"input\\", { + \\"onUpdate:modelValue\\": $event => test = $event +}, null, 8, [\\"onUpdate:modelValue\\"]), [[vModelText, test]]);" +`; + +exports[`reassign variable as component: reassign variable as component 1`] = ` +"import { defineComponent, createVNode } from \\"vue\\"; +let a = 1; +const A = defineComponent({ + setup(_, { + slots + }) { + return () => createVNode(\\"span\\", null, [slots.default()]); + } + +}); +const _a = 1; + +const __a = function () { + return a; +}(); + +a = createVNode(A, null, { + default: () => [__a], + _: 2 +});" +`; + +exports[`select: select 1`] = ` +"import { createTextVNode, createVNode, vModelSelect, withDirectives } from \\"vue\\"; +withDirectives(createVNode(\\"select\\", { + \\"onUpdate:modelValue\\": $event => test = $event +}, [createVNode(\\"option\\", { + \\"value\\": \\"1\\" +}, [createTextVNode(\\"a\\")]), createVNode(\\"option\\", { + \\"value\\": 2 +}, [createTextVNode(\\"b\\")]), createVNode(\\"option\\", { + \\"value\\": 3 +}, [createTextVNode(\\"c\\")])], 8, [\\"onUpdate:modelValue\\"]), [[vModelSelect, test]]);" +`; + +exports[`should keep \`import * as Vue from "vue"\`: should keep \`import * as Vue from "vue"\` 1`] = ` +"import { createTextVNode, createVNode } from \\"vue\\"; +import * as Vue from 'vue'; +createVNode(\\"div\\", null, [createTextVNode(\\"Vue\\")]);" +`; + +exports[`single no need for a mergeProps call: single no need for a mergeProps call 1`] = ` +"import { createTextVNode, createVNode } from \\"vue\\"; +createVNode(\\"div\\", x, [createTextVNode(\\"single\\")], 16);" +`; + +exports[`specifiers should be merged into a single importDeclaration: specifiers should be merged into a single importDeclaration 1`] = ` +"import { createVNode, vShow } from \\"vue\\"; +import { Fragment as _Fragment } from \\"vue\\"; +createVNode(_Fragment, null, null);" +`; + +exports[`textarea: textarea 1`] = ` +"import { vModelText, createVNode, withDirectives } from \\"vue\\"; +withDirectives(createVNode(\\"textarea\\", { + \\"onUpdate:modelValue\\": $event => test = $event +}, null, 8, [\\"onUpdate:modelValue\\"]), [[vModelText, test]]);" +`; + +exports[`v-show: v-show 1`] = ` +"import { createTextVNode, vShow, createVNode, withDirectives } from \\"vue\\"; +withDirectives(createVNode(\\"div\\", null, [createTextVNode(\\"vShow\\")], 512), [[vShow, x]]);" +`; + +exports[`vHtml: vHtml 1`] = ` +"import { createVNode } from \\"vue\\"; +createVNode(\\"h1\\", { + \\"innerHTML\\": \\"
foo
\\" +}, null, 8, [\\"innerHTML\\"]);" +`; + +exports[`vText: vText 1`] = ` +"import { createVNode } from \\"vue\\"; +createVNode(\\"div\\", { + \\"textContent\\": text +}, null, 8, [\\"textContent\\"]);" +`; diff --git a/packages/babel-plugin-jsx/test/coverage.test.ts b/packages/babel-plugin-jsx/test/coverage.test.ts deleted file mode 100644 index 7abfd0c..0000000 --- a/packages/babel-plugin-jsx/test/coverage.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { transformSync } from '@babel/core'; -import preset from '../babel.config.js'; - -test('coverage', () => { - ['index.test.tsx', 'v-model.test.tsx'] - .forEach((filename) => { - const mainTest = fs.readFileSync(path.resolve(__dirname, `./${filename}`)).toString(); - transformSync(mainTest, { - babelrc: false, - presets: [preset], - filename, - }); - }); -}); diff --git a/packages/babel-plugin-jsx/test/snapshot.test.ts b/packages/babel-plugin-jsx/test/snapshot.test.ts new file mode 100644 index 0000000..a748ed9 --- /dev/null +++ b/packages/babel-plugin-jsx/test/snapshot.test.ts @@ -0,0 +1,144 @@ +import { transform } from '@babel/core'; +import JSX from '../src'; + +const transpile = (source: string) => new Promise((resolve, reject) => transform( + source, + { + filename: '', + presets: null, + plugins: [[JSX, { optimize: true }]], + configFile: false, + }, (error, result) => { + if (error) { + return reject(error); + } + resolve(result?.code); + }, +)); + +const tests = [ + { + name: 'input[type="checkbox"]', + from: '', + }, + { + name: 'input[type="radio"]', + from: ` + <> + + + + `, + }, + { + name: 'select', + from: ` + + `, + }, + { + name: 'textarea', + from: '