@tarojs/taroize 3.8.0-canary.0 → 4.0.0-alpha.2

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/wxml.js CHANGED
@@ -1,10 +1,13 @@
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.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 babel_traverse_1 = require("babel-traverse");
6
- const t = require("babel-types");
7
- const babylon_1 = require("babylon");
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,183 @@ 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.wxTemplateCommand = [
35
- exports.WX_IF,
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
- const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) => {
48
+ // style 属性中属性名转小驼峰格式 并且将 {{}} 转为 ${}格式生成对应ast节点
49
+ function convertStyleAttrs(styleAttrsMap) {
50
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] 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.updateLogFileContent)(`INFO [taroize] 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
+ return match.replace(size, parseFloat(size) / 20 + '').replace(unit, 'rem');
102
+ })
103
+ .replace(/\s*-?([0-9.]+)(rpx)\b/gi, function (match, size, unit) {
104
+ if (Number(size) === 0) {
105
+ return match.replace(size, '0').replace(unit, 'rem');
106
+ }
107
+ return match.replace(size, parseFloat(size) / 40 + '').replace(unit, 'rem');
108
+ });
109
+ // 把 xx="...{{参数}}rpx/px"的尺寸单位都转为rem,比如"{{参数}}rpx" -> "{{参数/40}}rem"
110
+ tempValue = tempValue
111
+ .replace(/\{\{([^{}]*)\}\}(px)/gi, function (match, size, unit) {
112
+ // 判断{{}}是否包含加减乘除算式和三元表达式, 是的话得加括号
113
+ if (match.match(/[+\-*/?]/g)) {
114
+ return match.replace(size, '(' + size + ')/20').replace(unit, 'rem');
115
+ }
116
+ return match.replace(size, size + '/20').replace(unit, 'rem');
117
+ })
118
+ .replace(/\{\{([^{}]*)\}\}(rpx)/gi, function (match, size, unit) {
119
+ if (match.match(/[+\-*/?]/g)) {
120
+ return match.replace(size, '(' + size + ')/40').replace(unit, 'rem');
121
+ }
122
+ return match.replace(size, size + '/40').replace(unit, 'rem');
123
+ });
124
+ }
125
+ catch (error) {
126
+ (0, utils_1.createErrorCodeMsg)('WxmlUnitConversionError', `wxml内px/rpx单位转换失败: ${error}`, tempValue, global_1.globals.currentParseFile);
127
+ (0, helper_1.printLog)("error" /* processTypeEnum.ERROR */, `wxml内px/rpx单位转换失败: ${error}`);
128
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] convertStyleUnit - wxml内px/rpx单位转换异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
129
+ }
130
+ }
131
+ return tempValue;
132
+ }
133
+ exports.convertStyleUnit = convertStyleUnit;
134
+ /**
135
+ * 预解析,收集wxml所有的模板信息
136
+ *
137
+ * @param { any[] } templates wxml页面下的模板信息
138
+ * @returns Visitor
139
+ */
140
+ const createPreWxmlVistor = (templates) => {
141
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createPreWxmlVistor - 入参 ${(0, utils_1.getLineBreak)()}templates: ${templates} ${(0, utils_1.getLineBreak)()}`);
142
+ // const Applys = new Map<string, string[]>()
143
+ return {
144
+ JSXElement: {
145
+ enter(path) {
146
+ const openingElement = path.get('openingElement');
147
+ const jsxName = openingElement.get('name');
148
+ if (!jsxName.isJSXIdentifier()) {
149
+ return;
150
+ }
151
+ const tagName = jsxName.node.name;
152
+ if (tagName !== 'Template') {
153
+ return;
154
+ }
155
+ const templateInfo = (0, template_1.preParseTemplate)(path);
156
+ if (templateInfo) {
157
+ templates.set(templateInfo.name, {
158
+ funcs: templateInfo.funcs,
159
+ applyTemplates: templateInfo.applys,
160
+ });
161
+ }
162
+ },
163
+ },
164
+ };
165
+ };
166
+ exports.createPreWxmlVistor = createPreWxmlVistor;
167
+ /**
168
+ * 根据template中使用的wxs组装需要导入的wxs语句
169
+ * 如: import xxx from '../xxx.wxs.js'
170
+ *
171
+ * @param templateFileName template模版文件名
172
+ * @param usedWxses template中使用的变量是wxs模块的集合
173
+ * @param dirPath 当前解析文件的路径
174
+ * @returns 需要导入的wxs语句集合
175
+ */
176
+ function getWxsImports(templateFileName, usedWxses, dirPath) {
177
+ const templatePath = pathTool.join(global_1.globals.rootPath, 'imports', `${templateFileName}.js`);
178
+ const wxsImports = [];
179
+ for (const usedWxs of usedWxses) {
180
+ const wxsAbsPath = pathTool.resolve(dirPath, `${usedWxs.src}.js`);
181
+ const wxsRelPath = pathTool.relative(pathTool.dirname(templatePath), wxsAbsPath);
182
+ wxsImports.push((0, utils_1.buildImportStatement)((0, utils_1.normalizePath)(wxsRelPath), [], usedWxs.module));
183
+ }
184
+ return wxsImports;
185
+ }
186
+ exports.getWxsImports = getWxsImports;
187
+ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = [], templates) => {
188
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 入参 ${(0, utils_1.getLineBreak)()}dirPath: ${dirPath} ${(0, utils_1.getLineBreak)()}`);
52
189
  const jsxAttrVisitor = (path) => {
190
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 解析JSXAttribute ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
53
191
  const name = path.node.name;
54
- const jsx = path.findParent(p => p.isJSXElement());
192
+ const jsx = path.findParent((p) => p.isJSXElement());
55
193
  // 把 hidden 转换为 wxif
56
194
  if (name.name === 'hidden') {
57
195
  const value = path.get('value');
58
- if (t.isJSXExpressionContainer(value)) {
196
+ if (t.isJSXExpressionContainer(value) && !t.isJSXEmptyExpression(value.node.expression)) {
59
197
  const exclamation = t.unaryExpression('!', value.node.expression);
60
198
  path.set('value', t.jSXExpressionContainer(exclamation));
61
199
  path.set('name', t.jSXIdentifier(exports.WX_IF));
62
200
  }
63
201
  }
202
+ // 当设置图片mode="",则改为默认值(且taro不支持mode空值)
203
+ if (name.name === 'mode' && path.node.value === null) {
204
+ path.set('value', t.stringLiteral('scaleToFill'));
205
+ }
206
+ // 当设置 style 属性但未赋值则删除该属性
207
+ if (name.name === 'style' && !path.node.value) {
208
+ path.remove();
209
+ return;
210
+ }
64
211
  const valueCopy = (0, lodash_1.cloneDeep)(path.get('value').node);
212
+ if (typeof valueCopy === 'undefined' || t.isJSXFragment(valueCopy)) {
213
+ return;
214
+ }
65
215
  transformIf(name.name, path, jsx, valueCopy);
66
216
  const loopItem = transformLoop(name.name, path, jsx, valueCopy);
67
217
  if (loopItem) {
@@ -74,14 +224,31 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
74
224
  }
75
225
  };
76
226
  const renameJSXKey = (path) => {
227
+ var _a, _b, _c, _d;
228
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 解析JSXIdentifier ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
77
229
  const nodeName = path.node.name;
78
230
  if (path.parentPath.isJSXAttribute()) {
79
- if (nodeName === exports.WX_KEY) {
80
- path.replaceWith(t.jSXIdentifier('key'));
231
+ const cacheNode = (0, lodash_1.cloneDeep)(path.parentPath.parentPath.parent);
232
+ if (nodeName === exports.WX_SHOW) {
233
+ path.replaceWith(t.jSXIdentifier(exports.WX_IF)); // wx:show转换后不支持,不频繁切换的话wx:if可替代
234
+ const position = {
235
+ col: ((_a = cacheNode.position) === null || _a === void 0 ? void 0 : _a.start.column) || 0,
236
+ row: ((_b = cacheNode.position) === null || _b === void 0 ? void 0 : _b.start.line) || 0
237
+ };
238
+ (0, utils_1.createErrorCodeMsg)('uncompilableAttribute', `属性 ${nodeName}不能编译,会被替换为wx:if`, (0, utils_1.astToCode)(cacheNode) || '', global_1.globals.currentParseFile, position);
239
+ // eslint-disable-next-line no-console
240
+ console.log(`属性 ${nodeName}不能编译,会被替换为wx:if`);
241
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] createWxmlVistor - ${nodeName} 属性不能编译,会被替换为 wx:if ${(0, utils_1.getLineBreak)()}`);
81
242
  }
