fix: wrong compilation result of withDirectives (#404)

This commit is contained in:
Amour1688 2021-04-30 01:06:23 +08:00
parent cbad0e5c5f
commit 224196d3ec
5 changed files with 66 additions and 58 deletions

View File

@ -242,8 +242,7 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
values.forEach((value, index) => {
const propName = args[index];
// v-model target with variable
// const isIdentifierProp = t.isIdentifier(propName);
const isDynamic = !t.isStringLiteral(propName) && !t.isNullLiteral(propName);
const isDynamic = propName && !t.isStringLiteral(propName) && !t.isNullLiteral(propName);
// must be v-model or v-models and is a component
if (!directive) {

View File

@ -1,7 +1,7 @@
import * as t from '@babel/types';
import { NodePath } from '@babel/traverse';
import { createIdentifier } from './utils';
import { State, ExcludesBoolean } from '.';
import { State } from '.';
export type Tag = t.Identifier | t.MemberExpression | t.StringLiteral | t.CallExpression;
@ -24,7 +24,7 @@ const getType = (path: NodePath<t.JSXOpeningElement>) => {
return typePath ? typePath.get('value').node : null;
};
const parseModifiers = (value: t.ArrayExpression): string[] => (
const parseModifiers = (value: any): string[] => (
t.isArrayExpression(value)
? value.elements
.map((el) => (t.isStringLiteral(el) ? el.value : ''))
@ -64,37 +64,38 @@ const parseDirectives = (params: {
const shouldResolve = !['html', 'text', 'model', 'models'].includes(directiveName)
|| (isVModel && !isComponent);
if (['models', 'model'].includes(directiveName)) {
if (t.isArrayExpression(value)) {
const elementsList = isVModels ? value.elements! : [value];
let modifiers = underscoreModifiers;
elementsList.forEach((element) => {
if (isVModels && !t.isArrayExpression(element)) {
throw new Error('You should pass a Two-dimensional Arrays to v-models');
}
if (t.isArrayExpression(value)) {
const elementsList = isVModels ? value.elements! : [value];
const { elements } = element as t.ArrayExpression;
const [first, second, third] = elements;
let modifiers = underscoreModifiers;
elementsList.forEach((element) => {
if (isVModels && !t.isArrayExpression(element)) {
throw new Error('You should pass a Two-dimensional Arrays to v-models');
}
if (second && !t.isArrayExpression(second) && !t.isSpreadElement(second)) {
args.push(second);
modifiers = parseModifiers(third as t.ArrayExpression);
} else if (t.isArrayExpression(second)) {
args.push(t.nullLiteral());
modifiers = parseModifiers(second);
} else {
// work as v-model={[value]} or v-models={[[value]]}
const { elements } = element as t.ArrayExpression;
const [first, second, third] = elements;
if (second && !t.isArrayExpression(second) && !t.isSpreadElement(second)) {
args.push(second);
modifiers = parseModifiers(third as t.ArrayExpression);
} else if (t.isArrayExpression(second)) {
if (!shouldResolve) {
args.push(t.nullLiteral());
}
modifiersSet.push(new Set(modifiers));
vals.push(first as t.Expression);
});
} else if (isVModel) {
// work as v-model={value}
args.push(t.nullLiteral());
modifiersSet.push(new Set(underscoreModifiers));
}
modifiers = parseModifiers(second);
} else if (!shouldResolve) {
// work as v-model={[value]} or v-models={[[value]]}
args.push(t.nullLiteral());
}
modifiersSet.push(new Set(modifiers));
vals.push(first as t.Expression);
});
} else if (isVModel && !shouldResolve) {
// work as v-model={value}
args.push(t.nullLiteral());
modifiersSet.push(new Set(underscoreModifiers));
} else {
modifiersSet.push(new Set(underscoreModifiers));
}
@ -107,7 +108,9 @@ const parseDirectives = (params: {
directive: shouldResolve ? [
resolveDirective(path, state, tag, directiveName),
vals[0] || value,
!!modifiersSet[0]?.size && t.unaryExpression('void', t.numericLiteral(0), true),
modifiersSet[0]?.size
? args[0] || t.unaryExpression('void', t.numericLiteral(0), true)
: args[0],
!!modifiersSet[0]?.size && t.objectExpression(
[...modifiersSet[0]].map(
(modifier) => t.objectProperty(
@ -116,7 +119,7 @@ const parseDirectives = (params: {
),
),
),
].filter(Boolean as any as ExcludesBoolean) : undefined,
].filter(Boolean) as t.Expression[] : undefined,
};
};

View File

@ -36,6 +36,24 @@ exports[`custom directive: custom directive 1`] = `
_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"cus\\"), x]]);"
`;
exports[`custom directive: custom directive 2`] = `
"import { withDirectives as _withDirectives, createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent, Fragment as _Fragment } from \\"vue\\";
_createVNode(_Fragment, null, [_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, 'y']]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, 'y', {
a: true,
b: true
}]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, void 0, {
a: true,
b: true
}]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, y, {
a: true,
b: true
}]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, y, {
a: true,
b: true
}]])]);"
`;
exports[`disable object slot syntax with defaultSlot: defaultSlot 1`] = `
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";

View File

@ -257,32 +257,6 @@ describe('Transform JSX', () => {
});
describe('directive', () => {
test('custom', () => {
const calls: number[] = [];
const customDirective = {
mounted() {
calls.push(1);
},
};
const wrapper = shallowMount({
directives: { custom: customDirective },
setup() {
return () => (
<a
v-custom={{
value: 123,
modifiers: { modifier: true },
arg: 'arg',
}}
/>
);
},
});
const node = wrapper.vm.$.subTree;
expect(calls).toEqual(expect.arrayContaining([1]));
expect(node.dirs).toHaveLength(1);
});
test('vHtml', () => {
const wrapper = shallowMount({
setup() {

View File

@ -139,6 +139,20 @@ const transpile = (
a = <A>{a}</A>;
`,
},
{
name: 'custom directive',
from: `
<>
<A v-xxx={x} />
<A v-xxx={[x]} />
<A v-xxx={[x, 'y']} />
<A v-xxx={[x, 'y', ['a', 'b']]} />
<A v-xxx={[x, ['a', 'b']]} />
<A v-xxx={[x, y, ['a', 'b']]} />
<A v-xxx={[x, y, ['a', 'b']]} />
</>
`,
},
{
name: 'vModels',
from: '<C v-models={[[foo, ["modifier"]], [bar, "bar", ["modifier1", "modifier2"]]]} />',