refactor: support transformOn

This commit is contained in:
Amour1688 2020-05-26 21:04:56 +08:00
parent 402568dc52
commit 7a1a39a4cb
19 changed files with 161 additions and 95 deletions

View File

@ -1,8 +0,0 @@
{
"presets": [
"@babel/env"
],
"plugins": [
"./src/index.js"
]
}

6
lerna.json Normal file
View File

@ -0,0 +1,6 @@
{
"packages": [
"packages/*"
],
"version": "0.0.0"
}

View File

@ -1,49 +1,17 @@
{
"name": "@ant-design-vue/babel-plugin-jsx",
"version": "1.0.0-alpha.2",
"description": "Babel plugin for Vue 3.0 JSX",
"main": "src/index.js",
"scripts": {
"dev": "webpack-dev-server",
"lint": "eslint --ext .js src",
"test": "jest --config .jest.js"
"publish": "lerna publish"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vueComponent/jsx.git"
},
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/vueComponent/jsx/issues"
},
"homepage": "https://github.com/vueComponent/jsx#readme",
"keywords": [
"vue",
"jsx"
],
"dependencies": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.0.0",
"camelcase": "^6.0.0",
"html-tags": "^3.1.0",
"svg-tags": "^1.0.0"
},
"devDependencies": {
"@babel/core": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"@vue/test-utils": "^2.0.0-alpha.6",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.0.1",
"babel-loader": "^8.1.0",
"eslint": "^7.0.0",
"eslint-config-airbnb": "^18.1.0",
"eslint-plugin-import": "^2.20.2",
"jest": "^26.0.1",
"regenerator-runtime": "^0.13.5",
"vue": "^3.0.0-beta.14",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
"lerna": "^3.19.0"
}
}

View File

@ -0,0 +1,11 @@
# @ant-design-vue/babel-helper-vue-transform-on
A package used internally by vue jsx transformer to merge props spread. It is required to merge some prop trees like this:
## Usage
```
const babelHelperVueTransformOn = require('babel-helper-vue-transform-on');
// TODO: DEMONSTRATE API
```

View File

@ -0,0 +1,9 @@
const transformOn = (obj) => {
const result = {};
Object.keys(obj).forEach((evt) => {
result[`on${evt[0].toUpperCase()}${evt.substr(1)}`] = obj[evt];
});
return result;
};
module.exports = transformOn;

View File

@ -0,0 +1,9 @@
{
"name": "@ant-design-vue/babel-helper-vue-transform-on",
"version": "1.0.0",
"description": "> TODO: description",
"author": "Amour1688 <lcz_1996@foxmail.com>",
"license": "MIT",
"main": "index.js",
"private": true
}

View File

@ -0,0 +1,13 @@
{
"presets": [
[
"@babel/env",
{
// "modules": "cjs"
}
]
],
"plugins": [
["./src/index.js", { "transformOn": true }]
]
}

View File

@ -0,0 +1,11 @@
# `babel-plugin-jsx`
> TODO: description
## Usage
```
const babelPluginJsx = require('babel-plugin-jsx');
// TODO: DEMONSTRATE API
```

View File

@ -1,19 +1,26 @@
import { createApp, ref, defineComponent } from 'vue';
const SuperButton = (props, context) => (
<div class={props.class}>
Super
<button
on={{
const SuperButton = (props, context) => {
const obj = {
mouseover: () => {
context.emit('mouseover');
},
click: () => {
context.emit('click');
},
}}
};
return (
<div class={props.class}>
Super
<button
on={obj}
>
{ props.buttonText }
{context.slots.default()}
</button>
</div>
);
);
};
SuperButton.inheritAttrs = false;
@ -23,17 +30,23 @@ const App = defineComponent(() => {
count.value++;
};
const obj = {
click: inc,
mouseover: inc,
};
return () => (
<>
<div>
Foo {count.value}
<SuperButton
buttonText="VueComponent"
class="xxx"
on={{
click: inc,
}}
/>
</>
vShow={true}
on={obj}
>
<button>1234</button>
</SuperButton>
</div>
);
});

View File

@ -0,0 +1,42 @@
{
"name": "@ant-design-vue/babel-plugin-jsx",
"version": "1.0.0",
"description": "Babel plugin for Vue 3.0 JSX",
"author": "Amour1688 <lcz_1996@foxmail.com>",
"homepage": "https://github.com/vueComponent/jsx/tree/master/packages/babel-plugin-jsx#readme",
"license": "MIT",
"main": "src/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/vueComponent/jsx.git"
},
"scripts": {
"dev": "webpack-dev-server",
"lint": "eslint --ext .js src",
"test": "jest --config .jest.js"
},
"bugs": {
"url": "https://github.com/vueComponent/jsx/issues"
},
"dependencies": {
"@ant-design-vue/babel-helper-vue-transform-on": "^1.0.0",
"@babel/helper-module-imports": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.0.0",
"camelcase": "^6.0.0",
"html-tags": "^3.1.0",
"svg-tags": "^1.0.0"
},
"devDependencies": {
"@babel/core": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"@vue/test-utils": "^2.0.0-alpha.6",
"babel-jest": "^26.0.1",
"babel-loader": "^8.1.0",
"jest": "^26.0.1",
"regenerator-runtime": "^0.13.5",
"vue": "^3.0.0-beta.14",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
}
}

View File