82
- if (nodeName.startsWith('wx:') && !exports.wxTemplateCommand.includes(nodeName)) {
243
+ else if (nodeName.startsWith('wx:') && !exports.wxTemplateCommand.includes(nodeName)) {
244
+ const position = {
245
+ col: ((_c = cacheNode.position) === null || _c === void 0 ? void 0 : _c.start.column) || 0,
246
+ row: ((_d = cacheNode.position) === null || _d === void 0 ? void 0 : _d.start.line) || 0
247
+ };
248
+ (0, utils_1.createErrorCodeMsg)('unknownScopeAttribute', `未知 wx 作用域属性: ${nodeName},该属性会被移除掉。`, (0, utils_1.astToCode)(cacheNode) || '', global_1.globals.currentParseFile, position);
83
249
  // eslint-disable-next-line no-console
84
250
  console.log(`未知 wx 作用域属性: ${nodeName},该属性会被移除掉。`);
251
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] createWxmlVistor - 未知 wx 作用域属性: ${nodeName},该属性会被移除掉 ${(0, utils_1.getLineBreak)()}`);
85
252
  path.parentPath.remove();
86
253
  }
87
254
  }
@@ -89,8 +256,25 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
89
256
  return {
90
257
  JSXAttribute: jsxAttrVisitor,
91
258
  JSXIdentifier: renameJSXKey,
259
+ Identifier: {
260
+ enter(path) {
261
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 解析Identifier ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
262
+ if (!path.isReferencedIdentifier()) {
263
+ return;
264
+ }
265
+ const jsxExprContainer = path.findParent((p) => p.isJSXExpressionContainer());
266
+ if (!jsxExprContainer || !jsxExprContainer.isJSXExpressionContainer()) {
267
+ return;
268
+ }
269
+ if ((0, utils_1.isValidVarName)(path.node.name)) {
270
+ refIds.add(path.node.name);
271
+ }
272
+ },
273
+ },
92
274
  JSXElement: {
93
275
  enter(path) {
276
+ var _a, _b, _c;
277
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 解析JSXElement ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
94
278
  const openingElement = path.get('openingElement');
95
279
  const jsxName = openingElement.get('name');
96
280
  const attrs = openingElement.get('attributes');
@@ -98,31 +282,22 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
98
282
  return;
99
283
  }
100
284
  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
285
  JSXAttribute: jsxAttrVisitor,
114
- JSXIdentifier: renameJSXKey
286
+ JSXIdentifier: renameJSXKey,
115
287
  });
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) {
288
+ 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'; });
289
+ if (slotAttr && t.isJSXAttribute(slotAttr.node)) {
118
290
  const slotValue = slotAttr.node.value;
291
+ let slotName = '';
119
292
  if (slotValue && t.isStringLiteral(slotValue)) {
120
- const slotName = slotValue.value;
121
- const parentComponent = path.findParent(p => p.isJSXElement() && t.isJSXIdentifier(p.node.openingElement.name) && !utils_1.DEFAULT_Component_SET.has(p.node.openingElement.name.name));
293
+ slotName = slotValue.value;
294
+ const parentComponent = path.findParent((p) => p.isJSXElement() &&
295
+ t.isJSXIdentifier(p.node.openingElement.name) &&
296
+ !utils_1.DEFAULT_Component_SET.has(p.node.openingElement.name.name));
122
297
  if (parentComponent && parentComponent.isJSXElement()) {
123
298
  slotAttr.remove();
124
299
  path.traverse({
125
- JSXAttribute: jsxAttrVisitor
300
+ JSXAttribute: jsxAttrVisitor,
126
301
  });
127
302
  const block = (0, utils_1.buildBlockElement)();
128
303
  block.children = [(0, lodash_1.cloneDeep)(path.node)];
@@ -131,19 +306,26 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
131
306
  }
132
307
  }
133
308
  else {
134
- throw (0, utils_1.codeFrameError)(slotValue, 'slot 的值必须是一个字符串');
309
+ // 当元素设置slot标签且值为空串时,移除slot属性
310
+ slotAttr.remove();
135
311
  }
136
312
  }
137
313
  const tagName = jsxName.node.name;
138
314
  if (tagName === 'Slot') {
139
- const nameAttr = attrs.find(a => a.node.name.name === 'name');
315
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - tagName: Slot ${(0, utils_1.getLineBreak)()}`);
316
+ const nameAttr = attrs.find((a) => t.isJSXAttribute(a.node) && a.node.name.name === 'name');
140
317
  let slotName = '';
141
- if (nameAttr) {
318
+ if (nameAttr && t.isJSXAttribute(nameAttr.node)) {
142
319
  if (nameAttr.node.value && t.isStringLiteral(nameAttr.node.value)) {
143
320
  slotName = nameAttr.node.value.value;
144
321
  }
145
322
  else {
146
- throw (0, utils_1.codeFrameError)(jsxName.node, 'slot 的值必须是一个字符串');
323
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] createWxmlVistor - slot 的值不是一个字符串 ${(0, utils_1.getLineBreak)()}`);
324
+ // const error = codeFrameError(jsxName.node, 'slot 的值必须是一个字符串')
325
+ // @ts-ignore
326
+ const { line, column } = ((_b = (_a = path.node) === null || _a === void 0 ? void 0 : _a.position) === null || _b === void 0 ? void 0 : _b.start) || { line: 0, column: 0 };
327
+ const position = { col: column, row: line };
328
+ throw new utils_1.IReportError('slot 的值必须是一个字符串', 'SlotValueTypeError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
147
329
  }
148
330
  }
149
331
  const children = t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('props')), t.identifier(slotName ? buildSlotName(slotName) : 'children'));
@@ -151,60 +333,137 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
151
333
  path.replaceWith(path.parentPath.isJSXElement() ? t.jSXExpressionContainer(children) : children);
152
334
  }
153
335
  catch (error) {
336
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] createWxmlVistor - Slot 节点替换异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
154
337
  //
155
338
  }
156
339
  }
157
340
  if (tagName === 'Wxs') {
158
- wxses.push(getWXS(attrs.map(a => a.node), path, imports));
341
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - tagName: Wxs ${(0, utils_1.getLineBreak)()}`);
342
+ wxses.push(getWXS(attrs.map((a) => a.node), path, imports));
159
343
  }
