Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: should merge generated imports #274

Merged
merged 6 commits into from
Jan 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = {
'@typescript-eslint/explicit-module-boundary-types': [0],
'@typescript-eslint/no-explicit-any': [0],
'@typescript-eslint/no-non-null-assertion': [0],
'max-len': [0],
},
settings: {
'import/resolver': {
Expand Down
31 changes: 29 additions & 2 deletions packages/babel-plugin-jsx/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface VueJSXPluginOptions {

export type ExcludesBoolean = <T>(x: T | false | true) => x is T;

const hasJSX = (parentPath: NodePath) => {
const hasJSX = (parentPath: NodePath<t.Program>) => {
let fileHasJSX = false;
parentPath.traverse({
JSXElement(path) { // skip ts error
Expand All @@ -51,7 +51,7 @@ export default ({ types }: typeof BabelCore) => ({
...tranformVueJSX,
...sugarFragment,
Program: {
enter(path: NodePath, state: State) {
enter(path: NodePath<t.Program>, state: State) {
if (hasJSX(path)) {
const importNames = [
'createVNode',
Expand Down Expand Up @@ -131,6 +131,33 @@ export default ({ types }: typeof BabelCore) => ({
}
}
},
exit(path: NodePath<t.Program>) {
const body = path.get('body') as NodePath[];
const specifiersMap = new Map<string, t.ImportSpecifier>();

body.filter((nodePath) => t.isImportDeclaration(nodePath.node)
&& nodePath.node.source.value === 'vue')
.forEach((nodePath) => {
const { specifiers } = nodePath.node as t.ImportDeclaration;
let shouldRemove = false;
specifiers.forEach((specifier) => {
if (!specifier.loc && t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) {
specifiersMap.set(specifier.imported.name, specifier);
shouldRemove = true;
}
});
if (shouldRemove) {
nodePath.remove();
}
});

const specifiers = [...specifiersMap.keys()].map(
(imported) => specifiersMap.get(imported)!,
);
if (specifiers.length) {
path.unshiftContainer('body', t.importDeclaration(specifiers, t.stringLiteral('vue')));
}
},
},
},
});
80 changes: 22 additions & 58 deletions packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`MereProps Order: MereProps Order 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { mergeProps as _mergeProps } from \\"vue\\";
import { createTextVNode as _createTextVNode } from \\"vue\\";
"import { createVNode as _createVNode, mergeProps as _mergeProps, createTextVNode as _createTextVNode } from \\"vue\\";

_createVNode(\\"button\\", _mergeProps({
\\"loading\\": true
Expand All @@ -27,24 +25,19 @@ createVNode('div', null, ['Without JSX should work']);"
`;

exports[`Without props: Without props 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { createTextVNode as _createTextVNode } from \\"vue\\";
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";

_createVNode(\\"a\\", null, [_createTextVNode(\\"a\\")]);"
`;

exports[`custom directive: custom directive 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { resolveDirective as _resolveDirective } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent } from \\"vue\\";

_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"cus\\"), x]]);"
`;

exports[`disable object slot syntax with defaultSlot: defaultSlot 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";

_createVNode(_resolveComponent(\\"Badge\\"), null, {
default: () => [slots.default()],
Expand All @@ -53,9 +46,7 @@ _createVNode(_resolveComponent(\\"Badge\\"), null, {
`;

exports[`dynamic type in input: dynamic type in input 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { vModelDynamic as _vModelDynamic } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelDynamic as _vModelDynamic } from \\"vue\\";

_withDirectives(_createVNode(\\"input\\", {
\\"type\\": type,
Expand All @@ -64,9 +55,7 @@ _withDirectives(_createVNode(\\"input\\", {
`;

exports[`input[type="checkbox"]: input[type="checkbox"] 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { vModelCheckbox as _vModelCheckbox } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelCheckbox as _vModelCheckbox } from \\"vue\\";

_withDirectives(_createVNode(\\"input\\", {
\\"type\\": \\"checkbox\\",
Expand All @@ -75,10 +64,7 @@ _withDirectives(_createVNode(\\"input\\", {
`;

exports[`input[type="radio"]: input[type="radio"] 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { vModelRadio as _vModelRadio } from \\"vue\\";
import { Fragment as _Fragment } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelRadio as _vModelRadio, Fragment as _Fragment } from \\"vue\\";

_createVNode(_Fragment, null, [_withDirectives(_createVNode(\\"input\\", {
\\"type\\": \\"radio\\",
Expand All @@ -94,9 +80,7 @@ _createVNode(_Fragment, null, [_withDirectives(_createVNode(\\"input\\", {
`;

exports[`input[type="text"] .lazy modifier: input[type="text"] .lazy modifier 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { vModelText as _vModelText } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";

_withDirectives(_createVNode(\\"input\\", {
\\"onUpdate:modelValue\\": $event => test = $event
Expand All @@ -106,18 +90,15 @@ _withDirectives(_createVNode(\\"input\\", {
`;

exports[`input[type="text"]: input[type="text"] 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { vModelText as _vModelText } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";

_withDirectives(_createVNode(\\"input\\", {
\\"onUpdate:modelValue\\": $event => test = $event
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
`;

exports[`override props multiple: multiple 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";

_createVNode(_resolveComponent(\\"A\\"), {
\\"loading\\": true,
Expand All @@ -138,8 +119,7 @@ _createVNode(\\"div\\", a, null);"
`;

exports[`passing object slots via JSX children multiple expressions: multiple expressions 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";

_createVNode(_resolveComponent(\\"A\\"), null, {
default: () => [foo, bar],
Expand All @@ -148,20 +128,17 @@ _createVNode(_resolveComponent(\\"A\\"), null, {
`;

exports[`passing object slots via JSX children single expression, function expression: single expression, function expression 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";

_createVNode(_resolveComponent(\\"A\\"), null, {
default: () => \\"foo\\"
});"
`;

exports[`passing object slots via JSX children single expression, non-literal value: runtime check: single expression, non-literal value: runtime check 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { isVNode as _isVNode } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"let _slot;

let _slot;
import { createVNode as _createVNode, isVNode as _isVNode, resolveComponent as _resolveComponent } from \\"vue\\";

function _isSlot(s) {
return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !_isVNode(s);
Expand All @@ -176,8 +153,7 @@ _createVNode(_resolveComponent(\\"A\\"), null, _isSlot(_slot = foo()) ? _slot :
`;

exports[`reassign variable as component: reassign variable as component 1`] = `
"import { isVNode as _isVNode } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
"import { isVNode as _isVNode, createVNode as _createVNode } from \\"vue\\";
import { defineComponent } from 'vue';

function _isSlot(s) {
Expand Down Expand Up @@ -207,10 +183,7 @@ a = _createVNode(A, null, _isSlot(a) ? a : {
`;

exports[`select: select 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { vModelSelect as _vModelSelect } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { createTextVNode as _createTextVNode } from \\"vue\\";
"import { withDirectives as _withDirectives, vModelSelect as _vModelSelect, createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";

_withDirectives(_createVNode(\\"select\\", {
\\"onUpdate:modelValue\\": $event => test = $event
Expand All @@ -224,16 +197,14 @@ _withDirectives(_createVNode(\\"select\\", {
`;

exports[`should keep \`import * as Vue from "vue"\`: should keep \`import * as Vue from "vue"\` 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { createTextVNode as _createTextVNode } from \\"vue\\";
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } 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 { createVNode as _createVNode } from \\"vue\\";
import { createTextVNode as _createTextVNode } from \\"vue\\";
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";

_createVNode(\\"div\\", x, [_createTextVNode(\\"single\\")], 16);"
`;
Expand All @@ -247,18 +218,15 @@ _createVNode(_Fragment, null, null);"
`;

exports[`textarea: textarea 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { vModelText as _vModelText } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";

_withDirectives(_createVNode(\\"textarea\\", {
\\"onUpdate:modelValue\\": $event => test = $event
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
`;

exports[`use "model" as the prop name: use "model" as the prop name 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";

_createVNode(_resolveComponent(\\"C\\"), {
\\"model\\": foo,
Expand All @@ -267,10 +235,7 @@ _createVNode(_resolveComponent(\\"C\\"), {
`;

exports[`v-show: v-show 1`] = `
"import { withDirectives as _withDirectives } from \\"vue\\";
import { createVNode as _createVNode } from \\"vue\\";
import { vShow as _vShow } from \\"vue\\";
import { createTextVNode as _createTextVNode } from \\"vue\\";
"import { withDirectives as _withDirectives, createVNode as _createVNode, vShow as _vShow, createTextVNode as _createTextVNode } from \\"vue\\";

_withDirectives(_createVNode(\\"div\\", null, [_createTextVNode(\\"vShow\\")], 512), [[_vShow, x]]);"
`;
Expand All @@ -284,8 +249,7 @@ _createVNode(\\"h1\\", {
`;

exports[`vModels: vModels 1`] = `
"import { createVNode as _createVNode } from \\"vue\\";
import { resolveComponent as _resolveComponent } from \\"vue\\";
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";

_createVNode(_resolveComponent(\\"C\\"), {
\\"modelValue\\": foo,
Expand Down