@ -3,12 +3,12 @@ const tranformVueJSX = require('./transform-vue-jsx');
const sugarVModel = require('./sugar-v-model');
const sugarFragment = require('./sugar-fragment');
module.exports = ({ types: t }) => ({
module.exports = ({ types: t }, opts = {}) => ({
name: 'babel-plugin-jsx',
inherits: syntaxJsx,
visitor: {
...sugarVModel(t),
...tranformVueJSX(t),
...tranformVueJSX(t, opts),
...sugarFragment(t),
},
});

View File

@ -1,16 +1,11 @@
const htmlTags = require('html-tags');
const svgTags = require('svg-tags');
const { addNamed } = require('@babel/helper-module-imports');
const { addNamed, addDefault } = require('@babel/helper-module-imports');
const xlinkRE = /^xlink([A-Z])/;
const eventRE = /^on[A-Z][a-z]+$/;
const rootAttributes = ['class', 'style'];
/**
* click --> onClick
*/
const transformOn = (event = '') => `on${event[0].toUpperCase()}${event.substr(1)}`;
/**
* Checks if string is describing a directive
@ -85,18 +80,15 @@ const getJSXAttributeValue = (t, path) => {
return null;
};
const transformJSXAttribute = (t, path, attributesToMerge, directives) => {
const transformJSXAttribute = (t, path, state, attributesToMerge, directives) => {
let name = getJSXAttributeName(t, path);
if (name === 'on') {
const { properties = [] } = getJSXAttributeValue(t, path);
properties.forEach((property) => {
attributesToMerge.push(t.objectExpression([
t.objectProperty(
t.identifier(transformOn(property.key.name)),
property.value,
),
]));
});
const attributeValue = getJSXAttributeValue(t, path);
if (state.opts.transformOn && (name === 'on' || name === 'nativeOn')) {
const transformOn = addDefault(path, '@ant-design-vue/babel-helper-vue-transform-on', { nameHint: '_transformOn' });
attributesToMerge.push(t.callExpression(
transformOn,
[attributeValue || t.booleanLiteral(true)],
));
return null;
}
if (isDirective(name)) {
@ -104,18 +96,18 @@ const transformJSXAttribute = (t, path, attributesToMerge, directives) => {
? name.replace('v-', '')
: name.replace(`v${name[1]}`, name[1].toLowerCase());
if (directiveName === '_model') {
directives.push(getJSXAttributeValue(t, path));
directives.push(attributeValue);
} else if (directiveName === 'show') {
directives.push(t.arrayExpression([
path.vShow,
getJSXAttributeValue(t, path),
state.vShow,
attributeValue,
]));
} else {
directives.push(t.arrayExpression([
t.callExpression(path.resolveDirective, [
t.callExpression(state.resolveDirective, [
t.stringLiteral(directiveName),
]),
getJSXAttributeValue(t, path),
attributeValue,
]));
}
return null;
@ -127,7 +119,7 @@ const transformJSXAttribute = (t, path, attributesToMerge, directives) => {
t.stringLiteral(
name,
),
getJSXAttributeValue(t, path),
attributeValue,
),
]),
);
@ -141,7 +133,7 @@ const transformJSXAttribute = (t, path, attributesToMerge, directives) => {
t.stringLiteral(
name,
),
getJSXAttributeValue(t, path) || t.booleanLiteral(true),
attributeValue || t.booleanLiteral(true),
);
};
@ -169,12 +161,12 @@ const transformJSXSpreadAttribute = (t, path, attributesToMerge) => {
})));
};
const transformAttribute = (t, path, attributesToMerge, directives) => (
const transformAttribute = (t, path, state, attributesToMerge, directives) => (
path.isJSXAttribute()
? transformJSXAttribute(t, path, attributesToMerge, directives)
? transformJSXAttribute(t, path, state, attributesToMerge, directives)
: transformJSXSpreadAttribute(t, path, attributesToMerge));
const getAttributes = (t, path, directives) => {
const getAttributes = (t, path, state, directives) => {
const attributes = path.get('openingElement').get('attributes');
if (attributes.length === 0) {
return t.nullLiteral();
@ -184,13 +176,13 @@ const getAttributes = (t, path, directives) => {
const attributeArray = [];
attributes
.forEach((attribute) => {
const attr = transformAttribute(t, attribute, attributesToMerge, directives);
const attr = transformAttribute(t, attribute, state, attributesToMerge, directives);
if (attr) {
attributeArray.push(attr);
}
});
return t.callExpression(
path.mergeProps,
state.mergeProps,
[
...attributesToMerge,
t.objectExpression(attributeArray),
@ -295,18 +287,18 @@ const getChildren = (t, paths) => paths
&& !t.isJSXEmptyExpression(value)
));
const transformJSXElement = (t, path) => {
const transformJSXElement = (t, path, state) => {
const directives = [];
const tag = getTag(t, path);
const children = t.arrayExpression(getChildren(t, path.get('children')));
const h = t.callExpression(path.h, [
const h = t.callExpression(state.h, [
tag,
getAttributes(t, path, directives),
getAttributes(t, path, state, directives),
!t.isStringLiteral(tag)
? t.objectExpression([
t.objectProperty(
t.identifier('default'),
t.callExpression(path.withCtx, [
t.callExpression(state.withCtx, [
t.arrowFunctionExpression(
[],
children,
@ -319,7 +311,7 @@ const transformJSXElement = (t, path) => {
if (!directives.length) {
return h;
}
return t.callExpression(path.withDirectives, [
return t.callExpression(state.withDirectives, [
h,
t.arrayExpression(directives),
]);
@ -332,14 +324,14 @@ const imports = [
module.exports = (t) => ({
JSXElement: {
exit(path) {
exit(path, state) {
imports.forEach((m) => {
if (!path[m]) {
path[m] = addNamed(path, m, 'vue');
if (!state[m]) {
state[m] = addNamed(path, m, 'vue');
}
});
path.replaceWith(
transformJSXElement(t, path),
transformJSXElement(t, path, state),
);
},
},