160
344
  if (tagName === 'Template') {
161
- // path.traverse({
162
- // JSXAttribute: jsxAttrVisitor
163
- // })
164
- const template = (0, template_1.parseTemplate)(path, dirPath);
345
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - tagName: Template ${(0, utils_1.getLineBreak)()}`);
346
+ const template = (0, template_1.parseTemplate)(path, dirPath, wxses);
165
347
  if (template) {
166
- const { ast: classDecl, name } = template;
167
- const taroComponentsImport = (0, utils_1.buildImportStatement)('@tarojs/components', [
168
- ...global_1.usedComponents
169
- ]);
348
+ let funcs = new Set();
349
+ const { ast: classDecl, name, tmplName, usedWxses } = template;
350
+ const wxsImports = getWxsImports(name, usedWxses, dirPath);
351
+ const taroComponentsImport = (0, utils_1.buildImportStatement)('@tarojs/components', [...global_1.usedComponents]);
170
352
  const taroImport = (0, utils_1.buildImportStatement)('@tarojs/taro', [], 'Taro');
171
353
  const reactImport = (0, utils_1.buildImportStatement)('react', [], 'React');
172
- // const withWeappImport = buildImportStatement(
173
- // '@tarojs/with-weapp',
174
- // [],
175
- // 'withWeapp'
176
- // )
354
+ // 引入 @tarojs/with-weapp
355
+ const withWeappImport = (0, utils_1.buildImportStatement)('@tarojs/with-weapp', [], 'withWeapp');
177
356
  const ast = t.file(t.program([]));
178
- ast.program.body.unshift(taroComponentsImport, reactImport, taroImport,
179
- // withWeappImport,
180
- t.exportDefaultDeclaration(classDecl));
357
+ ast.program.body.unshift(taroComponentsImport, reactImport, taroImport, withWeappImport, ...wxsImports, classDecl, t.exportDefaultDeclaration(t.identifier(name)));
181
358
  const usedTemplate = new Set();
182
- (0, babel_traverse_1.default)(ast, {
359
+ // funcs的值首先来源于预解析结果
360
+ if (templates) {
361
+ const applyFuncs = (_c = templates.get(name)) === null || _c === void 0 ? void 0 : _c.funcs;
362
+ if (applyFuncs) {
363
+ funcs = applyFuncs;
364
+ }
365
+ }
366
+ (0, traverse_1.default)(ast, {
183
367
  JSXIdentifier(path) {
368
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 解析JSXIdentifier ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
184
369
  const node = path.node;
185
370
  if (node.name.endsWith('Tmpl') && node.name.length > 4 && path.parentPath.isJSXOpeningElement()) {
186
371
  usedTemplate.add(node.name);
372
+ // 传递的方法有两处来源
373
+ const templateImport = imports.find((tmplImport) => tmplImport.name === `${node.name}`);
374
+ const templateInfo = templates === null || templates === void 0 ? void 0 : templates.get(node.name);
375
+ let templateFuncs = templateImport === null || templateImport === void 0 ? void 0 : templateImport.funcs;
376
+ if (templateInfo === null || templateInfo === void 0 ? void 0 : templateInfo.funcs) {
377
+ if (templateFuncs) {
378
+ templateFuncs = new Set([...templateFuncs, ...templateInfo.funcs]);
379
+ }
380
+ else {
381
+ templateFuncs = templateInfo.funcs;
382
+ }
383
+ }
384
+ if (templateFuncs && templateFuncs.size > 0) {
385
+ const openingElement = path.parentPath.node;
386
+ const attributes = openingElement.attributes;
387
+ templateFuncs.forEach((templateFunc) => {
388
+ const value = t.jsxExpressionContainer(t.identifier(templateFunc));
389
+ const name = t.jsxIdentifier(templateFunc);
390
+ // 传递的方法插入到Tmpl标签属性中
391
+ attributes.push(t.jsxAttribute(name, value));
392
+ if (!funcs.has(templateFunc)) {
393
+ funcs.add(templateFunc);
394
+ }
395
+ });
396
+ }
187
397
  }
188
- }
398
+ },
399
+ JSXAttribute(path) {
400
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 解析JSXAttribute ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
401
+ // 识别template使用到的处理事件的func
402
+ const node = path.node;
403
+ if (t.isJSXExpressionContainer(node.value) &&
404
+ t.isMemberExpression(node.value.expression) &&
405
+ t.isThisExpression(node.value.expression.object) &&
406
+ t.isIdentifier(node.value.expression.property)) {
407
+ const funcName = node.value.expression.property.name;
408
+ // func的调用形式 this.func --> func
409
+ path.replaceWith(t.jsxAttribute(node.name, t.jsxExpressionContainer(t.identifier(funcName))));
410
+ }
411
+ },
189
412
  });
190
- usedTemplate.forEach(componentName => {
413
+ (0, traverse_1.default)(ast, {
414
+ // 将使用到的处理事件的func写入到props
415
+ BlockStatement(path) {
416
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - 解析BlockStatement ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
417
+ if (funcs.size > 0) {
418
+ const body = path.node.body;
419
+ if (t.isVariableDeclaration(body[0])) {
420
+ // 如果已经定义了props
421
+ const declarator = body[0].declarations[0];
422
+ if (t.isObjectPattern(declarator.id)) {
423
+ const properties = declarator.id.properties;
424
+ funcs.forEach((func) => {
425
+ properties.push(t.objectProperty(t.identifier(func), t.identifier(func), false, true));
426
+ });
427
+ }
428
+ }
429
+ else {
430
+ // 没有定义,则插入 const {xxx} = this.props
431
+ const properties = [];
432
+ funcs.forEach((func) => {
433
+ properties.push(t.objectProperty(t.identifier(func), t.identifier(func), false, true));
434
+ });
435
+ const id = t.objectPattern(properties);
436
+ const init = t.memberExpression(t.thisExpression(), t.identifier('props'));
437
+ const declarator = t.variableDeclarator(id, init);
438
+ const declaration = t.variableDeclaration('const', [declarator]);
439
+ body.splice(0, 0, declaration);
440
+ }
441
+ }
442
+ path.stop();
443
+ },
444
+ });
445
+ usedTemplate.forEach((componentName) => {
191
446
  if (componentName !== classDecl.id.name) {
192
447
  ast.program.body.unshift((0, utils_1.buildImportStatement)(`./${componentName}`, [], componentName));
193
448
  }
194
449
  });
195
450
  imports.push({
196
451
  ast,
197
- name
452
+ name,
453
+ funcs,
454
+ tmplName,
198
455
  });
199
456
  }
200
457
  }
201
458
  if (tagName === 'Import') {
459
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - tagName: Import ${(0, utils_1.getLineBreak)()}`);
202
460
  const mods = (0, template_1.parseModule)(path, dirPath, 'import');
203
461
  if (mods) {
204
462
  imports.push(...mods);
205
463
  }
206
464
  }
207
465
  if (tagName === 'Include') {
466
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] createWxmlVistor - tagName: Include ${(0, utils_1.getLineBreak)()}`);
208
467
  (0, template_1.parseModule)(path, dirPath, 'include');
209
468
  }
210
469
  },
@@ -217,33 +476,85 @@ const createWxmlVistor = (loopIds, refIds, dirPath, wxses = [], imports = []) =>
217
476
  const children = path.node.children;
218
477
  if (children.length === 1) {
219
478
  const caller = children[0];
220
- if (t.isJSXExpressionContainer(caller) && t.isCallExpression(caller.expression) && !path.parentPath.isExpressionStatement()) {
479
+ if (t.isJSXExpressionContainer(caller) &&
480
+ t.isCallExpression(caller.expression) &&
481
+ !path.parentPath.isExpressionStatement()) {
221
482
  try {
222
483
  path.replaceWith(caller);
223
484
  }
224
485
  catch (error) {
486
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] createWxmlVistor - block 节点替换异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
225
487
  //
226
488
  }
227
489
  }
228
490
  }
229
- }
230
- }
491
+ },
492
+ },
231
493
  };
232
494
  };
233
495
  exports.createWxmlVistor = createWxmlVistor;
234
- function parseWXML(dirPath, wxml, parseImport) {
235
- let parseResult = (0, cache_1.getCacheWxml)(dirPath);
236
- if (parseResult) {
237
- return parseResult;
496
+ /**
497
+ * @description 根据模板信息中的直接调用,遍历获取完整的调用
498
+ * @param templates 模板信息
499
+ */
500
+ function templateBfs(templates) {
501
+ var _a;
502
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] templateBfs - 进入函数 ${(0, utils_1.getLineBreak)()}`);
503
+ const names = [];
504
+ const applys = new Map();
505
+ for (const key of templates.keys()) {
506
+ names.push(key);
507
+ const templateInfo = templates.get(key);
508
+ if (templateInfo) {
509
+ applys.set(key, templateInfo.applyTemplates);
510
+ }
511
+ }
512
+ for (const name of names) {
513
+ const templateInfo = templates.get(name);
514
+ if (!templateInfo || templateInfo.applyTemplates.size === 0) {
515
+ continue;
516
+ }
517
+ const visited = new Set();
518
+ const queue = [name];
519
+ while (queue.length > 0) {
520
+ const template = queue.shift();
521
+ if (visited.has(template)) {
522
+ continue;
523
+ }
524
+ visited.add(template);
525
+ const templateApplys = applys.get(template);
526
+ if (!templateApplys || templateApplys.size === 0) {
527
+ continue;
528
+ }
529
+ templateApplys.forEach((item) => {
530
+ if (names.includes(item)) {
531
+ queue.push(item);
532
+ }
533
+ });
534
+ }
535
+ visited.delete(name);
536
+ templateInfo.applyTemplates = visited;
537
+ for (const item of visited) {
538
+ const applyFuncs = (_a = templates.get(item)) === null || _a === void 0 ? void 0 : _a.funcs;
539
+ if (applyFuncs) {
540
+ const funcs = templateInfo.funcs;
541
+ templateInfo.funcs = new Set([...funcs, ...applyFuncs]);
542
+ }
543
+ }
544
+ templates.set(name, templateInfo);
238
545
  }
