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