@tarojs/taroize 3.6.18 → 3.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/src/constant.js +1 -1
- package/lib/src/events.js +28 -1
- package/lib/src/events.js.map +1 -1
- package/lib/src/global.js +6 -2
- package/lib/src/global.js.map +1 -1
- package/lib/src/index.js +3 -3
- package/lib/src/index.js.map +1 -1
- package/lib/src/script.js +45 -29
- package/lib/src/script.js.map +1 -1
- package/lib/src/template.js +133 -25
- package/lib/src/template.js.map +1 -1
- package/lib/src/utils.js +163 -37
- package/lib/src/utils.js.map +1 -1
- package/lib/src/vue.js +26 -25
- package/lib/src/vue.js.map +1 -1
- package/lib/src/wxml.js +576 -137
- package/lib/src/wxml.js.map +1 -1
- package/package.json +38 -4
package/lib/src/wxml.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseContent = exports.removEmptyTextAndComment = exports.parseWXML = exports.createWxmlVistor = exports.wxTemplateCommand = exports.WX_ELSE = exports.WX_KEY = exports.WX_FOR_INDEX = exports.WX_FOR_ITEM = exports.WX_FOR = exports.WX_ELSE_IF = exports.WX_IF = exports.NodeType = void 0;
|
|
3
|
+
exports.parseStyle = exports.parseContent = exports.removEmptyTextAndComment = exports.parseWXML = exports.createWxmlVistor = exports.getWxsImports = exports.createPreWxmlVistor = exports.convertStyleUnit = exports.wxTemplateCommand = exports.WX_SHOW = exports.WX_ELSE = exports.WX_KEY = exports.WX_FOR_INDEX = exports.WX_FOR_ITEM = exports.WX_FOR = exports.WX_ELSE_IF = exports.WX_IF = exports.NodeType = void 0;
|
|
4
4
|
/* eslint-disable camelcase */
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
5
|
+
const parser_1 = require("@babel/parser");
|
|
6
|
+
const traverse_1 = require("@babel/traverse");
|
|
7
|
+
const t = require("@babel/types");
|
|
8
|
+
const helper_1 = require("@tarojs/helper");
|
|
9
|
+
const shared_1 = require("@tarojs/shared");
|
|
8
10
|
const himalaya_wxml_1 = require("himalaya-wxml");
|
|
9
11
|
const lodash_1 = require("lodash");
|
|
10
12
|
const cache_1 = require("./cache");
|
|
@@ -14,6 +16,7 @@ const global_1 = require("./global");
|
|
|
14
16
|
const template_1 = require("./template");
|
|
15
17
|
const utils_1 = require("./utils");
|
|
16
18
|
const { prettyPrint } = require('html');
|
|
19
|
+
const pathTool = require('path');
|
|
17
20
|
const allCamelCase = (str) => str.charAt(0).toUpperCase() + (0, lodash_1.camelCase)(str.substr(1));
|
|
18
21
|
function buildSlotName(slotName) {
|
|
19
22
|
return `render${slotName[0].toUpperCase() + slotName.replace('-', '').slice(1)}`;
|
|
@@ -31,37 +34,183 @@ exports.WX_FOR_ITEM = 'wx:for-item';
|
|
|
31
34
|
exports.WX_FOR_INDEX = 'wx:for-index';
|
|
32
35
|
exports.WX_KEY = 'wx:key';
|
|
33
36
|
exports.WX_ELSE = 'wx:else';
|
|
34
|
-
exports.
|
|
35
|
-
|
|
36
|
-
exports.WX_ELSE_IF,
|
|
37
|
-
exports.WX_FOR,
|
|
38
|
-
exports.WX_FOR_ITEM,
|
|
39
|
-
exports.WX_FOR_INDEX,
|
|
40
|
-
exports.WX_KEY,
|
|
41
|
-
'wx:else'
|
|
42
|
-
];
|
|
37
|
+
exports.WX_SHOW = 'wx:show';
|
|
38
|
+
exports.wxTemplateCommand = [exports.WX_IF, exports.WX_ELSE_IF, exports.WX_FOR, exports.WX_FOR_ITEM, exports.WX_FOR_INDEX, exports.WX_KEY, 'wx:else'];
|
|
43
39
|
function buildElement(name, children = [], attributes = []) {
|
|
44
40
|
return {
|
|
45
41
|
tagName: name,
|
|
46
42
|
type: NodeType.Element,
|
|
47
43
|
attributes,
|
|
48
|
-
children
|
|
44
|
+
children,
|
|
49
45
|
};
|
|
50
46
|
}
|
|
51
|
-
|
|
47
|
+
// 将 style 属性中属性名转小驼峰格式 并且将 {{}} 转为 ${}格式生成对应ast节点
|
|
48
|
+
function convertStyleAttrs(styleAttrsMap) {
|
|
49
|
+
styleAttrsMap.forEach((attr) => {
|
|
50
|
+
attr.attrName = (0, shared_1.toCamelCase)(attr.attrName.trim());
|
|
51
|
+
// 匹配 {{}} 内部以及左右两边值
|
|
52
|
+
const attrValueReg = /([^{}]*)\{\{([^{}]*)\}\}([^{}]*)/;
|
|
53
|
+
const matchs = attrValueReg.exec(attr.value);
|
|
54
|
+
if (matchs !== null) {
|
|
55
|
+
const tempLeftValue = matchs[1] || '';
|
|
56
|
+
const tempMidValue = matchs[2] || '';
|
|
57
|
+
const tempRightValue = matchs[3] || '';
|
|
58
|
+
// 将模版中的内容转换为 ast 节点
|
|
59
|
+
const tempMidValueAst = (0, parser_1.parse)(tempMidValue).program.body[0];
|
|
60
|
+
attr.value = t.templateLiteral([t.templateElement({ raw: tempLeftValue }), t.templateElement({ raw: tempRightValue }, true)], [tempMidValueAst.expression]);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
attr.value = t.stringLiteral(attr.value.trim());
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 对 style 中单个属性值进行解析
|
|
69
|
+
*
|
|
70
|
+
* @param { any[] } styleAttrsMap 元素为单个属性值的数组
|
|
71
|
+
* @param { any[] } attrKeyValueMap 属性解析为 {attrName: attrValue} 形式的数组
|
|
72
|
+
*/
|
|
73
|
+
function parseStyleAttrs(styleAttrsMap, attrKeyValueMap) {
|
|
74
|
+
styleAttrsMap.forEach((attr) => {
|
|
75
|
+
if (attr) {
|
|
76
|
+
// 对含三元运算符的写法 style="width:{{ xx ? xx : xx }}" 匹配第一个 : 避免匹配三元表达式中的 : 运算符
|
|
77
|
+
const reg = /([^:]+):\s*([^;]+)/;
|
|
78
|
+
const matchs = attr.match(reg);
|
|
79
|
+
const attrName = matchs[1];
|
|
80
|
+
const value = matchs[2];
|
|
81
|
+
if (attrName) {
|
|
82
|
+
attrKeyValueMap.push({ attrName, value });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function convertStyleUnit(value) {
|
|
88
|
+
let tempValue = value;
|
|
89
|
+
// 尺寸单位转换 都转为rem : 1rpx 转为 1/40rem,,1px 转为 1/20rem
|
|
90
|
+
if (tempValue.indexOf('px') !== -1) {
|
|
91
|
+
// 把 xxx="...[数字]rpx/px" 的尺寸单位都转为 rem, 转换方法类似postcss-taro-unit-transform
|
|
92
|
+
try {
|
|
93
|
+
tempValue = tempValue
|
|
94
|
+
.replace(/\s*-?([0-9.]+)(px)\b/gi, function (match, size, unit) {
|
|
95
|
+
if (Number(size) === 0) {
|
|
96
|
+
return match.replace(size, '0').replace(unit, 'rem');
|
|
97
|
+
}
|
|
98
|
+
// 绝对值<1的非零值转十进制会被转为0, 这种情况直接把值认为是1
|
|
99
|
+
if (parseInt(size, 10) === 0) {
|
|
100
|
+
return match.replace(size, '1').replace(unit, 'rem');
|
|
101
|
+
}
|
|
102
|
+
return match.replace(size, parseInt(size, 10) / 20 + '').replace(unit, 'rem');
|
|
103
|
+
})
|
|
104
|
+
.replace(/\s*-?([0-9.]+)(rpx)\b/gi, function (match, size, unit) {
|
|
105
|
+
if (Number(size) === 0) {
|
|
106
|
+
return match.replace(size, '0').replace(unit, 'rem');
|
|
107
|
+
}
|
|
108
|
+
if (parseInt(size, 10) === 0) {
|
|
109
|
+
return match.replace(size, '1').replace(unit, 'rem');
|
|
110
|
+
}
|
|
111
|
+
return match.replace(size, parseInt(size, 10) / 40 + '').replace(unit, 'rem');
|
|
112
|
+
});
|
|
113
|
+
// 把 xx="...{{参数}}rpx/px"的尺寸单位都转为rem,比如"{{参数}}rpx" -> "{{参数/40}}rem"
|
|
114
|
+
tempValue = tempValue
|
|
115
|
+
.replace(/\{\{([^{}]*)\}\}(px)/gi, function (match, size, unit) {
|
|
116
|
+
// 判断{{}}是否包含加减乘除算式和三元表达式, 是的话得加括号
|
|
117
|
+
if (match.match(/[+\-*/?]/g)) {
|
|
118
|
+
return match.replace(size, '(' + size + ')/20').replace(unit, 'rem');
|
|
119
|
+
}
|
|
120
|
+
return match.replace(size, size + '/20').replace(unit, 'rem');
|
|
121
|
+
})
|
|
122
|
+
.replace(/\{\{([^{}]*)\}\}(rpx)/gi, function (match, size, unit) {
|
|
123
|
+
if (match.match(/[+\-*/?]/g)) {
|
|
124
|
+
return match.replace(size, '(' + size + ')/40').replace(unit, 'rem');
|
|
125
|
+
}
|
|
126
|
+
return match.replace(size, size + '/40').replace(unit, 'rem');
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
(0, helper_1.printLog)("error" /* processTypeEnum.ERROR */, `wxml内px/rpx单位转换失败: ${error}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return tempValue;
|
|
134
|
+
}
|
|
135
|
+
exports.convertStyleUnit = convertStyleUnit;
|
|
136
|
+
/**
|
|
137
|
+
* 预解析,收集wxml所有的模板信息
|
|
138
|
+
*
|
|
139
|
+
* @param { any[] } templates wxml页面下的模板信息
|
|
140
|
+
* @returns Visitor
|
|
141
|
+
*/
|
|
142
|
+
const createPreWxmlVistor = (templates) => {
|
|
143
|
+
// const Applys = new Map<string, string[]>()
|
|
144
|
+
return {
|
|
145
|
+
JSXElement: {
|
|
146
|
+
enter(path) {
|
|
147
|
+
const openingElement = path.get('openingElement');
|
|
148
|
+
const jsxName = openingElement.get('name');
|
|
149
|
+
if (!jsxName.isJSXIdentifier()) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const tagName = jsxName.node.name;
|
|
153
|
+
if (tagName !== 'Template') {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const templateInfo = (0, template_1.preParseTemplate)(path);
|
|
157
|
+
if (templateInfo) {
|
|
158
|
+
templates.set(templateInfo.name, {
|
|
159
|
+
funcs: templateInfo.funcs,
|
|
160
|
+
applyTemplates: templateInfo.applys,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
exports.createPreWxmlVistor = createPreWxmlVistor;
|
|
168
|
+
/**
|
|
169
|
+
* 根据template中使用的wxs组装需要导入的wxs语句
|
|
170
|
+
* 如: import xxx from '../xxx.wxs.js'
|
|
171
|
+
*
|
|
172
|
+
* @param templateFileName template模版文件名
|
|
173
|
+
* @param usedWxses template中使用的变量是wxs模块的集合
|
|
174
|
+
* @param dirPath 当前解析文件的路径
|
|
175
|
+
* @returns 需要导入的wxs语句集合
|
|
176
|
+
*/
|
|
177
|
+
function getWxsImports(templateFileName, usedWxses, dirPath) {
|
|
178
|
+
const templatePath = pathTool.join(global_1.globals.rootPath, 'imports', `${templateFileName}.js`);
|
|
179
|
+
const wxsImports = [];
|
|
180
|
+
for (const usedWxs of usedWxses) {
|
|
181
|
+
const wxsAbsPath = pathTool.resolve(dirPath, `${usedWxs.src}.js`);
|
|
182
|
+
const wxsRelPath = pathTool.relative(pathTool.dirname(templatePath), wxsAbsPath);
|
|
183
|
+
wxsImports.push((0, utils_1.buildImportStatement)((0, utils_1.normalizePath)(wxsRelPath), [], usedWxs.module));
|
|
184
|
+
}
|
|
185
|
+
return wxsImports;
|
|
186
|
+
}
|
|
187
|
+
exports.getWxsImports = getWxsImports;
|
|
188
|
+
const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = [], templates) => {
|
|
52
189
|
const jsxAttrVisitor = (path) => {
|
|
53
190
|
const name = path.node.name;
|
|
54
|
-
const jsx = path.findParent(p => p.isJSXElement());
|
|
191
|
+
const jsx = path.findParent((p) => p.isJSXElement());
|
|
55
192
|
// 把 hidden 转换为 wxif
|
|
56
193
|
if (name.name === 'hidden') {
|
|
57
194
|
const value = path.get('value');
|
|
58
|
-
if (t.isJSXExpressionContainer(value)) {
|
|
195
|
+
if (t.isJSXExpressionContainer(value) && !t.isJSXEmptyExpression(value.node.expression)) {
|
|
59
196
|
const exclamation = t.unaryExpression('!', value.node.expression);
|
|
60
197
|
path.set('value', t.jSXExpressionContainer(exclamation));
|
|
61
198
|
path.set('name', t.jSXIdentifier(exports.WX_IF));
|
|
62
199
|
}
|
|
63
200
|
}
|
|
201
|
+
// 当设置图片mode="",则改为默认值(且taro不支持mode空值)
|
|
202
|
+
if (name.name === 'mode' && path.node.value === null) {
|
|
203
|
+
path.set('value', t.stringLiteral('scaleToFill'));
|
|
204
|
+
}
|
|
205
|
+
// 当设置 style 属性但未赋值则删除该属性
|
|
206
|
+
if (name.name === 'style' && !path.node.value) {
|
|
207
|
+
path.remove();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
64
210
|
const valueCopy = (0, lodash_1.cloneDeep)(path.get('value').node);
|
|
211
|
+
if (typeof valueCopy === 'undefined' || t.isJSXFragment(valueCopy)) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
65
214
|
transformIf(name.name, path, jsx, valueCopy);
|
|
66
215
|
const loopItem = transformLoop(name.name, path, jsx, valueCopy);
|
|
67
216
|
if (loopItem) {
|
|
@@ -76,10 +225,12 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
|
|
|
76
225
|
const renameJSXKey = (path) => {
|
|
77
226
|
const nodeName = path.node.name;
|
|
78
227
|
if (path.parentPath.isJSXAttribute()) {
|
|
79
|
-
if (nodeName === exports.
|
|
80
|
-
path.replaceWith(t.jSXIdentifier(
|
|
228
|
+
if (nodeName === exports.WX_SHOW) {
|
|
229
|
+
path.replaceWith(t.jSXIdentifier(exports.WX_IF)); // wx:show转换后不支持,不频繁切换的话wx:if可替代
|
|
230
|
+
// eslint-disable-next-line no-console
|
|
231
|
+
console.log(`属性 ${nodeName}不能编译,会被替换为wx:if`);
|
|
81
232
|
}
|
|
82
|
-
if (nodeName.startsWith('wx:') && !exports.wxTemplateCommand.includes(nodeName)) {
|
|
233
|
+
else if (nodeName.startsWith('wx:') && !exports.wxTemplateCommand.includes(nodeName)) {
|
|
83
234
|
// eslint-disable-next-line no-console
|
|
84
235
|
console.log(`未知 wx 作用域属性: ${nodeName},该属性会被移除掉。`);
|
|
85
236
|
path.parentPath.remove();
|
|
@@ -89,8 +240,23 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
|
|
|
89
240
|
return {
|
|
90
241
|
JSXAttribute: jsxAttrVisitor,
|
|
91
242
|
JSXIdentifier: renameJSXKey,
|
|
243
|
+
Identifier: {
|
|
244
|
+
enter(path) {
|
|
245
|
+
if (!path.isReferencedIdentifier()) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const jsxExprContainer = path.findParent((p) => p.isJSXExpressionContainer());
|
|
249
|
+
if (!jsxExprContainer || !jsxExprContainer.isJSXExpressionContainer()) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if ((0, utils_1.isValidVarName)(path.node.name)) {
|
|
253
|
+
refIds.add(path.node.name);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
},
|
|
92
257
|
JSXElement: {
|
|
93
258
|
enter(path) {
|
|
259
|
+
var _a;
|
|
94
260
|
const openingElement = path.get('openingElement');
|
|
95
261
|
const jsxName = openingElement.get('name');
|
|
96
262
|
const attrs = openingElement.get('attributes');
|
|
@@ -98,31 +264,22 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
|
|
|
98
264
|
return;
|
|
99
265
|
}
|
|
100
266
|
path.traverse({
|
|
101
|
-
Identifier(p) {
|
|
102
|
-
if (!p.isReferencedIdentifier()) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const jsxExprContainer = p.findParent(p => p.isJSXExpressionContainer());
|
|
106
|
-
if (!jsxExprContainer || !jsxExprContainer.isJSXExpressionContainer()) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if ((0, utils_1.isValidVarName)(p.node.name)) {
|
|
110
|
-
refIds.add(p.node.name);
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
267
|
JSXAttribute: jsxAttrVisitor,
|
|
114
|
-
JSXIdentifier: renameJSXKey
|
|
268
|
+
JSXIdentifier: renameJSXKey,
|
|
115
269
|
});
|
|
116
|
-
const slotAttr = attrs.find(a => { var _a; return ((_a = a.node) === null || _a === void 0 ? void 0 : _a.name.name) === 'slot'; });
|
|
117
|
-
if (slotAttr) {
|
|
270
|
+
const slotAttr = attrs.find((a) => { var _a; return t.isJSXAttribute(a.node) && ((_a = a.node) === null || _a === void 0 ? void 0 : _a.name.name) === 'slot'; });
|
|
271
|
+
if (slotAttr && t.isJSXAttribute(slotAttr.node)) {
|
|
118
272
|
const slotValue = slotAttr.node.value;
|
|
273
|
+
let slotName = '';
|
|
119
274
|
if (slotValue && t.isStringLiteral(slotValue)) {
|
|
120
|
-
|
|
121
|
-
const parentComponent = path.findParent(p => p.isJSXElement() &&
|
|
275
|
+
slotName = slotValue.value;
|
|
276
|
+
const parentComponent = path.findParent((p) => p.isJSXElement() &&
|
|
277
|
+
t.isJSXIdentifier(p.node.openingElement.name) &&
|
|
278
|
+
!utils_1.DEFAULT_Component_SET.has(p.node.openingElement.name.name));
|
|
122
279
|
if (parentComponent && parentComponent.isJSXElement()) {
|
|
123
280
|
slotAttr.remove();
|
|
124
281
|
path.traverse({
|
|
125
|
-
JSXAttribute: jsxAttrVisitor
|
|
282
|
+
JSXAttribute: jsxAttrVisitor,
|
|
126
283
|
});
|
|
127
284
|
const block = (0, utils_1.buildBlockElement)();
|
|
128
285
|
block.children = [(0, lodash_1.cloneDeep)(path.node)];
|
|
@@ -131,14 +288,15 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
|
|
|
131
288
|
}
|
|
132
289
|
}
|
|
133
290
|
else {
|
|
134
|
-
|
|
291
|
+
// 当元素设置slot标签且值为空串时,移除slot属性
|
|
292
|
+
slotAttr.remove();
|
|
135
293
|
}
|
|
136
294
|
}
|
|
137
295
|
const tagName = jsxName.node.name;
|
|
138
296
|
if (tagName === 'Slot') {
|
|
139
|
-
const nameAttr = attrs.find(a => a.node.name.name === 'name');
|
|
297
|
+
const nameAttr = attrs.find((a) => t.isJSXAttribute(a.node) && a.node.name.name === 'name');
|
|
140
298
|
let slotName = '';
|
|
141
|
-
if (nameAttr) {
|
|
299
|
+
if (nameAttr && t.isJSXAttribute(nameAttr.node)) {
|
|
142
300
|
if (nameAttr.node.value && t.isStringLiteral(nameAttr.node.value)) {
|
|
143
301
|
slotName = nameAttr.node.value.value;
|
|
144
302
|
}
|
|
@@ -155,46 +313,115 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
|
|
|
155
313
|
}
|
|
156
314
|
}
|
|
157
315
|
if (tagName === 'Wxs') {
|
|
158
|
-
wxses.push(getWXS(attrs.map(a => a.node), path, imports));
|
|
316
|
+
wxses.push(getWXS(attrs.map((a) => a.node), path, imports));
|
|
159
317
|
}
|
|
160
318
|
if (tagName === 'Template') {
|
|
161
|
-
|
|
162
|
-
// JSXAttribute: jsxAttrVisitor
|
|
163
|
-
// })
|
|
164
|
-
const template = (0, template_1.parseTemplate)(path, dirPath);
|
|
319
|
+
const template = (0, template_1.parseTemplate)(path, dirPath, wxses);
|
|
165
320
|
if (template) {
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
]);
|
|
321
|
+
let funcs = new Set();
|
|
322
|
+
const { ast: classDecl, name, tmplName, usedWxses } = template;
|
|
323
|
+
const wxsImports = getWxsImports(name, usedWxses, dirPath);
|
|
324
|
+
const taroComponentsImport = (0, utils_1.buildImportStatement)('@tarojs/components', [...global_1.usedComponents]);
|
|
170
325
|
const taroImport = (0, utils_1.buildImportStatement)('@tarojs/taro', [], 'Taro');
|
|
171
326
|
const reactImport = (0, utils_1.buildImportStatement)('react', [], 'React');
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
// [],
|
|
175
|
-
// 'withWeapp'
|
|
176
|
-
// )
|
|
327
|
+
// 引入 @tarojs/with-weapp
|
|
328
|
+
const withWeappImport = (0, utils_1.buildImportStatement)('@tarojs/with-weapp', [], 'withWeapp');
|
|
177
329
|
const ast = t.file(t.program([]));
|
|
178
|
-
ast.program.body.unshift(taroComponentsImport, reactImport, taroImport,
|
|
179
|
-
// withWeappImport,
|
|
180
|
-
t.exportDefaultDeclaration(classDecl));
|
|
330
|
+
ast.program.body.unshift(taroComponentsImport, reactImport, taroImport, withWeappImport, ...wxsImports, classDecl, t.exportDefaultDeclaration(t.identifier(name)));
|
|
181
331
|
const usedTemplate = new Set();
|
|
182
|
-
|
|
332
|
+
// funcs的值首先来源于预解析结果
|
|
333
|
+
if (templates) {
|
|
334
|
+
const applyFuncs = (_a = templates.get(name)) === null || _a === void 0 ? void 0 : _a.funcs;
|
|
335
|
+
if (applyFuncs) {
|
|
336
|
+
funcs = applyFuncs;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
(0, traverse_1.default)(ast, {
|
|
183
340
|
JSXIdentifier(path) {
|
|
184
341
|
const node = path.node;
|
|
185
342
|
if (node.name.endsWith('Tmpl') && node.name.length > 4 && path.parentPath.isJSXOpeningElement()) {
|
|
186
343
|
usedTemplate.add(node.name);
|
|
344
|
+
// 传递的方法有两处来源
|
|
345
|
+
const templateImport = imports.find((tmplImport) => tmplImport.name === `${node.name}`);
|
|
346
|
+
const templateInfo = templates === null || templates === void 0 ? void 0 : templates.get(node.name);
|
|
347
|
+
let templateFuncs = templateImport === null || templateImport === void 0 ? void 0 : templateImport.funcs;
|
|
348
|
+
if (templateInfo === null || templateInfo === void 0 ? void 0 : templateInfo.funcs) {
|
|
349
|
+
if (templateFuncs) {
|
|
350
|
+
templateFuncs = new Set([...templateFuncs, ...templateInfo.funcs]);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
templateFuncs = templateInfo.funcs;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (templateFuncs && templateFuncs.size > 0) {
|
|
357
|
+
const openingElement = path.parentPath.node;
|
|
358
|
+
const attributes = openingElement.attributes;
|
|
359
|
+
templateFuncs.forEach((templateFunc) => {
|
|
360
|
+
const value = t.jsxExpressionContainer(t.identifier(templateFunc));
|
|
361
|
+
const name = t.jsxIdentifier(templateFunc);
|
|
362
|
+
// 传递的方法插入到Tmpl标签属性中
|
|
363
|
+
attributes.push(t.jsxAttribute(name, value));
|
|
364
|
+
if (!funcs.has(templateFunc)) {
|
|
365
|
+
funcs.add(templateFunc);
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}
|
|
187
369
|
}
|
|
188
|
-
}
|
|
370
|
+
},
|
|
371
|
+
JSXAttribute(path) {
|
|
372
|
+
// 识别template使用到的处理事件的func
|
|
373
|
+
const node = path.node;
|
|
374
|
+
if (t.isJSXExpressionContainer(node.value) &&
|
|
375
|
+
t.isMemberExpression(node.value.expression) &&
|
|
376
|
+
t.isThisExpression(node.value.expression.object) &&
|
|
377
|
+
t.isIdentifier(node.value.expression.property)) {
|
|
378
|
+
const funcName = node.value.expression.property.name;
|
|
379
|
+
// func的调用形式 this.func --> func
|
|
380
|
+
path.replaceWith(t.jsxAttribute(node.name, t.jsxExpressionContainer(t.identifier(funcName))));
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
(0, traverse_1.default)(ast, {
|
|
385
|
+
// 将使用到的处理事件的func写入到props
|
|
386
|
+
BlockStatement(path) {
|
|
387
|
+
if (funcs.size > 0) {
|
|
388
|
+
const body = path.node.body;
|
|
389
|
+
if (t.isVariableDeclaration(body[0])) {
|
|
390
|
+
// 如果已经定义了props
|
|
391
|
+
const declarator = body[0].declarations[0];
|
|
392
|
+
if (t.isObjectPattern(declarator.id)) {
|
|
393
|
+
const properties = declarator.id.properties;
|
|
394
|
+
funcs.forEach((func) => {
|
|
395
|
+
properties.push(t.objectProperty(t.identifier(func), t.identifier(func), false, true));
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
// 没有定义,则插入 const {xxx} = this.props
|
|
401
|
+
const properties = [];
|
|
402
|
+
funcs.forEach((func) => {
|
|
403
|
+
properties.push(t.objectProperty(t.identifier(func), t.identifier(func), false, true));
|
|
404
|
+
});
|
|
405
|
+
const id = t.objectPattern(properties);
|
|
406
|
+
const init = t.memberExpression(t.thisExpression(), t.identifier('props'));
|
|
407
|
+
const declarator = t.variableDeclarator(id, init);
|
|
408
|
+
const declaration = t.variableDeclaration('const', [declarator]);
|
|
409
|
+
body.splice(0, 0, declaration);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
path.stop();
|
|
413
|
+
},
|
|
189
414
|
});
|
|
190
|
-
usedTemplate.forEach(componentName => {
|
|
415
|
+
usedTemplate.forEach((componentName) => {
|
|
191
416
|
if (componentName !== classDecl.id.name) {
|
|
192
417
|
ast.program.body.unshift((0, utils_1.buildImportStatement)(`./${componentName}`, [], componentName));
|
|
193
418
|
}
|
|
194
419
|
});
|
|
195
420
|
imports.push({
|
|
196
421
|
ast,
|
|
197
|
-
name
|
|
422
|
+
name,
|
|
423
|
+
funcs,
|
|
424
|
+
tmplName,
|
|
198
425
|
});
|
|
199
426
|
}
|
|
200
427
|
}
|
|
@@ -217,7 +444,9 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
|
|
|
217
444
|
const children = path.node.children;
|
|
218
445
|
if (children.length === 1) {
|
|
219
446
|
const caller = children[0];
|
|
220
|
-
if (t.isJSXExpressionContainer(caller) &&
|
|
447
|
+
if (t.isJSXExpressionContainer(caller) &&
|
|
448
|
+
t.isCallExpression(caller.expression) &&
|
|
449
|
+
!path.parentPath.isExpressionStatement()) {
|
|
221
450
|
try {
|
|
222
451
|
path.replaceWith(caller);
|
|
223
452
|
}
|
|
@@ -226,11 +455,61 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
|
|
|
226
455
|
}
|
|
227
456
|
}
|
|
228
457
|
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
458
|
+
},
|
|
459
|
+
},
|
|
231
460
|
};
|
|
232
461
|
};
|
|
233
462
|
exports.createWxmlVistor = createWxmlVistor;
|
|
463
|
+
/**
|
|
464
|
+
* @description 根据模板信息中的直接调用,遍历获取完整的调用
|
|
465
|
+
* @param templates 模板信息
|
|
466
|
+
*/
|
|
467
|
+
function templateBfs(templates) {
|
|
468
|
+
var _a;
|
|
469
|
+
const names = [];
|
|
470
|
+
const applys = new Map();
|
|
471
|
+
for (const key of templates.keys()) {
|
|
472
|
+
names.push(key);
|
|
473
|
+
const templateInfo = templates.get(key);
|
|
474
|
+
if (templateInfo) {
|
|
475
|
+
applys.set(key, templateInfo.applyTemplates);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
for (const name of names) {
|
|
479
|
+
const templateInfo = templates.get(name);
|
|
480
|
+
if (!templateInfo || templateInfo.applyTemplates.size === 0) {
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
const visited = new Set();
|
|
484
|
+
const queue = [name];
|
|
485
|
+
while (queue.length > 0) {
|
|
486
|
+
const template = queue.shift();
|
|
487
|
+
if (visited.has(template)) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
visited.add(template);
|
|
491
|
+
const templateApplys = applys.get(template);
|
|
492
|
+
if (!templateApplys || templateApplys.size === 0) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
templateApplys.forEach((item) => {
|
|
496
|
+
if (names.includes(item)) {
|
|
497
|
+
queue.push(item);
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
visited.delete(name);
|
|
502
|
+
templateInfo.applyTemplates = visited;
|
|
503
|
+
for (const item of visited) {
|
|
504
|
+
const applyFuncs = (_a = templates.get(item)) === null || _a === void 0 ? void 0 : _a.funcs;
|
|
505
|
+
if (applyFuncs) {
|
|
506
|
+
const funcs = templateInfo.funcs;
|
|
507
|
+
templateInfo.funcs = new Set([...funcs, ...applyFuncs]);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
templates.set(name, templateInfo);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
234
513
|
function parseWXML(dirPath, wxml, parseImport) {
|
|
235
514
|
let parseResult = (0, cache_1.getCacheWxml)(dirPath);
|
|
236
515
|
if (parseResult) {
|
|
@@ -240,7 +519,7 @@ function parseWXML(dirPath, wxml, parseImport) {
|
|
|
240
519
|
wxml = prettyPrint(wxml, {
|
|
241
520
|
max_char: 0,
|
|
242
521
|
indent_char: 0,
|
|
243
|
-
unformatted: ['text', 'wxs']
|
|
522
|
+
unformatted: ['text', 'wxs'],
|
|
244
523
|
});
|
|
245
524
|
}
|
|
246
525
|
catch (error) {
|
|
@@ -255,21 +534,30 @@ function parseWXML(dirPath, wxml, parseImport) {
|
|
|
255
534
|
const imports = [];
|
|
256
535
|
const refIds = new Set();
|
|
257
536
|
const loopIds = new Set();
|
|
537
|
+
// 模板信息
|
|
538
|
+
const templates = new Map();
|
|
258
539
|
if (!wxml) {
|
|
259
540
|
return {
|
|
260
541
|
wxses,
|
|
261
542
|
imports,
|
|
262
543
|
refIds,
|
|
263
|
-
wxml: t.nullLiteral()
|
|
544
|
+
wxml: t.nullLiteral(),
|
|
264
545
|
};
|
|
265
546
|
}
|
|
266
547
|
const nodes = removEmptyTextAndComment((0, himalaya_wxml_1.parse)(wxml.trim()));
|
|
267
|
-
const ast = t.file(t.program([
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
(0,
|
|
271
|
-
|
|
272
|
-
|
|
548
|
+
const ast = t.file(t.program([t.expressionStatement(parseNode(buildElement('block', nodes)))], []));
|
|
549
|
+
// 在解析wxml页面前,先进行预解析
|
|
550
|
+
// 当前预解析主要为了抽取页面下的模板信息
|
|
551
|
+
(0, traverse_1.default)(ast, (0, exports.createPreWxmlVistor)(templates));
|
|
552
|
+
// 获取template调用后,需要通过遍历,获取某个模板完整的调用关系
|
|
553
|
+
templateBfs(templates);
|
|
554
|
+
(0, traverse_1.default)(ast, (0, exports.createWxmlVistor)(loopIds, refIds, dirPath, wxses, imports, templates));
|
|
555
|
+
refIds.forEach((id) => {
|
|
556
|
+
if (loopIds.has(id) ||
|
|
557
|
+
imports
|
|
558
|
+
.filter((i) => i.wxs)
|
|
559
|
+
.map((i) => i.name)
|
|
560
|
+
.includes(id)) {
|
|
273
561
|
refIds.delete(id);
|
|
274
562
|
}
|
|
275
563
|
});
|
|
@@ -277,7 +565,7 @@ function parseWXML(dirPath, wxml, parseImport) {
|
|
|
277
565
|
wxses,
|
|
278
566
|
imports,
|
|
279
567
|
wxml: hydrate(ast),
|
|
280
|
-
refIds
|
|
568
|
+
refIds,
|
|
281
569
|
};
|
|
282
570
|
(0, cache_1.saveCacheWxml)(dirPath, parseResult);
|
|
283
571
|
return parseResult;
|
|
@@ -297,8 +585,7 @@ function getWXS(attrs, path, imports) {
|
|
|
297
585
|
if (t.isStringLiteral(attrValue)) {
|
|
298
586
|
value = attrValue.value;
|
|
299
587
|
}
|
|
300
|
-
else if (t.isJSXExpressionContainer(attrValue) &&
|
|
301
|
-
t.isStringLiteral(attrValue.expression)) {
|
|
588
|
+
else if (t.isJSXExpressionContainer(attrValue) && t.isStringLiteral(attrValue.expression)) {
|
|
302
589
|
value = attrValue.expression.value;
|
|
303
590
|
}
|
|
304
591
|
if (attrName === 'module') {
|
|
@@ -310,23 +597,64 @@ function getWXS(attrs, path, imports) {
|
|
|
310
597
|
}
|
|
311
598
|
}
|
|
312
599
|
if (!src) {
|
|
313
|
-
const { children: [script] } = path.node;
|
|
600
|
+
const { children: [script], } = path.node;
|
|
314
601
|
if (!t.isJSXText(script)) {
|
|
315
602
|
throw new Error('wxs 如果没有 src 属性,标签内部必须有 wxs 代码。');
|
|
316
603
|
}
|
|
317
604
|
src = './wxs__' + moduleName;
|
|
318
605
|
const ast = (0, utils_1.parseCode)(script.value);
|
|
319
|
-
(0,
|
|
606
|
+
(0, traverse_1.default)(ast, {
|
|
320
607
|
CallExpression(path) {
|
|
608
|
+
var _a, _b, _c;
|
|
609
|
+
// wxs标签中getRegExp转换为new RegExp
|
|
321
610
|
if (t.isIdentifier(path.node.callee, { name: 'getRegExp' })) {
|
|
322
|
-
|
|
611
|
+
// 根据正则表达式是否定义了正则匹配修饰符,有则不变,没有就用默认
|
|
612
|
+
if (path.node.arguments.length > 1) {
|
|
613
|
+
const regex = path.node.arguments[0];
|
|
614
|
+
const modifier = path.node.arguments[1];
|
|
615
|
+
if (t.isStringLiteral(regex) && t.isStringLiteral(modifier)) {
|
|
616
|
+
const regexStr = (_a = regex.extra) === null || _a === void 0 ? void 0 : _a.raw;
|
|
617
|
+
const regexModifier = (_b = modifier.extra) === null || _b === void 0 ? void 0 : _b.rawValue;
|
|
618
|
+
const regexWithoutQuotes = regexStr.replace(/^['"](.*)['"]$/, '$1');
|
|
619
|
+
const newExpr = t.newExpression(t.identifier('RegExp'), [
|
|
620
|
+
t.stringLiteral(regexWithoutQuotes),
|
|
621
|
+
t.stringLiteral(regexModifier),
|
|
622
|
+
]);
|
|
623
|
+
path.replaceWith(newExpr);
|
|
624
|
+
}
|
|
625
|
+
else if (t.isIdentifier(regex) || t.isIdentifier(modifier)) {
|
|
626
|
+
throw new Error('getRegExp 函数暂不支持传入变量类型的参数');
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
throw new Error('getRegExp 函数暂不支持传入非字符串类型的参数');
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else if (path.node.arguments.length === 1) {
|
|
633
|
+
const regex = path.node.arguments[0];
|
|
634
|
+
if (t.isStringLiteral(regex)) {
|
|
635
|
+
const regexStr = (_c = regex.extra) === null || _c === void 0 ? void 0 : _c.raw;
|
|
636
|
+
const regexWithoutQuotes = regexStr.replace(/^['"](.*)['"]$/, '$1');
|
|
637
|
+
const newExpr = t.newExpression(t.identifier('RegExp'), [t.stringLiteral(regexWithoutQuotes)]);
|
|
638
|
+
path.replaceWith(newExpr);
|
|
639
|
+
}
|
|
640
|
+
else if (t.isIdentifier(regex)) {
|
|
641
|
+
throw new Error('getRegExp 函数暂不支持传入变量类型的参数');
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
throw new Error('getRegExp 函数暂不支持传入非字符串类型的参数');
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
const newExpr = t.newExpression(t.identifier('RegExp'), []);
|
|
649
|
+
path.replaceWith(newExpr);
|
|
650
|
+
}
|
|
323
651
|
}
|
|
324
|
-
}
|
|
652
|
+
},
|
|
325
653
|
});
|
|
326
654
|
imports.push({
|
|
327
655
|
ast,
|
|
328
656
|
name: moduleName,
|
|
329
|
-
wxs: true
|
|
657
|
+
wxs: true,
|
|
330
658
|
});
|
|
331
659
|
}
|
|
332
660
|
if (!moduleName || !src) {
|
|
@@ -335,7 +663,7 @@ function getWXS(attrs, path, imports) {
|
|
|
335
663
|
path.remove();
|
|
336
664
|
return {
|
|
337
665
|
module: moduleName,
|
|
338
|
-
src
|
|
666
|
+
src,
|
|
339
667
|
};
|
|
340
668
|
}
|
|
341
669
|
function hydrate(file) {
|
|
@@ -344,9 +672,7 @@ function hydrate(file) {
|
|
|
344
672
|
const jsx = ast.expression;
|
|
345
673
|
if (jsx.children.length === 1) {
|
|
346
674
|
const children = jsx.children[0];
|
|
347
|
-
return t.isJSXExpressionContainer(children)
|
|
348
|
-
? children.expression
|
|
349
|
-
: children;
|
|
675
|
+
return t.isJSXExpressionContainer(children) ? children.expression : children;
|
|
350
676
|
}
|
|
351
677
|
else {
|
|
352
678
|
return jsx;
|
|
@@ -358,9 +684,9 @@ function transformLoop(name, attr, jsx, value) {
|
|
|
358
684
|
if (!jsxElement.node) {
|
|
359
685
|
return;
|
|
360
686
|
}
|
|
361
|
-
const attrs = jsxElement.get('attributes').map(a => a.node);
|
|
362
|
-
const wxForItem = attrs.find(a => a.name.name === exports.WX_FOR_ITEM);
|
|
363
|
-
const hasSinglewxForItem = wxForItem && wxForItem.value && t.isJSXExpressionContainer(wxForItem.value);
|
|
687
|
+
const attrs = jsxElement.get('attributes').map((a) => a.node);
|
|
688
|
+
const wxForItem = attrs.find((a) => t.isJSXAttribute(a) && a.name.name === exports.WX_FOR_ITEM);
|
|
689
|
+
const hasSinglewxForItem = wxForItem && t.isJSXAttribute(wxForItem) && wxForItem.value && t.isJSXExpressionContainer(wxForItem.value);
|
|
364
690
|
if (hasSinglewxForItem || name === exports.WX_FOR || name === 'wx:for-items') {
|
|
365
691
|
if (!value || !t.isJSXExpressionContainer(value)) {
|
|
366
692
|
throw new Error('wx:for 的值必须使用 "{{}}" 包裹');
|
|
@@ -371,7 +697,7 @@ function transformLoop(name, attr, jsx, value) {
|
|
|
371
697
|
jsx
|
|
372
698
|
.get('openingElement')
|
|
373
699
|
.get('attributes')
|
|
374
|
-
.forEach(p => {
|
|
700
|
+
.forEach((p) => {
|
|
375
701
|
const node = p.node;
|
|
376
702
|
if (node.name.name === exports.WX_FOR_ITEM) {
|
|
377
703
|
if (!node.value || !t.isStringLiteral(node.value)) {
|
|
@@ -391,19 +717,49 @@ function transformLoop(name, attr, jsx, value) {
|
|
|
391
717
|
jsx
|
|
392
718
|
.get('openingElement')
|
|
393
719
|
.get('attributes')
|
|
394
|
-
.forEach(p => {
|
|
720
|
+
.forEach((p) => {
|
|
395
721
|
const node = p.node;
|
|
396
|
-
if (node.name.name === exports.WX_KEY
|
|
397
|
-
|
|
398
|
-
|
|
722
|
+
if (node.name.name === exports.WX_KEY) {
|
|
723
|
+
node.name = t.jSXIdentifier('key');
|
|
724
|
+
if (t.isStringLiteral(node.value)) {
|
|
725
|
+
if (node.value.value === '*this') {
|
|
726
|
+
node.value = t.jSXExpressionContainer(t.identifier(item.value));
|
|
727
|
+
}
|
|
728
|
+
else if (node.value.value === 'index') {
|
|
729
|
+
// index表示item在数组里的下标, 并不是item的某个property, 单独抽出来处理
|
|
730
|
+
node.value = t.jSXExpressionContainer(t.identifier(node.value.value));
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
node.value = t.jSXExpressionContainer(t.memberExpression(t.identifier(item.value), t.identifier(node.value.value)));
|
|
734
|
+
}
|
|
399
735
|
}
|
|
400
|
-
|
|
401
|
-
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
jsx
|
|
739
|
+
.get('openingElement')
|
|
740
|
+
.get('attributes')
|
|
741
|
+
.forEach((p) => {
|
|
742
|
+
const node = p.node;
|
|
743
|
+
if (node.name.name === exports.WX_IF) {
|
|
744
|
+
// 如果同时使用了 wx:if,分离
|
|
745
|
+
const ifBlock = (0, utils_1.buildBlockElement)();
|
|
746
|
+
ifBlock.children = [(0, lodash_1.cloneDeep)(jsx.node)];
|
|
747
|
+
try {
|
|
748
|
+
jsx.replaceWith(ifBlock);
|
|
749
|
+
}
|
|
750
|
+
catch (error) {
|
|
751
|
+
// jsx外层是wx:if的转换,替换(replaceWith)时会抛出异常
|
|
752
|
+
// catch异常后,正常替换
|
|
402
753
|
}
|
|
754
|
+
p.remove();
|
|
403
755
|
}
|
|
404
756
|
});
|
|
757
|
+
if (t.isJSXEmptyExpression(value.expression)) {
|
|
758
|
+
(0, helper_1.printLog)("warning" /* processTypeEnum.WARNING */, 'value.expression', 'wxml.ts -> t.isJSXEmptyExpression(value.expression)');
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
405
761
|
const replacement = t.jSXExpressionContainer(t.callExpression(t.memberExpression(value.expression, t.identifier('map')), [
|
|
406
|
-
t.arrowFunctionExpression([t.identifier(item.value), t.identifier(index.value)], t.blockStatement([t.returnStatement(jsx.node)]))
|
|
762
|
+
t.arrowFunctionExpression([t.identifier(item.value), t.identifier(index.value)], t.blockStatement([t.returnStatement(jsx.node)])),
|
|
407
763
|
]));
|
|
408
764
|
const block = (0, utils_1.buildBlockElement)();
|
|
409
765
|
block.children = [replacement];
|
|
@@ -415,7 +771,7 @@ function transformLoop(name, attr, jsx, value) {
|
|
|
415
771
|
}
|
|
416
772
|
return {
|
|
417
773
|
item: item.value,
|
|
418
|
-
index: index.value
|
|
774
|
+
index: index.value,
|
|
419
775
|
};
|
|
420
776
|
}
|
|
421
777
|
}
|
|
@@ -423,13 +779,19 @@ function transformIf(name, attr, jsx, value) {
|
|
|
423
779
|
if (name !== exports.WX_IF) {
|
|
424
780
|
return;
|
|
425
781
|
}
|
|
426
|
-
if (jsx.node.openingElement.attributes.some(a => a.name.name === 'slot')) {
|
|
782
|
+
if (jsx.node.openingElement.attributes.some((a) => t.isJSXAttribute(a) && a.name.name === 'slot')) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
// 考虑到wx:if和wx:for的优先级,如果同时使用,先解析wx:for
|
|
786
|
+
if (jsx.node.openingElement.attributes.some((a) => t.isJSXAttribute(a) && (a.name.name === 'wx:for' || a.name.name === 'wx:for-items'))) {
|
|
427
787
|
return;
|
|
428
788
|
}
|
|
429
789
|
const conditions = [];
|
|
430
790
|
let siblings = [];
|
|
431
791
|
try {
|
|
432
|
-
siblings = jsx
|
|
792
|
+
siblings = jsx
|
|
793
|
+
.getAllNextSiblings()
|
|
794
|
+
.filter((s) => !(s.isJSXExpressionContainer() && t.isJSXEmptyExpression(s.get('expression'))));
|
|
433
795
|
}
|
|
434
796
|
catch (error) {
|
|
435
797
|
return;
|
|
@@ -443,7 +805,7 @@ function transformIf(name, attr, jsx, value) {
|
|
|
443
805
|
conditions.push({
|
|
444
806
|
condition: exports.WX_IF,
|
|
445
807
|
path: jsx,
|
|
446
|
-
tester: value
|
|
808
|
+
tester: value,
|
|
447
809
|
});
|
|
448
810
|
attr.remove();
|
|
449
811
|
for (let index = 0; index < siblings.length; index++) {
|
|
@@ -457,7 +819,7 @@ function transformIf(name, attr, jsx, value) {
|
|
|
457
819
|
conditions.push({
|
|
458
820
|
condition: currMatches.reg.input,
|
|
459
821
|
path: sibling,
|
|
460
|
-
tester: currMatches.tester
|
|
822
|
+
tester: currMatches.tester,
|
|
461
823
|
});
|
|
462
824
|
if (nextMatches === null) {
|
|
463
825
|
break;
|
|
@@ -468,11 +830,13 @@ function transformIf(name, attr, jsx, value) {
|
|
|
468
830
|
function handleConditions(conditions) {
|
|
469
831
|
if (conditions.length === 1) {
|
|
470
832
|
const ct = conditions[0];
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
833
|
+
if (!t.isJSXEmptyExpression(ct.tester.expression)) {
|
|
834
|
+
try {
|
|
835
|
+
ct.path.replaceWith(t.jSXExpressionContainer(t.logicalExpression('&&', ct.tester.expression, (0, lodash_1.cloneDeep)(ct.path.node))));
|
|
836
|
+
}
|
|
837
|
+
catch (error) {
|
|
838
|
+
//
|
|
839
|
+
}
|
|
476
840
|
}
|
|
477
841
|
}
|
|
478
842
|
if (conditions.length > 1) {
|
|
@@ -480,16 +844,20 @@ function handleConditions(conditions) {
|
|
|
480
844
|
const lastCon = conditions[lastLength];
|
|
481
845
|
let lastAlternate = (0, lodash_1.cloneDeep)(lastCon.path.node);
|
|
482
846
|
try {
|
|
483
|
-
if (lastCon.condition === exports.WX_ELSE_IF) {
|
|
847
|
+
if (lastCon.condition === exports.WX_ELSE_IF && !t.isJSXEmptyExpression(lastCon.tester.expression)) {
|
|
484
848
|
lastAlternate = t.logicalExpression('&&', lastCon.tester.expression, lastAlternate);
|
|
485
849
|
}
|
|
486
|
-
const node = conditions
|
|
487
|
-
.
|
|
488
|
-
|
|
850
|
+
const node = conditions.slice(0, lastLength).reduceRight((acc, condition) => {
|
|
851
|
+
if (t.isJSXEmptyExpression(condition.tester.expression)) {
|
|
852
|
+
(0, helper_1.printLog)("warning" /* processTypeEnum.WARNING */, 'condition.tester.expression', 't.isJSXEmptyExpression(condition.tester.expression)');
|
|
853
|
+
return null;
|
|
854
|
+
}
|
|
489
855
|
return t.conditionalExpression(condition.tester.expression, (0, lodash_1.cloneDeep)(condition.path.node), acc);
|
|
490
856
|
}, lastAlternate);
|
|
491
|
-
|
|
492
|
-
|
|
857
|
+
if (node != null) {
|
|
858
|
+
conditions[0].path.replaceWith(t.jSXExpressionContainer(node));
|
|
859
|
+
conditions.slice(1).forEach((c) => c.path.remove());
|
|
860
|
+
}
|
|
493
861
|
}
|
|
494
862
|
catch (error) {
|
|
495
863
|
console.error('wx:elif 的值需要用双括号 `{{}}` 包裹它的值');
|
|
@@ -503,9 +871,9 @@ function findWXIfProps(jsx) {
|
|
|
503
871
|
jsx
|
|
504
872
|
.get('openingElement')
|
|
505
873
|
.get('attributes')
|
|
506
|
-
.some(path => {
|
|
874
|
+
.some((path) => {
|
|
507
875
|
const attr = path.node;
|
|
508
|
-
if (t.isJSXIdentifier(attr.name)) {
|
|
876
|
+
if (t.isJSXIdentifier(attr.name) && attr != null) {
|
|
509
877
|
const name = attr.name.name;
|
|
510
878
|
if (name === exports.WX_IF) {
|
|
511
879
|
return true;
|
|
@@ -515,7 +883,7 @@ function findWXIfProps(jsx) {
|
|
|
515
883
|
path.remove();
|
|
516
884
|
matches = {
|
|
517
885
|
reg: match,
|
|
518
|
-
tester: attr.value
|
|
886
|
+
tester: attr.value,
|
|
519
887
|
};
|
|
520
888
|
return true;
|
|
521
889
|
}
|
|
@@ -530,10 +898,12 @@ function parseNode(node, tagName) {
|
|
|
530
898
|
}
|
|
531
899
|
else if (node.type === NodeType.Comment) {
|
|
532
900
|
const emptyStatement = t.jSXEmptyExpression();
|
|
533
|
-
emptyStatement.innerComments = [
|
|
901
|
+
emptyStatement.innerComments = [
|
|
902
|
+
{
|
|
534
903
|
type: 'CommentBlock',
|
|
535
|
-
value: ' ' + node.content + ' '
|
|
536
|
-
}
|
|
904
|
+
value: ' ' + node.content + ' ',
|
|
905
|
+
},
|
|
906
|
+
];
|
|
537
907
|
return t.jSXExpressionContainer(emptyStatement);
|
|
538
908
|
}
|
|
539
909
|
return parseElement(node);
|
|
@@ -546,7 +916,7 @@ function parseElement(element) {
|
|
|
546
916
|
let attributes = element.attributes;
|
|
547
917
|
if (tagName.name === 'Template') {
|
|
548
918
|
let isSpread = false;
|
|
549
|
-
attributes = attributes.map(attr => {
|
|
919
|
+
attributes = attributes.map((attr) => {
|
|
550
920
|
if (attr.key === 'data') {
|
|
551
921
|
const value = attr.value || '';
|
|
552
922
|
const content = parseContent(value);
|
|
@@ -562,7 +932,7 @@ function parseElement(element) {
|
|
|
562
932
|
// (...a) => {{a}}
|
|
563
933
|
attr.value = `{{${str.slice(4, strLastIndex)}}}`;
|
|
564
934
|
}
|
|
565
|
-
else if (/^\(([A-Za-z]+)\)$/.test(str)) {
|
|
935
|
+
else if (/^\(([A-Za-z,]+)\)$/.test(str)) {
|
|
566
936
|
// (a) => {{a:a}}
|
|
567
937
|
attr.value = `{{${str.replace(/^\(([A-Za-z]+)\)$/, '$1:$1')}}}`;
|
|
568
938
|
}
|
|
@@ -581,18 +951,20 @@ function parseElement(element) {
|
|
|
581
951
|
if (isSpread) {
|
|
582
952
|
attributes.push({
|
|
583
953
|
key: 'spread',
|
|
584
|
-
value: null
|
|
954
|
+
value: null,
|
|
585
955
|
});
|
|
586
956
|
}
|
|
587
957
|
}
|
|
588
958
|
return t.jSXElement(t.jSXOpeningElement(tagName, attributes.map(parseAttribute)), t.jSXClosingElement(tagName), removEmptyTextAndComment(element.children).map((el) => parseNode(el, element.tagName)), false);
|
|
589
959
|
}
|
|
590
960
|
function removEmptyTextAndComment(nodes) {
|
|
591
|
-
return nodes
|
|
592
|
-
|
|
961
|
+
return nodes
|
|
962
|
+
.filter((node) => {
|
|
963
|
+
return (node.type === NodeType.Element ||
|
|
593
964
|
(node.type === NodeType.Text && node.content.trim().length !== 0) ||
|
|
594
|
-
node.type === NodeType.Comment;
|
|
595
|
-
})
|
|
965
|
+
node.type === NodeType.Comment);
|
|
966
|
+
})
|
|
967
|
+
.filter((node, index) => !(index === 0 && node.type === NodeType.Comment));
|
|
596
968
|
}
|
|
597
969
|
exports.removEmptyTextAndComment = removEmptyTextAndComment;
|
|
598
970
|
function parseText(node, tagName) {
|
|
@@ -606,6 +978,7 @@ function parseText(node, tagName) {
|
|
|
606
978
|
}
|
|
607
979
|
return t.jSXExpressionContainer((0, utils_1.buildTemplate)(content));
|
|
608
980
|
}
|
|
981
|
+
// 匹配{{content}}
|
|
609
982
|
const handlebarsRE = /\{\{((?:.|\n)+?)\}\}/g;
|
|
610
983
|
function singleQuote(s) {
|
|
611
984
|
return `'${s}'`;
|
|
@@ -615,7 +988,7 @@ function parseContent(content, single = false) {
|
|
|
615
988
|
if (!handlebarsRE.test(content)) {
|
|
616
989
|
return {
|
|
617
990
|
type: 'raw',
|
|
618
|
-
content
|
|
991
|
+
content,
|
|
619
992
|
};
|
|
620
993
|
}
|
|
621
994
|
const tokens = [];
|
|
@@ -641,22 +1014,81 @@ function parseContent(content, single = false) {
|
|
|
641
1014
|
}
|
|
642
1015
|
return {
|
|
643
1016
|
type: 'expression',
|
|
644
|
-
content: tokens.join('+')
|
|
1017
|
+
content: tokens.join('+'),
|
|
645
1018
|
};
|
|
646
1019
|
}
|
|
647
1020
|
exports.parseContent = parseContent;
|
|
1021
|
+
/**
|
|
1022
|
+
* 判断 style 中的属性是否都是 attrName: attrValue 格式
|
|
1023
|
+
*
|
|
1024
|
+
* @param styleAttrsMap
|
|
1025
|
+
*/
|
|
1026
|
+
function isAllKeyValueFormat(styleAttrsMap) {
|
|
1027
|
+
// 匹配 attrName: attrValue 格式
|
|
1028
|
+
const isKeyValueFormat = /^(([A-Za-z-]+)\s*):(\s*).*/;
|
|
1029
|
+
const filterStyleAttrs = styleAttrsMap.filter((attr) => attr.trim() !== '');
|
|
1030
|
+
const isStringAttr = filterStyleAttrs.every((attr) => isKeyValueFormat.test(attr.trim()));
|
|
1031
|
+
return isStringAttr;
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* 解析内联style属性
|
|
1035
|
+
*
|
|
1036
|
+
* @param key 内联属性的类型
|
|
1037
|
+
* @param value 内联属性的值
|
|
1038
|
+
* @returns
|
|
1039
|
+
*/
|
|
1040
|
+
function parseStyle(key, value) {
|
|
1041
|
+
const styleAttrs = value.trim().split(';');
|
|
1042
|
+
// 针对attrName: attrValue 格式做转换处理, 其他类型采用'+'连接符
|
|
1043
|
+
if (isAllKeyValueFormat(styleAttrs)) {
|
|
1044
|
+
const attrKeyValueMap = [];
|
|
1045
|
+
parseStyleAttrs(styleAttrs, attrKeyValueMap);
|
|
1046
|
+
convertStyleAttrs(attrKeyValueMap);
|
|
1047
|
+
const objectLiteral = t.objectExpression(attrKeyValueMap.map((attr) => t.objectProperty(t.identifier(attr.attrName), attr.value)));
|
|
1048
|
+
return t.jSXAttribute(t.jSXIdentifier(key), t.jsxExpressionContainer(objectLiteral));
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
return parseContent(value);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
exports.parseStyle = parseStyle;
|
|
648
1055
|
function parseAttribute(attr) {
|
|
649
1056
|
let { key, value } = attr;
|
|
650
1057
|
let jsxValue = null;
|
|
1058
|
+
let type = '';
|
|
1059
|
+
let content = '';
|
|
651
1060
|
if (value) {
|
|
652
1061
|
if (key === 'class' && value.startsWith('[') && value.endsWith(']')) {
|
|
653
1062
|
value = value.slice(1, value.length - 1).replace(',', '');
|
|
654
1063
|
// eslint-disable-next-line no-console
|
|
655
1064
|
console.log((0, utils_1.codeFrameError)(attr, 'Taro/React 不支持 class 传入数组,此写法可能无法得到正确的 class'));
|
|
656
1065
|
}
|
|
657
|
-
|
|
1066
|
+
value = convertStyleUnit(value);
|
|
1067
|
+
// 判断属性是否为style属性
|
|
1068
|
+
if (key === 'style' && value) {
|
|
1069
|
+
try {
|
|
1070
|
+
const styleParseReslut = parseStyle(key, value);
|
|
1071
|
+
if (t.isJSXAttribute(styleParseReslut)) {
|
|
1072
|
+
return styleParseReslut;
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
content = styleParseReslut.content;
|
|
1076
|
+
type = styleParseReslut.type;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
catch (error) {
|
|
1080
|
+
const errorMsg = `当前属性: style="${value}" 解析失败,失败原因:${error}`;
|
|
1081
|
+
(0, helper_1.printLog)("error" /* processTypeEnum.ERROR */, errorMsg);
|
|
1082
|
+
throw new Error(errorMsg);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
const parseContentResult = parseContent(value);
|
|
1087
|
+
content = parseContentResult.content;
|
|
1088
|
+
type = parseContentResult.type;
|
|
1089
|
+
}
|
|
658
1090
|
if (type === 'raw') {
|
|
659
|
-
jsxValue = t.stringLiteral(content.replace(/"/g, '
|
|
1091
|
+
jsxValue = t.stringLiteral(content.replace(/"/g, "'"));
|
|
660
1092
|
}
|
|
661
1093
|
else {
|
|
662
1094
|
let expr;
|
|
@@ -674,8 +1106,10 @@ function parseAttribute(attr) {
|
|
|
674
1106
|
throw new Error(err);
|
|
675
1107
|
}
|
|
676
1108
|
}
|
|
677
|
-
else if (content.includes(':') ||
|
|
678
|
-
const file = (0,
|
|
1109
|
+
else if (content.includes(':') || content.includes('...')) {
|
|
1110
|
+
const file = (0, parser_1.parse)(`var a = ${attr.value.slice(1, attr.value.length - 1)}`, {
|
|
1111
|
+
plugins: ['objectRestSpread'],
|
|
1112
|
+
});
|
|
679
1113
|
expr = file.program.body[0].declarations[0].init;
|
|
680
1114
|
}
|
|
681
1115
|
else {
|
|
@@ -690,8 +1124,8 @@ function parseAttribute(attr) {
|
|
|
690
1124
|
jsxValue = t.jSXExpressionContainer(expr);
|
|
691
1125
|
}
|
|
692
1126
|
}
|
|
693
|
-
|
|
694
|
-
if (/^on[A-Z]/.test(jsxKey) &&
|
|
1127
|
+
let jsxKey = handleAttrKey(key);
|
|
1128
|
+
if (/^on[A-Z]/.test(jsxKey) && !/^catch/.test(key) && jsxValue && t.isStringLiteral(jsxValue)) {
|
|
695
1129
|
jsxValue = t.jSXExpressionContainer(t.memberExpression(t.thisExpression(), t.identifier(jsxValue.value)));
|
|
696
1130
|
}
|
|
697
1131
|
if (key.startsWith('catch') && value) {
|
|
@@ -700,15 +1134,20 @@ function parseAttribute(attr) {
|
|
|
700
1134
|
global_1.globals.hasCatchTrue = true;
|
|
701
1135
|
}
|
|
702
1136
|
else if (t.isStringLiteral(jsxValue)) {
|
|
703
|
-
jsxValue = t.jSXExpressionContainer(t.
|
|
1137
|
+
jsxValue = t.jSXExpressionContainer(t.memberExpression(t.thisExpression(), t.identifier(jsxValue.value)));
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
// 如果data-xxx自定义属性名xxx不是以-分隔的写法就要转成全小写属性名
|
|
1141
|
+
if (value && jsxKey.startsWith('data-')) {
|
|
1142
|
+
const realKey = jsxKey.replace(/^data-/, '');
|
|
1143
|
+
if (realKey.indexOf('-') === -1) {
|
|
1144
|
+
jsxKey = `data-${realKey.toLowerCase()}`;
|
|
704
1145
|
}
|
|
705
1146
|
}
|
|
706
1147
|
return t.jSXAttribute(t.jSXIdentifier(jsxKey), jsxValue);
|
|
707
1148
|
}
|
|
708
1149
|
function handleAttrKey(key) {
|
|
709
|
-
if (key.startsWith('wx:') ||
|
|
710
|
-
key.startsWith('wx-') ||
|
|
711
|
-
key.startsWith('data-')) {
|
|
1150
|
+
if (key.startsWith('wx:') || key.startsWith('wx-') || key.startsWith('data-')) {
|
|
712
1151
|
return key;
|
|
713
1152
|
}
|
|
714
1153
|
else if (key === 'class') {
|