546
+ }
547
+ function parseWXML(dirPath, wxml, parseImport) {
548
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] parseWXML - 入参 ${(0, utils_1.getLineBreak)()}dirPath: ${dirPath} ${(0, utils_1.getLineBreak)()}parseImport: ${parseImport} ${(0, utils_1.getLineBreak)()}`);
239
549
  try {
240
550
  wxml = prettyPrint(wxml, {
241
551
  max_char: 0,
242
552
  indent_char: 0,
243
- unformatted: ['text', 'wxs']
553
+ unformatted: ['text', 'wxs'],
244
554
  });
245
555
  }
246
556
  catch (error) {
557
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] parseWXML - wxml代码格式化异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
247
558
  //
248
559
  }
249
560
  if (!parseImport) {
@@ -255,21 +566,35 @@ function parseWXML(dirPath, wxml, parseImport) {
255
566
  const imports = [];
256
567
  const refIds = new Set();
257
568
  const loopIds = new Set();
569
+ // 模板信息
570
+ const templates = new Map();
258
571
  if (!wxml) {
259
572
  return {
260
573
  wxses,
261
574
  imports,
262
575
  refIds,
263
- wxml: t.nullLiteral()
576
+ wxml: t.nullLiteral(),
264
577
  };
265
578
  }
266
- const nodes = removEmptyTextAndComment((0, himalaya_wxml_1.parse)(wxml.trim()));
267
- const ast = t.file(t.program([
268
- t.expressionStatement(parseNode(buildElement('block', nodes)))
269
- ], []));
270
- (0, babel_traverse_1.default)(ast, (0, exports.createWxmlVistor)(loopIds, refIds, dirPath, wxses, imports));
271
- refIds.forEach(id => {
272
- if (loopIds.has(id) || imports.filter(i => i.wxs).map(i => i.name).includes(id)) {
579
+ const nodes = removeEmptyTextAndComment((0, himalaya_wxml_1.parse)(wxml.trim(), Object.assign(Object.assign({}, himalaya_wxml_1.parseDefaults), { includePositions: true })));
580
+ const ast = t.file(t.program([t.expressionStatement(parseNode(buildElement('block', nodes)))], []));
581
+ // 确认当前解析页面是否已经解析过,如果解析过则直接获取缓存解析
582
+ let parseResult = (0, cache_1.getCacheWxml)(dirPath, hydrate(ast));
583
+ if (parseResult) {
584
+ return parseResult;
585
+ }
586
+ // 在解析wxml页面前,先进行预解析
587
+ // 当前预解析主要为了抽取页面下的模板信息
588
+ (0, traverse_1.default)(ast, (0, exports.createPreWxmlVistor)(templates));
589
+ // 获取template调用后,需要通过遍历,获取某个模板完整的调用关系
590
+ templateBfs(templates);
591
+ (0, traverse_1.default)(ast, (0, exports.createWxmlVistor)(loopIds, refIds, dirPath, wxses, imports, templates));
592
+ refIds.forEach((id) => {
593
+ if (loopIds.has(id) ||
594
+ imports
595
+ .filter((i) => i.wxs)
596
+ .map((i) => i.name)
597
+ .includes(id)) {
273
598
  refIds.delete(id);
274
599
  }
275
600
  });
@@ -277,13 +602,14 @@ function parseWXML(dirPath, wxml, parseImport) {
277
602
  wxses,
278
603
  imports,
279
604
  wxml: hydrate(ast),
280
- refIds
605
+ refIds,
281
606
  };
282
607
  (0, cache_1.saveCacheWxml)(dirPath, parseResult);
283
608
  return parseResult;
284
609
  }
285
610
  exports.parseWXML = parseWXML;
286
611
  function getWXS(attrs, path, imports) {
612
+ var _a, _b, _c, _d, _e, _f;
287
613
  let moduleName = null;
288
614
  let src = null;
289
615
  for (const attr of attrs) {
@@ -292,13 +618,16 @@ function getWXS(attrs, path, imports) {
292
618
  const attrValue = attr.value;
293
619
  let value = null;
294
620
  if (attrValue === null) {
295
- throw new Error('WXS 标签的属性值不得为空');
621
+ // @ts-ignore
622
+ const { line, column } = ((_b = (_a = path.node) === null || _a === void 0 ? void 0 : _a.position) === null || _b === void 0 ? void 0 : _b.start) || { line: 0, column: 0 };
623
+ const position = { col: column, row: line };
624
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] getWXS - wxs 标签的属性值为空 ${(0, utils_1.getLineBreak)()}`);
625
+ throw new utils_1.IReportError('wxs 标签的属性值不得为空', 'WxsTagAttributeEmptyError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
296
626
  }
297
627
  if (t.isStringLiteral(attrValue)) {
298
628
  value = attrValue.value;
299
629
  }
300
- else if (t.isJSXExpressionContainer(attrValue) &&
301
- t.isStringLiteral(attrValue.expression)) {
630
+ else if (t.isJSXExpressionContainer(attrValue) && t.isStringLiteral(attrValue.expression)) {
302
631
  value = attrValue.expression.value;
303
632
  }
304
633
  if (attrName === 'module') {
@@ -310,32 +639,116 @@ function getWXS(attrs, path, imports) {
310
639
  }
311
640
  }
312
641
  if (!src) {
313
- const { children: [script] } = path.node;
642
+ const { children: [script], } = path.node;
314
643
  if (!t.isJSXText(script)) {
315
- throw new Error('wxs 如果没有 src 属性,标签内部必须有 wxs 代码。');
644
+ // @ts-ignore
645
+ const { line, column } = ((_d = (_c = path.node) === null || _c === void 0 ? void 0 : _c.position) === null || _d === void 0 ? void 0 : _d.start) || { line: 0, column: 0 };
646
+ const position = { col: column, row: line };
647
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] getWXS - wxs 没有 src 属性且标签内部没有 wxs 代码 ${(0, utils_1.getLineBreak)()}`);
648
+ throw new utils_1.IReportError('wxs 如果没有 src 属性,标签内部必须有 wxs 代码。', 'WxsTagCodeMissingError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
316
649
  }
317
650
  src = './wxs__' + moduleName;
318
651
  const ast = (0, utils_1.parseCode)(script.value);
319
- (0, babel_traverse_1.default)(ast, {
652
+ (0, traverse_1.default)(ast, {
320
653
  CallExpression(path) {
654
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
655
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] getWXS - 解析CallExpression ${(0, utils_1.getLineBreak)()}${path} ${(0, utils_1.getLineBreak)()}`);
656
+ // wxs标签中getRegExp转换为new RegExp
321
657
  if (t.isIdentifier(path.node.callee, { name: 'getRegExp' })) {
322
- console.warn((0, utils_1.codeFrameError)(path.node, '请使用 JavaScript 标准正则表达式把这个 getRegExp 函数重构。'));
658
+ // 根据正则表达式是否定义了正则匹配修饰符,有则不变,没有就用默认
659
+ if (path.node.arguments.length > 1) {
660
+ const regex = path.node.arguments[0];
661
+ const modifier = path.node.arguments[1];
662
+ if (t.isStringLiteral(regex) && t.isStringLiteral(modifier)) {
663
+ const regexStr = (_a = regex.extra) === null || _a === void 0 ? void 0 : _a.raw;
664
+ const regexModifier = (_b = modifier.extra) === null || _b === void 0 ? void 0 : _b.rawValue;
665
+ const regexWithoutQuotes = regexStr.replace(/^['"](.*)['"]$/, '$1');
666
+ const newExpr = t.newExpression(t.identifier('RegExp'), [
667
+ t.stringLiteral(regexWithoutQuotes),
668
+ t.stringLiteral(regexModifier),
669
+ ]);
670
+ path.replaceWith(newExpr);
671
+ }
672
+ else if (t.isIdentifier(regex) || t.isIdentifier(modifier)) {
673
+ // @ts-ignore
674
+ const { line, column } = ((_d = (_c = path.node) === null || _c === void 0 ? void 0 : _c.position) === null || _d === void 0 ? void 0 : _d.start) || { line: 0, column: 0 };
675
+ const position = { col: column, row: line };
676
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] getWXS - getRegExp 函数暂不支持传入变量类型的参数 ${(0, utils_1.getLineBreak)()}`);
677
+ throw new utils_1.IReportError('getRegExp 函数暂不支持传入变量类型的参数', 'GetRegExpVariableTypeError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
678
+ }
679
+ else {
680
+ // @ts-ignore
681
+ const { line, column } = ((_f = (_e = path.node) === null || _e === void 0 ? void 0 : _e.position) === null || _f === void 0 ? void 0 : _f.start) || { line: 0, column: 0 };
682
+ const position = { col: column, row: line };
683
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] getWXS - getRegExp 函数暂不支持传入非字符串类型的参数 ${(0, utils_1.getLineBreak)()}`);
684
+ throw new utils_1.IReportError('getRegExp 函数暂不支持传入非字符串类型的参数', 'GetRegExpParameterTypeError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
685
+ }
686
+ }
687
+ else if (path.node.arguments.length === 1) {
688
+ const regex = path.node.arguments[0];
689
+ if (t.isStringLiteral(regex)) {
690
+ const regexStr = (_g = regex.extra) === null || _g === void 0 ? void 0 : _g.raw;
691
+ const regexWithoutQuotes = regexStr.replace(/^['"](.*)['"]$/, '$1');
692
+ const newExpr = t.newExpression(t.identifier('RegExp'), [t.stringLiteral(regexWithoutQuotes)]);
693
+ path.replaceWith(newExpr);
694
+ }
695
+ else if (t.isIdentifier(regex)) {
696
+ // @ts-ignore
697
+ const { line, column } = ((_j = (_h = path.node) === null || _h === void 0 ? void 0 : _h.position) === null || _j === void 0 ? void 0 : _j.start) || { line: 0, column: 0 };
698
+ const position = { col: column, row: line };
699
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] getWXS - getRegExp 函数暂不支持传入变量类型的参数 ${(0, utils_1.getLineBreak)()}`);
700
+ throw new utils_1.IReportError('getRegExp 函数暂不支持传入变量类型的参数', 'GetRegExpVariableTypeError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
701
+ }
702
+ else {
703
+ // @ts-ignore
704
+ const { line, column } = ((_l = (_k = path.node) === null || _k === void 0 ? void 0 : _k.position) === null || _l === void 0 ? void 0 : _l.start) || { line: 0, column: 0 };
705
+ const position = { col: column, row: line };
706
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] getWXS - getRegExp 函数暂不支持传入非字符串类型的参数 ${(0, utils_1.getLineBreak)()}`);
707
+ throw new utils_1.IReportError('getRegExp 函数暂不支持传入非字符串类型的参数', 'GetRegExpParameterTypeError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
708
+ }
709
+ }
710
+ else {
711
+ const newExpr = t.newExpression(t.identifier('RegExp'), []);
712
+ path.replaceWith(newExpr);
713
+ }
323
714
  }
324
- }
715
+ // wxs标签中getDate()转换为new Date()
716
+ if (t.isIdentifier(path.node.callee, { name: 'getDate' })) {
717
+ let argument = [];
718
+ let newDate;
719
+ const date = path.node.arguments[0];
720
+ if (t.isStringLiteral(date)) {
721
+ argument = path.node.arguments.map((item) => { var _a; return t.stringLiteral((_a = item.extra) === null || _a === void 0 ? void 0 : _a.rawValue); });
722
+ newDate = t.newExpression(t.identifier('Date'), [...argument]);
723
+ }
724
+ else if (t.isNumericLiteral(date)) {
725
+ argument = path.node.arguments.map((item) => { var _a; return t.numericLiteral((_a = item.extra) === null || _a === void 0 ? void 0 : _a.rawValue); });
726
+ newDate = t.newExpression(t.identifier('Date'), [...argument]);
727
+ }
728
+ else {
729
+ newDate = t.newExpression(t.identifier('Date'), []);
730
+ }
731
+ path.replaceWith(newDate);
732
+ }
733
+ },
325
734
  });
326
735
  imports.push({
327
736
  ast,
328
737
  name: moduleName,
329
- wxs: true
738
+ wxs: true,
330
739
  });
331
740
  }
332
741
  if (!moduleName || !src) {
333
- throw new Error('一个 WXS 需要同时存在两个属性:`wxs`, `src`');
742
+ // @ts-ignore
743
+ const { line, column } = ((_f = (_e = path.node) === null || _e === void 0 ? void 0 : _e.position) === null || _f === void 0 ? void 0 : _f.start) || { line: 0, column: 0 };
744
+ const position = { col: column, row: line };
745
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] getWXS - wxs 未同时存在 wxs、src 两个属性 ${(0, utils_1.getLineBreak)()}`);
746
+ throw new utils_1.IReportError('一个 wxs 需要同时存在两个属性:`module`, `src`', 'WxsTagAttributesMissingError', 'WXML_FILE', (0, utils_1.astToCode)(path.node) || '', position);
334
747
  }
335
748
  path.remove();
336
749
  return {
337
750
  module: moduleName,
338
- src
751
+ src,
339
752
  };
340
753
  }
341
754
  function hydrate(file) {
@@ -344,9 +757,7 @@ function hydrate(file) {
344
757
  const jsx = ast.expression;
345
758
  if (jsx.children.length === 1) {
346
759
  const children = jsx.children[0];
347
- return t.isJSXExpressionContainer(children)
348
- ? children.expression
349
- : children;
760
+ return t.isJSXExpressionContainer(children) ? children.expression : children;
350
761
  }
351
762
  else {
352
763
  return jsx;
@@ -354,16 +765,21 @@ function hydrate(file) {
354
765
  }
355
766
  }
356
767
  function transformLoop(name, attr, jsx, value) {
768
+ var _a, _b;
357
769
  const jsxElement = jsx.get('openingElement');
358
770
  if (!jsxElement.node) {
359
771
  return;
360
772
  }
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);
773
+ const attrs = jsxElement.get('attributes').map((a) => a.node);
774
+ const wxForItem = attrs.find((a) => t.isJSXAttribute(a) && a.name.name === exports.WX_FOR_ITEM);
775
+ const hasSinglewxForItem = wxForItem && t.isJSXAttribute(wxForItem) && wxForItem.value && t.isJSXExpressionContainer(wxForItem.value);
364
776
  if (hasSinglewxForItem || name === exports.WX_FOR || name === 'wx:for-items') {
365
777
  if (!value || !t.isJSXExpressionContainer(value)) {
366
- throw new Error('wx:for 的值必须使用 "{{}}" 包裹');
778
+ // @ts-ignore
779
+ const { line, column } = ((_b = (_a = jsx.node) === null || _a === void 0 ? void 0 : _a.position) === null || _b === void 0 ? void 0 : _b.start) || { line: 0, column: 0 };
780
+ const position = { col: column, row: line };
781
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] transformLoop - wx:for 的值未用 "{{}}" 包裹 ${(0, utils_1.getLineBreak)()}`);
782
+ throw new utils_1.IReportError('wx:for 的值必须使用 "{{}}" 包裹', 'WxForValueFormatError', 'WXML_FILE', (0, utils_1.astToCode)(jsx.node) || '', position);
367
783
  }
368
784
  attr.remove();
369
785
  let item = t.stringLiteral('item');
@@ -371,18 +787,27 @@ function transformLoop(name, attr, jsx, value) {
371
787
  jsx
372
788
  .get('openingElement')
373
789
  .get('attributes')
374
- .forEach(p => {
790
+ .forEach((p) => {
791
+ var _a, _b, _c, _d;
375
792
  const node = p.node;
376
793
  if (node.name.name === exports.WX_FOR_ITEM) {
377
794
  if (!node.value || !t.isStringLiteral(node.value)) {
378
- throw new Error(exports.WX_FOR_ITEM + ' 的值必须是一个字符串');
795
+ // @ts-ignore
796
+ const { line, column } = ((_b = (_a = jsx.node) === null || _a === void 0 ? void 0 : _a.position) === null || _b === void 0 ? void 0 : _b.start) || { line: 0, column: 0 };
797
+ const position = { col: column, row: line };
798
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] transformLoop - ${exports.WX_FOR_ITEM} 的值不是一个字符串 ${(0, utils_1.getLineBreak)()}`);
799
+ throw new utils_1.IReportError(exports.WX_FOR_ITEM + ' 的值必须是一个字符串', 'WxForItemValueError', 'WXML_FILE', (0, utils_1.astToCode)(jsx.node) || '', position);
379
800
  }
380
801
  item = node.value;
381
802
  p.remove();
382
803
  }
383
804
  if (node.name.name === exports.WX_FOR_INDEX) {
384
805
  if (!node.value || !t.isStringLiteral(node.value)) {
385
- throw new Error(exports.WX_FOR_INDEX + ' 的值必须是一个字符串');
806
+ // @ts-ignore
807
+ const { line, column } = ((_d = (_c = jsx.node) === null || _c === void 0 ? void 0 : _c.position) === null || _d === void 0 ? void 0 : _d.start) || { line: 0, column: 0 };
808
+ const position = { col: column, row: line };
809
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] transformLoop - ${exports.WX_FOR_INDEX} 的值不是一个字符串 ${(0, utils_1.getLineBreak)()}`);
810
+ throw new utils_1.IReportError(exports.WX_FOR_INDEX + ' 的值必须是一个字符串', 'WxForIndexValueError', 'WXML_FILE', (0, utils_1.astToCode)(jsx.node) || '', position);
386
811
  }
387
812
  index = node.value;
388
813
  p.remove();
@@ -391,19 +816,50 @@ function transformLoop(name, attr, jsx, value) {
391
816
  jsx
392
817
  .get('openingElement')
393
818
  .get('attributes')
394
- .forEach(p => {
819
+ .forEach((p) => {
395
820
  const node = p.node;
396
- if (node.name.name === exports.WX_KEY && t.isStringLiteral(node.value)) {
397
- if (node.value.value === '*this') {
398
- node.value = t.jSXExpressionContainer(t.identifier(item.value));
821
+ if (node.name.name === exports.WX_KEY) {
822
+ node.name = t.jSXIdentifier('key');
823
+ if (t.isStringLiteral(node.value)) {
824
+ if (node.value.value === '*this') {
825
+ node.value = t.jSXExpressionContainer(t.identifier(item.value));
826
+ }
827
+ else if (node.value.value === 'index') {
828
+ // index表示item在数组里的下标, 并不是item的某个property, 单独抽出来处理
829
+ node.value = t.jSXExpressionContainer(t.identifier(node.value.value));
830
+ }
831
+ else {
832
+ node.value = t.jSXExpressionContainer(t.memberExpression(t.identifier(item.value), t.identifier(node.value.value)));
833
+ }
399
834
  }
400
- else {
401
- node.value = t.jSXExpressionContainer(t.memberExpression(t.identifier(item.value), t.identifier(node.value.value)));
835
+ }
836
+ });
837
+ jsx
838
+ .get('openingElement')
839
+ .get('attributes')
840
+ .forEach((p) => {
841
+ const node = p.node;
842
+ if (node.name.name === exports.WX_IF) {
843
+ // 如果同时使用了 wx:if,分离
844
+ const ifBlock = (0, utils_1.buildBlockElement)();
845
+ ifBlock.children = [(0, lodash_1.cloneDeep)(jsx.node)];
846
+ try {
847
+ jsx.replaceWith(ifBlock);
402
848
  }
849
+ catch (error) {
850
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] transformLoop - wx:if和wx:for合用时父组件使用wx:if导致使用replaceWith异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
851
+ // jsx外层是wx:if的转换,替换(replaceWith)时会抛出异常
852
+ // catch异常后,正常替换
853
+ }
854
+ p.remove();
403
855
  }
404
856
  });
857
+ if (t.isJSXEmptyExpression(value.expression)) {
858
+ (0, helper_1.printLog)("warning" /* processTypeEnum.WARNING */, 'value.expression', 'wxml.ts -> t.isJSXEmptyExpression(value.expression)');
859
+ return;
860
+ }
405
861
  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)]))
862
+ t.arrowFunctionExpression([t.identifier(item.value), t.identifier(index.value)], t.blockStatement([t.returnStatement(jsx.node)])),
407
863
  ]));
408
864
  const block = (0, utils_1.buildBlockElement)();
409
865
  block.children = [replacement];
@@ -411,31 +867,47 @@ function transformLoop(name, attr, jsx, value) {
411
867
  jsx.replaceWith(block);
412
868
  }
413
869
  catch (error) {
870
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] transformLoop - 节点替换异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
414
871
  //
415
872
  }
416
873
  return {
417
874
  item: item.value,
418
- index: index.value
875
+ index: index.value,
419
876
  };
420
877
  }
421
878
  }
422
879
  function transformIf(name, attr, jsx, value) {
880
+ var _a, _b;
423
881
  if (name !== exports.WX_IF) {
424
882
  return;
425
883
  }
426
- if (jsx.node.openingElement.attributes.some(a => a.name.name === 'slot')) {
884
+ if (jsx.node.openingElement.attributes.some((a) => t.isJSXAttribute(a) && a.name.name === 'slot')) {
885
+ return;
886
+ }
887
+ // 考虑到wx:if和wx:for的优先级,如果同时使用,先解析wx:for
888
+ if (jsx.node.openingElement.attributes.some((a) => t.isJSXAttribute(a) && (a.name.name === 'wx:for' || a.name.name === 'wx:for-items'))) {
427
889
  return;
428
890
  }
429
891
  const conditions = [];
430
892
  let siblings = [];
431
893
  try {
432
- siblings = jsx.getAllNextSiblings().filter(s => !(s.isJSXExpressionContainer() && s.get('expression').isJSXEmptyExpression()));
894
+ siblings = jsx
895
+ .getAllNextSiblings()
896
+ .filter((s) => !(s.isJSXExpressionContainer() && t.isJSXEmptyExpression(s.get('expression'))));
433
897
  }
434
898
  catch (error) {
899
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] transformIf - 节点过滤异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
435
900
  return;
436
901
  }
437
902
  if (value === null || !t.isJSXExpressionContainer(value)) {
903
+ const cacheNode = (0, lodash_1.cloneDeep)(attr.parentPath.parent);
904
+ const position = {
905
+ col: ((_a = cacheNode.position) === null || _a === void 0 ? void 0 : _a.start.column) || 0,
906
+ row: ((_b = cacheNode.position) === null || _b === void 0 ? void 0 : _b.start.line) || 0,
907
+ };
908
+ (0, utils_1.createErrorCodeMsg)('wxIfValueFormatError', 'wx:if 的值需要用双括号 `{{}}` 包裹它的值', (0, utils_1.astToCode)(cacheNode) || '', global_1.globals.currentParseFile, position);
438
909
  console.error('wx:if 的值需要用双括号 `{{}}` 包裹它的值');
910
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] transformIf - wx:if 的值需要用双括号 {{}} 包裹它的值 ${(0, utils_1.getLineBreak)()}`);
439
911
  if (value && t.isStringLiteral(value)) {
440
912
  value = t.jSXExpressionContainer((0, utils_1.buildTemplate)(value.value));
441
913
  }
@@ -443,11 +915,13 @@ function transformIf(name, attr, jsx, value) {
443
915
  conditions.push({
444
916
  condition: exports.WX_IF,
445
917
  path: jsx,
446
- tester: value
918
+ tester: value,
919
+ cachePath: (0, lodash_1.cloneDeep)(jsx)
447
920
  });
448
921
  attr.remove();
449
922
  for (let index = 0; index < siblings.length; index++) {
450
923
  const sibling = siblings[index];
924
+ const cacheSibling = (0, lodash_1.cloneDeep)(sibling);
451
925
  const next = (0, lodash_1.cloneDeep)(siblings[index + 1]);
452
926
  const currMatches = findWXIfProps(sibling);
453
927
  const nextMatches = findWXIfProps(next);
@@ -457,7 +931,8 @@ function transformIf(name, attr, jsx, value) {
457
931
  conditions.push({
458
932
  condition: currMatches.reg.input,
459
933
  path: sibling,
460
- tester: currMatches.tester
934
+ tester: currMatches.tester,
935
+ cachePath: cacheSibling
461
936
  });
462
937
  if (nextMatches === null) {
463
938
  break;
@@ -466,33 +941,48 @@ function transformIf(name, attr, jsx, value) {
466
941
  handleConditions(conditions);
467
942
  }
468
943
  function handleConditions(conditions) {
944
+ var _a, _b;
469
945
  if (conditions.length === 1) {
470
946
  const ct = conditions[0];
471
- try {
472
- ct.path.replaceWith(t.jSXExpressionContainer(t.logicalExpression('&&', ct.tester.expression, (0, lodash_1.cloneDeep)(ct.path.node))));
473
- }
474
- catch (error) {
475
- //
947
+ if (!t.isJSXEmptyExpression(ct.tester.expression)) {
948
+ try {
949
+ ct.path.replaceWith(t.jSXExpressionContainer(t.logicalExpression('&&', ct.tester.expression, (0, lodash_1.cloneDeep)(ct.path.node))));
950
+ }
951
+ catch (error) {
952
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] handleConditions - 替换节点异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
953
+ //
954
+ }
476
955
  }
477
956
  }
478
957
  if (conditions.length > 1) {
479
958
  const lastLength = conditions.length - 1;
480
959
  const lastCon = conditions[lastLength];
960
+ // 记录当前操作的 condition
961
+ let currentCondition = null;
481
962
  let lastAlternate = (0, lodash_1.cloneDeep)(lastCon.path.node);
482
963
  try {
483
- if (lastCon.condition === exports.WX_ELSE_IF) {
964
+ if (lastCon.condition === exports.WX_ELSE_IF && !t.isJSXEmptyExpression(lastCon.tester.expression)) {
484
965
  lastAlternate = t.logicalExpression('&&', lastCon.tester.expression, lastAlternate);
485
966
  }
486
- const node = conditions
487
- .slice(0, lastLength)
488
- .reduceRight((acc, condition) => {
967
+ const node = conditions.slice(0, lastLength).reduceRight((acc, condition) => {
968
+ currentCondition = condition;
969
+ if (t.isJSXEmptyExpression(condition.tester.expression)) {
970
+ (0, helper_1.printLog)("warning" /* processTypeEnum.WARNING */, 'condition.tester.expression', 't.isJSXEmptyExpression(condition.tester.expression)');
971
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] handleConditions - t.isJSXEmptyExpression(condition.tester.expression) ${(0, utils_1.getLineBreak)()}`);
972
+ return null;
973
+ }
489
974
  return t.conditionalExpression(condition.tester.expression, (0, lodash_1.cloneDeep)(condition.path.node), acc);
490
975
  }, lastAlternate);
491
- conditions[0].path.replaceWith(t.jSXExpressionContainer(node));
492
- conditions.slice(1).forEach(c => c.path.remove());
976
+ if (node != null) {
977
+ conditions[0].path.replaceWith(t.jSXExpressionContainer(node));
978
+ conditions.slice(1).forEach((c) => c.path.remove());
979
+ }
493
980
  }
494
981
  catch (error) {
495
- console.error('wx:elif 的值需要用双括号 `{{}}` 包裹它的值');
982
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] handleConditions - wx:elif 转换异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
983
+ const { line, column } = ((_b = (_a = currentCondition.cachePath.node) === null || _a === void 0 ? void 0 : _a.position) === null || _b === void 0 ? void 0 : _b.start) || { line: 0, column: 0 };
984
+ const position = { col: column, row: line };
985
+ throw new utils_1.IReportError('属性转换错误 wx:elif 的值需要用双括号 `{{}}` 包裹它的值', 'wxElifValueFormatError', 'WXML_FILE', (0, utils_1.astToCode)(currentCondition.cachePath.node) || '', position);
496
986
  }
497
987
  }
498
988
  }
@@ -503,9 +993,9 @@ function findWXIfProps(jsx) {
503
993
  jsx
504
994
  .get('openingElement')
505
995
  .get('attributes')
506
- .some(path => {
996
+ .some((path) => {
507
997
  const attr = path.node;
508
- if (t.isJSXIdentifier(attr.name)) {
998
+ if (t.isJSXIdentifier(attr.name) && attr != null) {
509
999
  const name = attr.name.name;
510
1000
  if (name === exports.WX_IF) {
511
1001
  return true;
@@ -515,7 +1005,7 @@ function findWXIfProps(jsx) {
515
1005
  path.remove();
516
1006
  matches = {
517
1007
  reg: match,
518
- tester: attr.value
1008
+ tester: attr.value,
519
1009
  };
520
1010
  return true;
521
1011
  }
@@ -525,20 +1015,25 @@ function findWXIfProps(jsx) {
525
1015
  return matches;
526
1016
  }
527
1017
  function parseNode(node, tagName) {
1018
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] parseNode - 入参 ${(0, utils_1.getLineBreak)()}tagName: ${tagName} ${(0, utils_1.getLineBreak)()}`);
528
1019
  if (node.type === NodeType.Text) {
529
1020
  return parseText(node, tagName);
530
1021
  }
531
1022
  else if (node.type === NodeType.Comment) {
532
1023
  const emptyStatement = t.jSXEmptyExpression();
533
- emptyStatement.innerComments = [{
1024
+ emptyStatement.innerComments = [
1025
+ {
534
1026
  type: 'CommentBlock',
535
- value: ' ' + node.content + ' '
536
- }];
537
- return t.jSXExpressionContainer(emptyStatement);
1027
+ value: ' ' + node.content + ' ',
1028
+ },
1029
+ ];
1030
+ const jsxExpressionContainer = t.jSXExpressionContainer(emptyStatement);
1031
+ return (0, utils_1.addLocInfo)(jsxExpressionContainer, node);
538
1032
  }
539
1033
  return parseElement(node);
540
1034
  }
541
1035
  function parseElement(element) {
1036
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] parseElement - 进入函数 ${(0, utils_1.getLineBreak)()}`);
542
1037
  const tagName = t.jSXIdentifier(global_1.THIRD_PARTY_COMPONENTS.has(element.tagName) ? element.tagName : allCamelCase(element.tagName));
543
1038
  if (utils_1.DEFAULT_Component_SET.has(tagName.name)) {
544
1039
  global_1.usedComponents.add(tagName.name);
@@ -546,7 +1041,7 @@ function parseElement(element) {
546
1041
  let attributes = element.attributes;
547
1042
  if (tagName.name === 'Template') {
548
1043
  let isSpread = false;
549
- attributes = attributes.map(attr => {
1044
+ attributes = attributes.map((attr) => {
550
1045
  if (attr.key === 'data') {
551
1046
  const value = attr.value || '';
552
1047
  const content = parseContent(value);
@@ -562,9 +1057,9 @@ function parseElement(element) {
562
1057
  // (...a) => {{a}}
563
1058
  attr.value = `{{${str.slice(4, strLastIndex)}}}`;
564
1059
  }
565
- else if (/^\(([A-Za-z]+)\)$/.test(str)) {
1060
+ else if (/^\(([A-Za-z,\s]+)\)$/.test(str)) {
566
1061
  // (a) => {{a:a}}
567
- attr.value = `{{${str.replace(/^\(([A-Za-z]+)\)$/, '$1:$1')}}}`;
1062
+ attr.value = `{{${str.slice(1, strLastIndex).replace(/([A-Za-z]+)/g, '$1:$1')}}}`;
568
1063
  }
569
1064
  else {
570
1065
  // (a:'a') => {{a:'a'}}
@@ -581,41 +1076,56 @@ function parseElement(element) {
581
1076
  if (isSpread) {
582
1077
  attributes.push({
583
1078
  key: 'spread',
584
- value: null
1079
+ value: null,
585
1080
  });
586
1081
  }
587
1082
  }
588
- return t.jSXElement(t.jSXOpeningElement(tagName, attributes.map(parseAttribute)), t.jSXClosingElement(tagName), removEmptyTextAndComment(element.children).map((el) => parseNode(el, element.tagName)), false);
1083
+ // return t.jSXElement(
1084
+ // t.jSXOpeningElement(tagName, attributes.map(parseAttribute)),
1085
+ // t.jSXClosingElement(tagName),
1086
+ // removeEmptyTextAndComment(element.children).map((el) => parseNode(el, element.tagName)),
1087
+ // false
1088
+ // )
1089
+ const jSXElement = t.jSXElement(t.jSXOpeningElement(tagName, attributes.map(parseAttribute)), t.jSXClosingElement(tagName), removeEmptyTextAndComment(element.children).map((el) => parseNode(el, element.tagName)), false);
1090
+ return (0, utils_1.addLocInfo)(jSXElement, element);
589
1091
  }
590
- function removEmptyTextAndComment(nodes) {
591
- return nodes.filter(node => {
592
- return node.type === NodeType.Element ||
1092
+ function removeEmptyTextAndComment(nodes) {
1093
+ return nodes
1094
+ .filter((node) => {
1095
+ return (node.type === NodeType.Element ||
593
1096
  (node.type === NodeType.Text && node.content.trim().length !== 0) ||
594
- node.type === NodeType.Comment;
595
- }).filter((node, index) => !(index === 0 && node.type === NodeType.Comment));
1097
+ node.type === NodeType.Comment);
1098
+ })
1099
+ .filter((node, index) => !(index === 0 && node.type === NodeType.Comment));
596
1100
  }
597
- exports.removEmptyTextAndComment = removEmptyTextAndComment;
1101
+ exports.removeEmptyTextAndComment = removeEmptyTextAndComment;
598
1102
  function parseText(node, tagName) {
1103
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] parseText - 进入函数 ${(0, utils_1.getLineBreak)()}`);
599
1104
  if (tagName === 'wxs') {
600
- return t.jSXText(node.content);
1105
+ // return t.jSXText(node.content)
1106
+ return (0, utils_1.addLocInfo)(t.jSXText(node.content), node);
601
1107
  }
602
1108
  const { type, content } = parseContent(node.content);
603
1109
  if (type === 'raw') {
604
1110
  const text = content.replace(/([{}]+)/g, "{'$1'}");
605
- return t.jSXText(text);
1111
+ // return t.jSXText(text)
1112
+ return (0, utils_1.addLocInfo)(t.jSXText(text), node);
606
1113
  }
607
- return t.jSXExpressionContainer((0, utils_1.buildTemplate)(content));
1114
+ // return t.jSXExpressionContainer(buildTemplate(content))
1115
+ return (0, utils_1.addLocInfo)(t.jSXExpressionContainer((0, utils_1.buildTemplate)(content)), node);
608
1116
  }
1117
+ // 匹配{{content}}
609
1118
  const handlebarsRE = /\{\{((?:.|\n)+?)\}\}/g;
610
1119
  function singleQuote(s) {
611
1120
  return `'${s}'`;
612
1121
  }
613
1122
  function parseContent(content, single = false) {
1123
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] parseContent - 进入函数 ${(0, utils_1.getLineBreak)()}`);
614
1124
  content = content.trim();
615
1125
  if (!handlebarsRE.test(content)) {
616
1126
  return {
617
1127
  type: 'raw',
618
- content
1128
+ content,
619
1129
  };
620
1130
  }
621
1131
  const tokens = [];
@@ -641,22 +1151,85 @@ function parseContent(content, single = false) {
641
1151
  }
642
1152
  return {
643
1153
  type: 'expression',
644
- content: tokens.join('+')
1154
+ content: tokens.join('+'),
645
1155
  };
646
1156
  }
647
1157
  exports.parseContent = parseContent;
1158
+ /**
1159
+ * 判断 style 中的属性是否都是 attrName: attrValue 格式
1160
+ *
1161
+ * @param styleAttrsMap
1162
+ */
1163
+ function isAllKeyValueFormat(styleAttrsMap) {
1164
+ // 匹配 attrName: attrValue 格式
1165
+ const isKeyValueFormat = /^(([A-Za-z-]+)\s*):(\s*).*/;
1166
+ const filterStyleAttrs = styleAttrsMap.filter((attr) => attr.trim() !== '');
1167
+ const isStringAttr = filterStyleAttrs.every((attr) => isKeyValueFormat.test(attr.trim()));
1168
+ return isStringAttr;
1169
+ }
1170
+ /**
1171
+ * 解析内联style属性
1172
+ *
1173
+ * @param key 内联属性的类型
1174
+ * @param value 内联属性的值
1175
+ * @returns
1176
+ */
1177
+ function parseStyle(key, value) {
1178
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] parseStyle - 入参 ${(0, utils_1.getLineBreak)()}key: ${key} ${(0, utils_1.getLineBreak)()}value: ${value} ${(0, utils_1.getLineBreak)()}`);
1179
+ const styleAttrs = value.trim().split(';');
1180
+ // 针对attrName: attrValue 格式做转换处理, 其他类型采用'+'连接符
1181
+ if (isAllKeyValueFormat(styleAttrs)) {
1182
+ const attrKeyValueMap = [];
1183
+ parseStyleAttrs(styleAttrs, attrKeyValueMap);
1184
+ convertStyleAttrs(attrKeyValueMap);
1185
+ const objectLiteral = t.objectExpression(attrKeyValueMap.map((attr) => t.objectProperty(t.identifier(attr.attrName), attr.value)));
1186
+ return t.jSXAttribute(t.jSXIdentifier(key), t.jsxExpressionContainer(objectLiteral));
1187
+ }
1188
+ else {
1189
+ return parseContent(value);
1190
+ }
1191
+ }
1192
+ exports.parseStyle = parseStyle;
648
1193
  function parseAttribute(attr) {
1194
+ (0, utils_1.updateLogFileContent)(`INFO [taroize] parseAttribute - 入参 ${(0, utils_1.getLineBreak)()}attr: ${JSON.stringify(attr)} ${(0, utils_1.getLineBreak)()}`);
649
1195
  let { key, value } = attr;
650
1196
  let jsxValue = null;
1197
+ let type = '';
1198
+ let content = '';
651
1199
  if (value) {
1200
+ const cacheValue = value;
652
1201
  if (key === 'class' && value.startsWith('[') && value.endsWith(']')) {
653
1202
  value = value.slice(1, value.length - 1).replace(',', '');
1203
+ (0, utils_1.createErrorCodeMsg)('unsupportedClassArray', 'Taro/React 不支持 class 传入数组,此写法可能无法得到正确的 class', `class=${JSON.stringify(cacheValue).replace(/"/g, "'")}`, global_1.globals.currentParseFile);
1204
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] parseAttribute - Taro/React 不支持 class 传入数组,此写法可能无法得到正确的 class ${(0, utils_1.getLineBreak)()}`);
654
1205
  // eslint-disable-next-line no-console
655
1206
  console.log((0, utils_1.codeFrameError)(attr, 'Taro/React 不支持 class 传入数组,此写法可能无法得到正确的 class'));
656
1207
  }
657
- const { type, content } = parseContent(value);
1208
+ value = convertStyleUnit(value);
1209
+ // 判断属性是否为style属性
1210
+ if (key === 'style' && value) {
1211
+ try {
1212
+ const styleParseReslut = parseStyle(key, value);
1213
+ if (t.isJSXAttribute(styleParseReslut)) {
1214
+ return styleParseReslut;
1215
+ }
1216
+ else {
1217
+ content = styleParseReslut.content;
1218
+ type = styleParseReslut.type;
1219
+ }
1220
+ }
1221
+ catch (error) {
1222
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] parseAttribute - 属性 style="${value}" 解析异常 ${(0, utils_1.getLineBreak)()}${error} ${(0, utils_1.getLineBreak)()}`);
1223
+ throw new utils_1.IReportError(`属性解析失败 style="${value}"解析失败,${error}`, 'StyleAttributeParsingError', 'WXML_FILE', `style="${value}"`);
1224
+ }
1225
+ }
1226
+ else {
1227
+ const parseContentResult = parseContent(value);
1228
+ content = parseContentResult.content;
1229
+ type = parseContentResult.type;
1230
+ }
658
1231
  if (type === 'raw') {
659
- jsxValue = t.stringLiteral(content.replace(/"/g, '\''));
1232
+ jsxValue = t.stringLiteral(content.replace(/"/g, "'"));
660
1233
  }
661
1234
  else {
662
1235
  let expr;
@@ -671,27 +1244,33 @@ function parseAttribute(attr) {
671
1244
  expr = t.stringLiteral('');
672
1245
  }
673
1246
  else {
674
- throw new Error(err);
1247
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] parseAttribute - 模板参数转换异常 ${(0, utils_1.getLineBreak)()}${err} ${(0, utils_1.getLineBreak)()}`);
1248
+ throw new utils_1.IReportError(err, 'TemplateParameterConversionError', 'WXML_FILE', `${key}: ${value}`);
675
1249
  }
676
1250
  }
677
- else if (content.includes(':') || (content.includes('...') && content.includes(','))) {
678
- const file = (0, babylon_1.parse)(`var a = ${attr.value.slice(1, attr.value.length - 1)}`, { plugins: ['objectRestSpread'] });
1251
+ else if (content.includes(':') || content.includes('...')) {
1252
+ const file = (0, parser_1.parse)(`var a = ${attr.value.slice(1, attr.value.length - 1)}`, {
1253
+ plugins: ['objectRestSpread'],
1254
+ });
679
1255
  expr = file.program.body[0].declarations[0].init;
680
1256
  }
681
1257
  else {
682
1258
  const err = `转换模板参数: \`${key}: ${value}\` 报错`;
683
- throw new Error(err);
1259
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] parseAttribute - 模板参数转换异常 ${(0, utils_1.getLineBreak)()}${err} ${(0, utils_1.getLineBreak)()}`);
1260
+ throw new utils_1.IReportError(err, 'TemplateParameterConversionError', 'WXML_FILE', `${key}: ${value}`);
684
1261
  }
685
1262
  }
686
1263
  if (t.isThisExpression(expr)) {
1264
+ (0, utils_1.createErrorCodeMsg)('ThisKeywordUsageWarning', '在参数中使用 `this` 可能会造成意想不到的结果,已将此参数修改为 `__placeholder__`,你可以在转换后的代码查找这个关键字修改。', value, global_1.globals.currentParseFile);
1265
+ (0, utils_1.updateLogFileContent)(`WARN [taroize] parseAttribute - 在参数中使用 this 可能会造成意想不到的结果 ${(0, utils_1.getLineBreak)()}`);
687
1266
  console.error('在参数中使用 `this` 可能会造成意想不到的结果,已将此参数修改为 `__placeholder__`,你可以在转换后的代码查找这个关键字修改。');
688
1267
  expr = t.stringLiteral('__placeholder__');
689
1268
  }
690
1269
  jsxValue = t.jSXExpressionContainer(expr);
691
1270
  }
692
1271
  }
693
- const jsxKey = handleAttrKey(key);
694
- if (/^on[A-Z]/.test(jsxKey) && !(/^catch/.test(key)) && jsxValue && t.isStringLiteral(jsxValue)) {
1272
+ let jsxKey = handleAttrKey(key);
1273
+ if (/^on[A-Z]/.test(jsxKey) && !/^catch/.test(key) && jsxValue && t.isStringLiteral(jsxValue)) {
695
1274
  jsxValue = t.jSXExpressionContainer(t.memberExpression(t.thisExpression(), t.identifier(jsxValue.value)));
696
1275
  }
697
1276
  if (key.startsWith('catch') && value) {
@@ -700,15 +1279,20 @@ function parseAttribute(attr) {
700
1279
  global_1.globals.hasCatchTrue = true;
701
1280
  }
702
1281
  else if (t.isStringLiteral(jsxValue)) {
703
- jsxValue = t.jSXExpressionContainer(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('privateStopNoop')), t.identifier('bind')), [t.thisExpression(), t.memberExpression(t.thisExpression(), t.identifier(jsxValue.value))]));
1282
+ jsxValue = t.jSXExpressionContainer(t.memberExpression(t.thisExpression(), t.identifier(jsxValue.value)));
1283
+ }
1284
+ }
1285
+ // 如果data-xxx自定义属性名xxx不是以-分隔的写法就要转成全小写属性名
1286
+ if (value && jsxKey.startsWith('data-')) {
1287
+ const realKey = jsxKey.replace(/^data-/, '');
1288
+ if (realKey.indexOf('-') === -1) {
1289
+ jsxKey = `data-${realKey.toLowerCase()}`;
704
1290
  }
705
1291
  }
706
1292
  return t.jSXAttribute(t.jSXIdentifier(jsxKey), jsxValue);
707
1293
  }
708
1294
  function handleAttrKey(key) {
709
- if (key.startsWith('wx:') ||
710
- key.startsWith('wx-') ||
711
- key.startsWith('data-')) {
1295
+ if (key.startsWith('wx:') || key.startsWith('wx-') || key.startsWith('data-')) {
712
1296
  return key;
713
1297
  }
714
1298
  else if (key === 'class') {
@@ -722,7 +1306,8 @@ function handleAttrKey(key) {
722
1306
  key = key.replace(/^(bind:|catch:|bind|catch)/, 'on');
723
1307
  key = (0, lodash_1.camelCase)(key);
724
1308
  if (!(0, utils_1.isValidVarName)(key)) {
725
- throw new Error(`"${key}" 不是一个有效 JavaScript 变量名`);
1309
+ (0, utils_1.updateLogFileContent)(`ERROR [taroize] handleAttrKey - ${key} 不是一个有效 JavaScript 变量名 ${(0, utils_1.getLineBreak)()}`);
1310
+ throw new utils_1.IReportError(`属性名"${key}" 不是一个有效 JavaScript 变量名`, 'InvalidVariableNameError', 'WXML_FILE', `${key}`);
726
1311
  }
727
1312
  return key.substr(0, 2) + key[2].toUpperCase() + key.substr(3);
728
1313
  }