@tarojs/cli-convertor 3.6.17 → 3.6.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ // import { ProjectType } from './../../taro-plugin-mini-ci/src/BaseCi';
12
13
  const template_1 = require("@babel/template");
13
14
  const traverse_1 = require("@babel/traverse");
14
15
  const t = require("@babel/types");
@@ -22,10 +23,11 @@ const unitTransform = require("postcss-taro-unit-transform");
22
23
  const prettier = require("prettier");
23
24
  const util_1 = require("./util");
24
25
  const astConvert_1 = require("./util/astConvert");
26
+ const global_1 = require("./util/global");
25
27
  const prettierJSConfig = {
26
28
  semi: false,
27
29
  singleQuote: true,
28
- parser: 'babel'
30
+ parser: 'babel',
29
31
  };
30
32
  const babylonConfig = {
31
33
  sourceType: 'module',
@@ -36,19 +38,18 @@ const babylonConfig = {
36
38
  'asyncGenerators',
37
39
  'objectRestSpread',
38
40
  'decorators',
39
- 'dynamicImport'
40
- ]
41
+ 'dynamicImport',
42
+ ],
41
43
  };
42
44
  const OUTPUT_STYLE_EXTNAME = '.scss';
43
45
  const WX_GLOBAL_FN = new Set(['getApp', 'getCurrentPages', 'requirePlugin', 'Behavior']);
44
46
  function processStyleImports(content, processFn) {
45
- const style = [];
46
- const imports = [];
47
+ // 获取css中的引用样式文件路径集合
48
+ const imports = (0, util_1.getWxssImports)(content);
49
+ // 将引用的样式文件路径转换为相对路径,后缀名转换为.scss
47
50
  const styleReg = new RegExp('.wxss');
48
51
  content = content.replace(helper_1.CSS_IMPORT_REG, (m, _$1, $2) => {
49
52
  if (styleReg.test($2)) {
50
- style.push(m);
51
- imports.push($2);
52
53
  if (processFn) {
53
54
  return processFn(m, $2);
54
55
  }
@@ -61,33 +62,38 @@ function processStyleImports(content, processFn) {
61
62
  });
62
63
  return {
63
64
  content,
64
- style,
65
- imports
65
+ imports,
66
66
  };
67
67
  }
68
68
  class Convertor {
69
- constructor(root) {
69
+ constructor(root, isTsProject) {
70
70
  this.wxsIncrementId = (0, util_1.incrementId)();
71
71
  this.root = root;
72
72
  this.convertRoot = path.join(this.root, 'taroConvert');
73
73
  this.convertDir = path.join(this.convertRoot, 'src');
74
74
  this.importsDir = path.join(this.convertDir, 'imports');
75
+ this.isTsProject = isTsProject;
76
+ if (isTsProject) {
77
+ this.miniprogramRoot = path.join(this.root, 'miniprogram');
78
+ }
75
79
  this.fileTypes = {
76
80
  TEMPL: '.wxml',
77
81
  STYLE: '.wxss',
78
82
  CONFIG: '.json',
79
- SCRIPT: '.js'
83
+ SCRIPT: isTsProject ? '.ts' : '.js',
80
84
  };
81
85
  this.pages = new Set();
82
86
  this.components = new Set();
83
87
  this.hadBeenCopyedFiles = new Set();
84
88
  this.hadBeenBuiltComponents = new Set();
85
89
  this.hadBeenBuiltImports = new Set();
90
+ this.reportErroMsg = [];
86
91
  this.init();
87
92
  }
88
93
  init() {
89
94
  console.log(helper_1.chalk.green('开始代码转换...'));
90
95
  this.initConvert();
96
+ this.getConvertConfig();
91
97
  this.getApp();
92
98
  this.getPages();
93
99
  this.getSitemapLocation();
@@ -100,13 +106,22 @@ class Convertor {
100
106
  else {
101
107
  helper_1.fs.ensureDirSync(this.convertRoot);
102
108
  }
109
+ this.convertSelfDefinedConfig();
110
+ // 创建.convert目录,存放转换中间数据
111
+ (0, util_1.generateDir)(path.join(this.convertRoot, '.convert'));
112
+ global_1.globals.logFilePath = path.join(this.convertRoot, '.convert', 'convert.log');
103
113
  }
104
114
  parseAst({ ast, sourceFilePath, outputFilePath, importStylePath, depComponents, imports = [] }) {
105
115
  const scriptFiles = new Set();
106
116
  // eslint-disable-next-line @typescript-eslint/no-this-alias
107
117
  const self = this;
118
+ // 转换后js页面的所有自定义标签
119
+ const scriptComponents = [];
108
120
  let componentClassName;
109
121
  let needInsertImportTaro = false;
122
+ let hasCacheOptionsRequired = false;
123
+ let hasDatasetRequired = false;
124
+ const set = new Set();
110
125
  (0, traverse_1.default)(ast, {
111
126
  Program: {
112
127
  enter(astPath) {
@@ -121,10 +136,10 @@ class Convertor {
121
136
  astPath.traverse({
122
137
  JSXElement() {
123
138
  isTaroComponent = true;
124
- }
139
+ },
125
140
  });
126
141
  }
127
- }
142
+ },
128
143
  });
129
144
  if (isTaroComponent) {
130
145
  componentClassName = node.id.name;
@@ -141,10 +156,10 @@ class Convertor {
141
156
  astPath.traverse({
142
157
  JSXElement() {
143
158
  isTaroComponent = true;
144
- }
159
+ },
145
160
  });
146
161
  }
147
- }
162
+ },
148
163
  });
149
164
  if (isTaroComponent) {
150
165
  if (node.id === null) {
@@ -172,10 +187,10 @@ class Convertor {
172
187
  astPath.traverse({
173
188
  JSXElement() {
174
189
  isTaroComponent = true;
175
- }
190
+ },
176
191
  });
177
192
  }
178
- }
193
+ },
179
194
  });
180
195
  if (isTaroComponent) {
181
196
  componentClassName = declaration.id.name;
@@ -187,40 +202,211 @@ class Convertor {
187
202
  const node = astPath.node;
188
203
  const source = node.source;
189
204
  const value = source.value;
190
- (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, source, value);
205
+ (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, source, value, self.isTsProject);
191
206
  },
192
207
  CallExpression(astPath) {
208
+ (0, util_1.printToLogFile)(`解析CallExpression: ${astPath} ${(0, util_1.getLineBreak)()}`);
193
209
  const node = astPath.node;
194
210
  const calleePath = astPath.get('callee');
195
211
  const callee = calleePath.node;
196
212
  if (callee.type === 'Identifier') {
197
213
  if (callee.name === 'require') {
198
214
  const args = node.arguments;
215
+ if (args.length === 0) {
216
+ // require()
217
+ return;
218
+ }
219
+ if (!t.isStringLiteral(args[0])) {
220
+ // require 暂不支持动态导入,如require('aa' + aa),后续收录到报告中
221
+ throw new Error(`require暂不支持动态导入, filePath: ${sourceFilePath}, context: ${astPath}`);
222
+ }
199
223
  const value = args[0].value;
200
- (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, args[0], value);
224
+ (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, args[0], value, self.isTsProject);
201
225
  }
202
226
  else if (WX_GLOBAL_FN.has(callee.name)) {
203
227
  calleePath.replaceWith(t.memberExpression(t.identifier('Taro'), callee));
204
228
  needInsertImportTaro = true;
205
229
  }
230
+ else if (callee.name === 'Page' || callee.name === 'Component' || callee.name === 'App') {
231
+ // 将 App() Page() Component() 改为 cacheOptions.setOptionsToCache() 的形式去初始化页面数据
232
+ const arg = astPath.get('arguments')[0];
233
+ const cacheOptionsAstNode = t.callExpression(t.memberExpression(t.identifier('cacheOptions'), t.identifier('setOptionsToCache')), [arg.node]);
234
+ astPath.replaceWith(cacheOptionsAstNode);
235
+ // 创建导入 cacheOptions 对象的 ast 节点
236
+ const requireCacheOptionsAst = t.variableDeclaration('const', [
237
+ t.variableDeclarator(t.objectPattern([
238
+ t.objectProperty(t.identifier('cacheOptions'), t.identifier('cacheOptions'), false, true),
239
+ ]), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
240
+ ]);
241
+ // 若已经引入过 cacheOptions 则不在引入,防止重复引入问题
242
+ if (!hasCacheOptionsRequired) {
243
+ ast.program.body.unshift(requireCacheOptionsAst);
244
+ hasCacheOptionsRequired = true;
245
+ }
246
+ }
206
247
  }
207
248
  },
208
249
  MemberExpression(astPath) {
209
250
  const node = astPath.node;
210
251
  const object = node.object;
252
+ const prettier = node.property;
211
253
  if (t.isIdentifier(object) && object.name === 'wx') {
212
254
  node.object = t.identifier('Taro');
213
255
  needInsertImportTaro = true;
214
256
  }
215
- }
257
+ else if (t.isIdentifier(prettier) && prettier.name === 'dataset') {
258
+ node.object = t.callExpression(t.identifier('getTarget'), [object, t.identifier('Taro')]);
259
+ // 创建导入 cacheOptions 对象的 ast 节点
260
+ if (!hasDatasetRequired) {
261
+ const requireCacheOptionsAst = t.variableDeclaration('const', [
262
+ t.variableDeclarator(t.objectPattern([
263
+ t.objectProperty(t.identifier('getTarget'), t.identifier('getTarget'), false, true),
264
+ ]), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
265
+ ]);
266
+ ast.program.body.unshift(requireCacheOptionsAst);
267
+ hasDatasetRequired = true;
268
+ needInsertImportTaro = true;
269
+ }
270
+ }
271
+ },
272
+ OptionalMemberExpression(astPath) {
273
+ const node = astPath.node;
274
+ const object = node.object;
275
+ const prettier = node.property;
276
+ if (t.isIdentifier(prettier) && prettier.name === 'dataset') {
277
+ node.object = t.callExpression(t.identifier('getTarget'), [object, t.identifier('Taro')]);
278
+ // 创建导入 getTarget 对象的 ast 节点, 并且防止重复引用
279
+ if (!hasDatasetRequired) {
280
+ const requireCacheOptionsAst = t.variableDeclaration('const', [
281
+ t.variableDeclarator(t.objectPattern([
282
+ t.objectProperty(t.identifier('getTarget'), t.identifier('getTarget'), false, true),
283
+ ]), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
284
+ ]);
285
+ ast.program.body.unshift(requireCacheOptionsAst);
286
+ hasDatasetRequired = true;
287
+ needInsertImportTaro = true;
288
+ }
289
+ }
290
+ },
291
+ // 获取js界面所有用到的自定义标签,不重复
292
+ JSXElement(astPath) {
293
+ const openingElement = astPath.get('openingElement');
294
+ const jsxName = openingElement.get('name');
295
+ if (jsxName.isJSXIdentifier()) {
296
+ const componentName = jsxName.node.name;
297
+ if (!util_1.DEFAULT_Component_SET.has(componentName) && scriptComponents.indexOf(componentName) === -1) {
298
+ scriptComponents.push(componentName);
299
+ }
300
+ if (/^\S(\S)*Tmpl$/.test(componentName)) {
301
+ const templateImport = imports.find((tmplImport) => tmplImport.name === `${componentName}`);
302
+ const templateFuncs = templateImport === null || templateImport === void 0 ? void 0 : templateImport.funcs;
303
+ if (templateFuncs && templateFuncs.size > 0) {
304
+ const attributes = openingElement.node.attributes;
305
+ templateFuncs.forEach((templateFunc) => {
306
+ const memberExpression = t.memberExpression(t.thisExpression(), t.identifier(templateFunc));
307
+ const value = t.jsxExpressionContainer(memberExpression);
308
+ const name = t.jsxIdentifier(templateFunc);
309
+ // 传递的方法插入到Tmpl标签属性中
310
+ attributes.push(t.jsxAttribute(name, value));
311
+ });
312
+ }
313
+ }
314
+ else if (componentName === 'Template') {
315
+ // 处理没被成功转换的模板, 如果被转换了就不会还是Template
316
+ const attrs = openingElement.get('attributes');
317
+ const is = attrs.find((attr) => t.isJSXAttribute(attr) &&
318
+ t.isJSXIdentifier(attr.get('name')) &&
319
+ t.isJSXAttribute(attr.node) &&
320
+ attr.node.name.name === 'is');
321
+ // 处理<template is=包含变量的情况(组件的动态名称)
322
+ if (is && t.isJSXAttribute(is.node)) {
323
+ const value = is.node.value;
324
+ if (value && t.isJSXExpressionContainer(value)) {
325
+ const expression = value.expression;
326
+ // 1、<template is={{var}}> 2、<template is="string{{var}}">
327
+ if (t.isIdentifier(expression) ||
328
+ (t.isBinaryExpression(expression) && expression.operator === '+')) {
329
+ // 加上map, template原名和新名字的映射
330
+ const componentMapList = [];
331
+ for (const order in imports) {
332
+ for (const key in imports[order]) {
333
+ if (key === 'tmplName') {
334
+ const tmplName = imports[order][key];
335
+ const tmplLastName = imports[order].name;
336
+ // imports去重可能会把map里的去掉, 所以要加回去
337
+ if (!scriptComponents.includes(tmplLastName)) {
338
+ scriptComponents.push(tmplLastName);
339
+ }
340
+ componentMapList.push(t.objectProperty(t.stringLiteral('' + tmplName), t.identifier(tmplLastName)));
341
+ }
342
+ }
343
+ }
344
+ const withWeappPath = astPath.findParent((p) => p.isClassDeclaration());
345
+ if (withWeappPath) {
346
+ const MapVariableDeclaration = t.variableDeclaration('const', [
347
+ t.variableDeclarator(t.identifier('ComponentMap'), t.objectExpression(componentMapList)),
348
+ ]);
349
+ withWeappPath.insertBefore(MapVariableDeclaration);
350
+ }
351
+ // 加上用map给新标签赋值
352
+ const returnPath = astPath.findParent((p) => p.isReturnStatement());
353
+ if (returnPath) {
354
+ const ComponentNameVariableDeclaration = t.variableDeclaration('let', [
355
+ t.variableDeclarator(t.identifier('ComponentName'), t.memberExpression(t.identifier('ComponentMap'), expression, true)),
356
+ ]);
357
+ returnPath.insertBefore(ComponentNameVariableDeclaration);
358
+ }
359
+ // 标签非Template的情况下不会加spread, 删除spread属性; 更改开闭合标签为ComponentName
360
+ const attributes = [];
361
+ const data = attrs.find((attr) => t.isJSXAttribute(attr) &&
362
+ t.isJSXIdentifier(attr.get('name')) &&
363
+ t.isJSXAttribute(attr.node) &&
364
+ attr.node.name.name === 'data');
365
+ if (data && t.isJSXAttribute(data.node)) {
366
+ attributes.push(data.node);
367
+ }
368
+ astPath.replaceWith(t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('ComponentName'), attributes), t.jSXClosingElement(t.jSXIdentifier('ComponentName')), [], true));
369
+ }
370
+ }
371
+ }
372
+ }
373
+ }
374
+ },
375
+ // 处理this.data.xx = XXX 的情况,因为此表达式在taro暂不支持, 转为setData
376
+ AssignmentExpression(astPath) {
377
+ const node = astPath.node;
378
+ if (t.isMemberExpression(node.left) &&
379
+ t.isMemberExpression(node.left.object) &&
380
+ t.isThisExpression(node.left.object.object) &&
381
+ t.isIdentifier(node.left.object.property)) {
382
+ // 确认左边是this.data
383
+ if (node.left.object.property.name === 'data' && t.isIdentifier(node.left.property)) {
384
+ const lastName = node.left.property.name;
385
+ // 右边不能确定数据类型,所以直接存整个对象
386
+ const rightValue = node.right;
387
+ // 由于合并setData会导致打乱代码顺序, 影响代码逻辑, 所以每一句this.data.xx单独转成一句setData
388
+ const memberExp = t.memberExpression(t.thisExpression(), t.identifier('setData'));
389
+ const objExp = t.objectExpression([t.objectProperty(t.identifier(lastName), rightValue)]);
390
+ astPath.replaceWith(t.expressionStatement(t.callExpression(memberExp, [objExp])));
391
+ console.log(`转换 语法 this.data.xx=XX暂不支持,原地替换为setData()`);
392
+ }
393
+ }
394
+ },
216
395
  });
217
396
  },
218
397
  exit(astPath) {
219
398
  const bodyNode = astPath.get('body');
220
- const lastImport = bodyNode.filter(p => p.isImportDeclaration()).pop();
221
- const hasTaroImport = bodyNode.some(p => p.isImportDeclaration() && p.node.source.value === '@tarojs/taro');
222
- if (needInsertImportTaro && !hasTaroImport) {
223
- astPath.node.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier('Taro'))], t.stringLiteral('@tarojs/taro')));
399
+ const lastImport = bodyNode.filter((p) => p.isImportDeclaration() || (0, astConvert_1.isCommonjsImport)(p)).pop();
400
+ if (needInsertImportTaro && !(0, astConvert_1.hasTaroImport)(bodyNode)) {
401
+ // 根据模块类型(commonjs/es6) 确定导入taro模块的类型
402
+ if ((0, astConvert_1.isCommonjsModule)(ast.program.body)) {
403
+ astPath.node.body.unshift(t.variableDeclaration('const', [
404
+ t.variableDeclarator(t.identifier('Taro'), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/taro')])),
405
+ ]));
406
+ }
407
+ else {
408
+ astPath.node.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier('Taro'))], t.stringLiteral('@tarojs/taro')));
409
+ }
224
410
  }
225
411
  astPath.traverse({
226
412
  StringLiteral(astPath) {
@@ -237,7 +423,7 @@ class Convertor {
237
423
  const imageRelativePath = (0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, sourceImagePath));
238
424
  const outputImagePath = self.getDistFilePath(sourceImagePath);
239
425
  if (helper_1.fs.existsSync(sourceImagePath)) {
240
- self.copyFileToTaro(sourceImagePath, outputImagePath);
426
+ (0, util_1.copyFileToTaro)(sourceImagePath, outputImagePath);
241
427
  (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, '图片', self.generateShowPath(outputImagePath));
242
428
  }
243
429
  else if (!t.isBinaryExpression(astPath.parent) || astPath.parent.operator !== '+') {
@@ -250,11 +436,18 @@ class Convertor {
250
436
  astPath.replaceWith(t.jSXExpressionContainer(t.callExpression(t.identifier('require'), [t.stringLiteral(imageRelativePath)])));
251
437
  }
252
438
  }
253
- }
439
+ },
254
440
  });
255
441
  if (lastImport) {
256
442
  if (importStylePath) {
257
- lastImport.insertAfter(t.importDeclaration([], t.stringLiteral((0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, importStylePath)))));
443
+ if ((0, astConvert_1.isCommonjsModule)(ast.program.body)) {
444
+ lastImport.insertAfter(t.callExpression(t.identifier('require'), [
445
+ t.stringLiteral((0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, importStylePath))),
446
+ ]));
447
+ }
448
+ else {
449
+ lastImport.insertAfter(t.importDeclaration([], t.stringLiteral((0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, importStylePath)))));
450
+ }
258
451
  }
259
452
  if (imports && imports.length) {
260
453
  imports.forEach(({ name, ast, wxs }) => {
@@ -262,34 +455,172 @@ class Convertor {
262
455
  if (componentClassName === importName) {
263
456
  return;
264
457
  }
265
- const importPath = path.join(self.importsDir, importName + (wxs ? self.wxsIncrementId() : '') + '.js');
458
+ const importPath = path.join(self.importsDir, importName + (wxs ? self.wxsIncrementId() : '') + (self.isTsProject ? '.ts' : '.js'));
266
459
  if (!self.hadBeenBuiltImports.has(importPath)) {
267
460
  self.hadBeenBuiltImports.add(importPath);
268
461
  self.writeFileToTaro(importPath, prettier.format((0, astConvert_1.generateMinimalEscapeCode)(ast), prettierJSConfig));
269
462
  }
270
- lastImport.insertAfter((0, template_1.default)(`import ${importName} from '${(0, helper_1.promoteRelativePath)(path.relative(outputFilePath, importPath))}'`, babylonConfig)());
463
+ if (scriptComponents.indexOf(importName) !== -1 || (wxs && wxs === true)) {
464
+ lastImport.insertAfter((0, template_1.default)(`import ${importName} from '${(0, helper_1.promoteRelativePath)(path.relative(outputFilePath, importPath))}'`, babylonConfig)());
465
+ }
271
466
  });
272
467
  }
273
468
  if (depComponents && depComponents.size) {
274
- depComponents.forEach(componentObj => {
275
- const name = (0, helper_1.pascalCase)(componentObj.name);
276
- const component = componentObj.path;
277
- lastImport.insertAfter((0, template_1.default)(`import ${name} from '${(0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, component))}'`, babylonConfig)());
469
+ depComponents.forEach((componentObj) => {
470
+ const name = (0, helper_1.pascalCase)(componentObj.name.toLowerCase());
471
+ // 如果不是js页面用到的组件,无需导入
472
+ if (scriptComponents.indexOf(name) === -1) {
473
+ return;
474
+ }
475
+ // 如果用到了,从scriptComponents中移除
476
+ const index = scriptComponents.indexOf(name);
477
+ scriptComponents.splice(index, 1);
478
+ let componentPath = componentObj.path;
479
+ if (componentPath.indexOf(self.root) !== -1) {
480
+ componentPath = path.relative(sourceFilePath, componentPath);
481
+ }
482
+ lastImport.insertAfter((0, template_1.default)(`import ${name} from '${(0, helper_1.promoteRelativePath)(componentPath)}'`, babylonConfig)());
278
483
  });
279
484
  }
280
485
  }
486
+ },
487
+ },
488
+ });
489
+ // 遍历 ast ,将多次 const { xxx } = require('@tarojs/with-weapp') 引入压缩为一次引入
490
+ (0, traverse_1.default)(ast, {
491
+ VariableDeclaration(astPath) {
492
+ const { kind, declarations } = astPath.node;
493
+ let currentAstIsWithWeapp = false;
494
+ if (kind === 'const') {
495
+ declarations.forEach((declaration) => {
496
+ const { id, init } = declaration;
497
+ if (t.isObjectPattern(id) &&
498
+ t.isCallExpression(init) &&
499
+ t.isIdentifier(init.callee) &&
500
+ t.isStringLiteral(init.arguments[0])) {
501
+ const name = init.callee.name;
502
+ const args = init.arguments[0].value;
503
+ if (name === 'require' && args === '@tarojs/with-weapp') {
504
+ currentAstIsWithWeapp = true;
505
+ id.properties.forEach((propertie) => {
506
+ if (t.isObjectProperty(propertie) && t.isIdentifier(propertie.value)) {
507
+ set.add(propertie.value.name);
508
+ }
509
+ });
510
+ }
511
+ }
512
+ });
281
513
  }
282
- }
514
+ if (currentAstIsWithWeapp) {
515
+ astPath.remove();
516
+ }
517
+ },
283
518
  });
519
+ // 若 set 为空则不引入 @tarojs/with-weapp
520
+ if (set.size !== 0) {
521
+ if ((0, astConvert_1.isCommonjsModule)(ast.program.body)) {
522
+ const objectPropertyArray = [];
523
+ set.forEach((key) => {
524
+ if (key === 'withWeapp') {
525
+ objectPropertyArray.push(t.objectProperty(t.identifier('default'), t.identifier('withWeapp'), false, true));
526
+ }
527
+ else {
528
+ objectPropertyArray.push(t.objectProperty(t.identifier(key), t.identifier(key), false, true));
529
+ }
530
+ });
531
+ const requireWithWeappAst = t.variableDeclaration('const', [
532
+ t.variableDeclarator(t.objectPattern(objectPropertyArray), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
533
+ ]);
534
+ ast.program.body.unshift(requireWithWeappAst);
535
+ }
536
+ else {
537
+ const objectPropertyArray = [];
538
+ let hasWithWeapp = false;
539
+ set.forEach((key) => {
540
+ if (key === 'withWeapp') {
541
+ hasWithWeapp = true;
542
+ }
543
+ else {
544
+ objectPropertyArray.push(t.importSpecifier(t.identifier(key), t.identifier(key)));
545
+ }
546
+ });
547
+ if (hasWithWeapp) {
548
+ objectPropertyArray.unshift(t.importDefaultSpecifier(t.identifier('withWeapp')));
549
+ }
550
+ const importWithWeapp = t.importDeclaration(objectPropertyArray, t.stringLiteral('@tarojs/with-weapp'));
551
+ ast.program.body.unshift(importWithWeapp);
552
+ }
553
+ }
284
554
  return {
285
555
  ast,
286
- scriptFiles
556
+ scriptFiles,
287
557
  };
288
558
  }
559
+ convertSelfDefinedConfig() {
560
+ // 搬运自定义的配置文件
561
+ const selfDefinedConfig = [];
562
+ // 目前只有tsconfig.json,还有的话继续加到array里
563
+ selfDefinedConfig[0] = `tsconfig${this.fileTypes.CONFIG}`;
564
+ for (const tempConfig of selfDefinedConfig) {
565
+ const tempConfigPath = path.join(this.root, tempConfig);
566
+ if (helper_1.fs.existsSync(tempConfig)) {
567
+ try {
568
+ const outputFilePath = path.join(this.convertRoot, tempConfig);
569
+ (0, util_1.copyFileToTaro)(tempConfigPath, outputFilePath);
570
+ }
571
+ catch (err) {
572
+ // 失败不退出,仅提示
573
+ console.log(helper_1.chalk.red(`tsconfig${this.fileTypes.CONFIG} 拷贝失败,请检查!`));
574
+ }
575
+ }
576
+ }
577
+ }
578
+ getConvertConfig() {
579
+ // 处理convert.config.json,并存储到convertConfig中
580
+ const convertJsonPath = path.join(this.root, `convert.config${this.fileTypes.CONFIG}`);
581
+ if (helper_1.fs.existsSync(convertJsonPath)) {
582
+ try {
583
+ const convertJson = JSON.parse(String(helper_1.fs.readFileSync(convertJsonPath)));
584
+ this.convertConfig = Object.assign({}, convertJson);
585
+ this.convertConfig.external = (0, util_1.transRelToAbsPath)(convertJsonPath, this.convertConfig.external);
586
+ }
587
+ catch (err) {
588
+ console.log(helper_1.chalk.red(`convert.config${this.fileTypes.CONFIG} 读取失败,请检查!`));
589
+ process.exit(1);
590
+ }
591
+ }
592
+ }
289
593
  getApp() {
290
- this.entryJSPath = path.join(this.root, `app${this.fileTypes.SCRIPT}`);
291
- this.entryJSONPath = path.join(this.root, `app${this.fileTypes.CONFIG}`);
292
- this.entryStylePath = path.join(this.root, `app${this.fileTypes.STYLE}`);
594
+ try {
595
+ const projectConfigPath = path.join(this.root, `project.config${this.fileTypes.CONFIG}`); // project.config.json 文件路径
596
+ // 解析 project.config.json 文件,获取 miniprogramRoot 字段的值
597
+ const projectConfig = JSON.parse(helper_1.fs.readFileSync(projectConfigPath, 'utf8'));
598
+ this.miniprogramRoot = projectConfig.miniprogramRoot;
599
+ }
600
+ catch (err) {
601
+ console.error('读取 project.config.json 文件失败:', err);
602
+ process.exit(1);
603
+ }
604
+ // 如果找到 miniprogramRoot字段,则以对应目录作为小程序逻辑目录
605
+ if (this.miniprogramRoot) {
606
+ this.root = path.resolve(this.miniprogramRoot);
607
+ }
608
+ if (this.isTsProject) {
609
+ this.entryJSPath = path.join(this.miniprogramRoot, `app${this.fileTypes.SCRIPT}`);
610
+ this.entryJSONPath = path.join(this.miniprogramRoot, `app${this.fileTypes.CONFIG}`);
611
+ this.entryStylePath = path.join(this.miniprogramRoot, `app${this.fileTypes.STYLE}`);
612
+ }
613
+ else {
614
+ this.entryJSPath = path.join(this.root, `app${this.fileTypes.SCRIPT}`);
615
+ this.entryJSONPath = path.join(this.root, `app${this.fileTypes.CONFIG}`);
616
+ this.entryStylePath = path.join(this.root, `app${this.fileTypes.STYLE}`);
617
+ }
618
+ // 如果在 miniprogramRoot 目录下找到 app.json 文件,则将入口文件和配置文件路径修改为对应的路径
619
+ if (this.miniprogramRoot && helper_1.fs.existsSync(path.join(this.root, `app${this.fileTypes.CONFIG}`))) {
620
+ this.entryJSPath = path.join(this.root, `app${this.fileTypes.SCRIPT}`);
621
+ this.entryJSONPath = path.join(this.root, `app${this.fileTypes.CONFIG}`);
622
+ this.entryStylePath = path.join(this.root, `app${this.fileTypes.STYLE}`);
623
+ }
293
624
  try {
294
625
  this.entryJSON = JSON.parse(String(helper_1.fs.readFileSync(this.entryJSONPath)));
295
626
  const using = this.entryJSON.usingComponents;
@@ -298,7 +629,10 @@ class Convertor {
298
629
  if (using[key].startsWith('plugin://'))
299
630
  continue;
300
631
  const componentPath = using[key];
301
- using[key] = path.join(this.root, componentPath);
632
+ // 非三方库的路径需要处理
633
+ if (!this.isThirdPartyLib(componentPath, this.root)) {
634
+ using[key] = path.join(this.root, componentPath);
635
+ }
302
636
  }
303
637
  this.entryUsingComponents = using;
304
638
  delete this.entryJSON.usingComponents;
@@ -329,10 +663,10 @@ class Convertor {
329
663
  if (!subPackages || !subPackages.length) {
330
664
  return;
331
665
  }
332
- subPackages.forEach(item => {
666
+ subPackages.forEach((item) => {
333
667
  if (item.pages && item.pages.length) {
334
668
  const root = item.root;
335
- item.pages.forEach(page => {
669
+ item.pages.forEach((page) => {
336
670
  let pagePath = `${root}/${page}`;
337
671
  pagePath = pagePath.replace(/\/{2,}/g, '/');
338
672
  this.pages.add(pagePath);
@@ -347,7 +681,7 @@ class Convertor {
347
681
  const sitemapFilePath = path.join(this.root, sitemapLocation);
348
682
  if (helper_1.fs.existsSync(sitemapFilePath)) {
349
683
  const outputFilePath = path.join(this.convertRoot, sitemapLocation);
350
- this.copyFileToTaro(sitemapFilePath, outputFilePath);
684
+ (0, util_1.copyFileToTaro)(sitemapFilePath, outputFilePath);
351
685
  }
352
686
  }
353
687
  }
@@ -356,32 +690,49 @@ class Convertor {
356
690
  return;
357
691
  }
358
692
  if (files.size) {
359
- files.forEach(file => {
693
+ files.forEach((file) => {
694
+ var _a, _b;
695
+ // 处理三方库引用,可在convert.config.json中nodePath字段自定义配置配置,默认node_modules
696
+ if (!path.isAbsolute(file)) {
697
+ (0, util_1.handleThirdPartyLib)(file, (_a = this.convertConfig) === null || _a === void 0 ? void 0 : _a.nodePath, this.root, this.convertRoot);
698
+ return;
699
+ }
360
700
  if (!helper_1.fs.existsSync(file) || this.hadBeenCopyedFiles.has(file)) {
361
701
  return;
362
702
  }
363
- const code = helper_1.fs.readFileSync(file).toString();
364
- let outputFilePath = file.replace(this.root, this.convertDir);
365
- const extname = path.extname(outputFilePath);
366
- if (/\.wxs/.test(extname)) {
367
- outputFilePath += '.js';
703
+ // 处理不转换的目录,可在convert.config.json中external字段配置
704
+ const matchUnconvertDir = (0, util_1.getMatchUnconvertDir)(file, (_b = this.convertConfig) === null || _b === void 0 ? void 0 : _b.external);
705
+ if (matchUnconvertDir !== null) {
706
+ (0, util_1.handleUnconvertDir)(matchUnconvertDir, this.root, this.convertDir);
707
+ return;
708
+ }
709
+ try {
710
+ const code = helper_1.fs.readFileSync(file).toString();
711
+ let outputFilePath = file.replace(this.isTsProject ? this.miniprogramRoot : this.root, this.convertDir);
712
+ const extname = path.extname(outputFilePath);
713
+ if (/\.wxs/.test(extname)) {
714
+ outputFilePath += '.js';
715
+ }
716
+ const transformResult = (0, transformer_wx_1.default)({
717
+ code,
718
+ sourcePath: file,
719
+ isNormal: true,
720
+ isTyped: helper_1.REG_TYPESCRIPT.test(file),
721
+ });
722
+ const { ast, scriptFiles } = this.parseAst({
723
+ ast: transformResult.ast,
724
+ outputFilePath,
725
+ sourceFilePath: file,
726
+ });
727
+ const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
728
+ this.writeFileToTaro(outputFilePath, prettier.format(jsCode, prettierJSConfig));
729
+ (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, 'JS 文件', this.generateShowPath(outputFilePath));
730
+ this.hadBeenCopyedFiles.add(file);
731
+ this.generateScriptFiles(scriptFiles);
732
+ }
733
+ catch (error) {
734
+ console.log(`转换文件${file}异常,errorMessage:${error}`);
368
735
  }
369
- const transformResult = (0, transformer_wx_1.default)({
370
- code,
371
- sourcePath: file,
372
- isNormal: true,
373
- isTyped: helper_1.REG_TYPESCRIPT.test(file)
374
- });
375
- const { ast, scriptFiles } = this.parseAst({
376
- ast: transformResult.ast,
377
- outputFilePath,
378
- sourceFilePath: file
379
- });
380
- const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
381
- this.writeFileToTaro(outputFilePath, prettier.format(jsCode, prettierJSConfig));
382
- (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, 'JS 文件', this.generateShowPath(outputFilePath));
383
- this.hadBeenCopyedFiles.add(file);
384
- this.generateScriptFiles(scriptFiles);
385
736
  });
386
737
  }
387
738
  }
@@ -389,19 +740,19 @@ class Convertor {
389
740
  helper_1.fs.ensureDirSync(path.dirname(dist));
390
741
  helper_1.fs.writeFileSync(dist, code);
391
742
  }
392
- copyFileToTaro(from, to, options) {
393
- const filename = path.basename(from);
394
- if (helper_1.fs.statSync(from).isFile() && !path.extname(to)) {
395
- helper_1.fs.ensureDir(to);
396
- return helper_1.fs.copySync(from, path.join(to, filename), options);
397
- }
398
- helper_1.fs.ensureDir(path.dirname(to));
399
- return helper_1.fs.copySync(from, to, options);
743
+ // 自定义组件,如果组件文件命名为index,引入时可省略index这一层,解析时需加上
744
+ getComponentPath(component, extname) {
745
+ if (helper_1.fs.existsSync(component + extname))
746
+ return component + extname;
747
+ else
748
+ return component + '/index' + extname;
400
749
  }
401
750
  getDistFilePath(src, extname) {
402
751
  if (!extname)
403
- return src.replace(this.root, this.convertDir);
404
- return src.replace(this.root, this.convertDir).replace(path.extname(src), extname);
752
+ return src.replace(this.isTsProject ? this.miniprogramRoot : this.root, this.convertDir);
753
+ return src
754
+ .replace(this.isTsProject ? this.miniprogramRoot : this.root, this.convertDir)
755
+ .replace(path.extname(src), extname);
405
756
  }
406
757
  getConfigFilePath(src) {
407
758
  const { dir, name } = path.parse(src);
@@ -413,10 +764,7 @@ class Convertor {
413
764
  this.writeFileToTaro(configSrc, prettier.format(code, prettierJSConfig));
414
765
  }
415
766
  generateShowPath(filePath) {
416
- return filePath
417
- .replace(path.join(this.root, '/'), '')
418
- .split(path.sep)
419
- .join('/');
767
+ return filePath.replace(path.join(this.root, '/'), '').split(path.sep).join('/');
420
768
  }
421
769
  formatFile(jsCode, template = '') {
422
770
  let code = jsCode;
@@ -442,10 +790,12 @@ ${code}
442
790
  const taroizeResult = taroize({
443
791
  json: entryJSON,
444
792
  script: entryJS,
793
+ scriptPath: this.entryJSPath,
445
794
  path: this.root,
446
795
  rootPath: this.root,
447
796
  framework: this.framework,
448
- isApp: true
797
+ isApp: true,
798
+ logFilePath: global_1.globals.logFilePath,
449
799
  });
450
800
  const { ast, scriptFiles } = this.parseAst({
451
801
  ast: taroizeResult.ast,
@@ -454,7 +804,7 @@ ${code}
454
804
  importStylePath: this.entryStyle
455
805
  ? this.entryStylePath.replace(path.extname(this.entryStylePath), OUTPUT_STYLE_EXTNAME)
456
806
  : null,
457
- isApp: true
807
+ isApp: true,
458
808
  });
459
809
  const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
460
810
  this.writeFileToTaro(entryDistJSPath, jsCode);
@@ -477,7 +827,7 @@ ${code}
477
827
  const { list = [] } = tabBar;
478
828
  const icons = new Set();
479
829
  if (Array.isArray(list) && list.length) {
480
- list.forEach(item => {
830
+ list.forEach((item) => {
481
831
  if (typeof item.iconPath === 'string')
482
832
  icons.add(item.iconPath);
483
833
  if (typeof item.selectedIconPath === 'string')
@@ -485,10 +835,10 @@ ${code}
485
835
  });
486
836
  if (icons.size > 0) {
487
837
  Array.from(icons)
488
- .map(icon => path.join(this.root, icon))
489
- .forEach(iconPath => {
838
+ .map((icon) => path.join(this.root, icon))
839
+ .forEach((iconPath) => {
490
840
  const iconDistPath = this.getDistFilePath(iconPath);
491
- this.copyFileToTaro(iconPath, iconDistPath);
841
+ (0, util_1.copyFileToTaro)(iconPath, iconDistPath);
492
842
  (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, 'TabBar 图标', this.generateShowPath(iconDistPath));
493
843
  });
494
844
  }
@@ -500,7 +850,7 @@ ${code}
500
850
  const customTabbarPath = path.join(this.root, 'custom-tab-bar');
501
851
  if (helper_1.fs.existsSync(customTabbarPath)) {
502
852
  const customTabbarDistPath = this.getDistFilePath(customTabbarPath);
503
- this.copyFileToTaro(customTabbarPath, customTabbarDistPath);
853
+ (0, util_1.copyFileToTaro)(customTabbarPath, customTabbarDistPath);
504
854
  (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, '自定义 TabBar', this.generateShowPath(customTabbarDistPath));
505
855
  }
506
856
  }
@@ -510,9 +860,52 @@ ${code}
510
860
  }
511
861
  return path.join(path.dirname(file), path.basename(file, path.extname(file)) + '.vue');
512
862
  }
863
+ // 判断是否是三方库
864
+ isThirdPartyLib(modulePath, curPageDir) {
865
+ // 相对路径和带根目录的路径都不是三方库
866
+ if (modulePath.indexOf('.') === 0 || modulePath.indexOf('/') === 0 || modulePath.indexOf(this.root) !== -1) {
867
+ return false;
868
+ }
869
+ // 通过格式如component/component引用组件
870
+ // app.json中引用组件
871
+ if (curPageDir === this.root) {
872
+ if (helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(path.join(curPageDir, modulePath)))) {
873
+ return false;
874
+ }
875
+ }
876
+ else {
877
+ // 页面中引用组件
878
+ if (helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(path.join(curPageDir, modulePath))) ||
879
+ helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(path.join(this.root, modulePath)))) {
880
+ return false;
881
+ }
882
+ }
883
+ return true;
884
+ }
885
+ // 判断三方库是否安装
886
+ isInNodeModule(modulePath) {
887
+ const nodeModules = path.resolve(this.root, 'node_modules');
888
+ if (!helper_1.fs.existsSync(nodeModules)) {
889
+ return false;
890
+ }
891
+ const modules = helper_1.fs.readdirSync(nodeModules);
892
+ const parts = modulePath.split('/');
893
+ if (modules.indexOf(parts[0]) === -1) {
894
+ return false;
895
+ }
896
+ return true;
897
+ }
513
898
  traversePages() {
514
- this.pages.forEach(page => {
515
- const pagePath = path.join(this.root, page);
899
+ this.pages.forEach((page) => {
900
+ var _a;
901
+ (0, util_1.printToLogFile)(`开始转换页面 ${page} ${(0, util_1.getLineBreak)()}`);
902
+ const pagePath = this.isTsProject ? path.join(this.miniprogramRoot, page) : path.join(this.root, page);
903
+ // 处理不转换的页面,可在convert.config.json中external字段配置
904
+ const matchUnconvertDir = (0, util_1.getMatchUnconvertDir)(pagePath, (_a = this.convertConfig) === null || _a === void 0 ? void 0 : _a.external);
905
+ if (matchUnconvertDir !== null) {
906
+ (0, util_1.handleUnconvertDir)(matchUnconvertDir, this.root, this.convertDir);
907
+ return;
908
+ }
516
909
  const pageJSPath = pagePath + this.fileTypes.SCRIPT;
517
910
  const pageDistJSPath = this.getDistFilePath(pageJSPath);
518
911
  const pageConfigPath = pagePath + this.fileTypes.CONFIG;
@@ -542,11 +935,15 @@ ${code}
542
935
  if (pageUsingComponents) {
543
936
  // 页面依赖组件
544
937
  const usingComponents = {};
545
- Object.keys(pageUsingComponents).forEach(component => {
938
+ Object.keys(pageUsingComponents).forEach((component) => {
939
+ var _a;
546
940
  const unResolveComponentPath = pageUsingComponents[component];
547
941
  if (unResolveComponentPath.startsWith('plugin://')) {
548
942
  usingComponents[component] = unResolveComponentPath;
549
943
  }
944
+ else if (this.isThirdPartyLib(unResolveComponentPath, path.resolve(pagePath, '..'))) {
945
+ (0, util_1.handleThirdPartyLib)(unResolveComponentPath, (_a = this.convertConfig) === null || _a === void 0 ? void 0 : _a.nodePath, this.root, this.convertRoot);
946
+ }
550
947
  else {
551
948
  let componentPath;
552
949
  if (unResolveComponentPath.startsWith(this.root)) {
@@ -554,13 +951,14 @@ ${code}
554
951
  }
555
952
  else {
556
953
  componentPath = path.resolve(pageConfigPath, '..', pageUsingComponents[component]);
954
+ // 支持将组件库放在工程根目录下
557
955
  if (!helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(componentPath))) {
558
956
  componentPath = path.join(this.root, pageUsingComponents[component]);
559
957
  }
560
958
  }
561
959
  depComponents.add({
562
960
  name: component,
563
- path: componentPath
961
+ path: componentPath,
564
962
  });
565
963
  }
566
964
  });
@@ -574,6 +972,7 @@ ${code}
574
972
  param.json = JSON.stringify(pageConfig);
575
973
  }
576
974
  param.script = String(helper_1.fs.readFileSync(pageJSPath));
975
+ param.scriptPath = pageJSPath;
577
976
  if (helper_1.fs.existsSync(pageTemplPath)) {
578
977
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '页面模板', this.generateShowPath(pageTemplPath));
579
978
  param.wxml = String(helper_1.fs.readFileSync(pageTemplPath));
@@ -585,6 +984,7 @@ ${code}
585
984
  }
586
985
  param.path = path.dirname(pageJSPath);
587
986
  param.rootPath = this.root;
987
+ param.logFilePath = global_1.globals.logFilePath;
588
988
  const taroizeResult = taroize(Object.assign(Object.assign({}, param), { framework: this.framework }));
589
989
  const { ast, scriptFiles } = this.parseAst({
590
990
  ast: taroizeResult.ast,
@@ -592,10 +992,11 @@ ${code}
592
992
  outputFilePath: pageDistJSPath,
593
993
  importStylePath: pageStyle ? pageStylePath.replace(path.extname(pageStylePath), OUTPUT_STYLE_EXTNAME) : null,
594
994
  depComponents,
595
- imports: taroizeResult.imports
995
+ imports: taroizeResult.imports,
596
996
  });
597
997
  const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
598
998
  this.writeFileToTaro(this.getComponentDest(pageDistJSPath), this.formatFile(jsCode, taroizeResult.template));
999
+ (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, 'writeFileToTaro', this.generateShowPath(pageDistJSPath));
599
1000
  this.writeFileToConfig(pageDistJSPath, param.json);
600
1001
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '页面文件', this.generateShowPath(pageDistJSPath));
601
1002
  if (pageStyle) {
@@ -607,6 +1008,7 @@ ${code}
607
1008
  catch (err) {
608
1009
  (0, helper_1.printLog)("error" /* processTypeEnum.ERROR */, '页面转换', this.generateShowPath(pageJSPath));
609
1010
  console.log(err);
1011
+ (0, util_1.printToLogFile)(`转换页面异常 ${err.stack} ${(0, util_1.getLineBreak)()}`);
610
1012
  }
611
1013
  });
612
1014
  }
@@ -614,21 +1016,21 @@ ${code}
614
1016
  if (!components || !components.size) {
615
1017
  return;
616
1018
  }
617
- components.forEach(componentObj => {
1019
+ components.forEach((componentObj) => {
618
1020
  const component = componentObj.path;
619
1021
  if (this.hadBeenBuiltComponents.has(component))
620
1022
  return;
621
1023
  this.hadBeenBuiltComponents.add(component);
622
- const componentJSPath = component + this.fileTypes.SCRIPT;
1024
+ const componentJSPath = this.getComponentPath(component, this.fileTypes.SCRIPT);
623
1025
  const componentDistJSPath = this.getDistFilePath(componentJSPath);
624
- const componentConfigPath = component + this.fileTypes.CONFIG;
625
- const componentStylePath = component + this.fileTypes.STYLE;
626
- const componentTemplPath = component + this.fileTypes.TEMPL;
1026
+ const componentConfigPath = this.getComponentPath(component, this.fileTypes.CONFIG);
1027
+ const componentStylePath = this.getComponentPath(component, this.fileTypes.STYLE);
1028
+ const componentTemplPath = this.getComponentPath(component, this.fileTypes.TEMPL);
627
1029
  try {
628
1030
  const param = {};
629
1031
  const depComponents = new Set();
630
1032
  if (!helper_1.fs.existsSync(componentJSPath)) {
631
- throw new Error(`组件 ${component} 没有 JS 文件!`);
1033
+ throw new Error(`自定义组件 ${component} 没有 JS 文件!`);
632
1034
  }
633
1035
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '组件文件', this.generateShowPath(componentJSPath));
634
1036
  if (helper_1.fs.existsSync(componentConfigPath)) {
@@ -638,14 +1040,17 @@ ${code}
638
1040
  const componentUsingComponnets = componentConfig.usingComponents;
639
1041
  if (componentUsingComponnets) {
640
1042
  // 页面依赖组件
641
- Object.keys(componentUsingComponnets).forEach(component => {
1043
+ Object.keys(componentUsingComponnets).forEach((component) => {
642
1044
  let componentPath = path.resolve(componentConfigPath, '..', componentUsingComponnets[component]);
643
1045
  if (!helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(componentPath))) {
644
1046
  componentPath = path.join(this.root, componentUsingComponnets[component]);
645
1047
  }
1048
+ if (!helper_1.fs.existsSync(componentPath + this.fileTypes.SCRIPT)) {
1049
+ componentPath = path.join(componentPath, `/index`);
1050
+ }
646
1051
  depComponents.add({
647
1052
  name: component,
648
- path: componentPath
1053
+ path: componentPath,
649
1054
  });
650
1055
  });
651
1056
  delete componentConfig.usingComponents;
@@ -664,6 +1069,7 @@ ${code}
664
1069
  }
665
1070
  param.path = path.dirname(componentJSPath);
666
1071
  param.rootPath = this.root;
1072
+ param.logFilePath = global_1.globals.logFilePath;
667
1073
  const taroizeResult = taroize(Object.assign(Object.assign({}, param), { framework: this.framework }));
668
1074
  const { ast, scriptFiles } = this.parseAst({
669
1075
  ast: taroizeResult.ast,
@@ -673,7 +1079,7 @@ ${code}
673
1079
  ? componentStylePath.replace(path.extname(componentStylePath), OUTPUT_STYLE_EXTNAME)
674
1080
  : null,
675
1081
  depComponents,
676
- imports: taroizeResult.imports
1082
+ imports: taroizeResult.imports,
677
1083
  });
678
1084
  const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
679
1085
  this.writeFileToTaro(this.getComponentDest(componentDistJSPath), this.formatFile(jsCode, taroizeResult.template));
@@ -693,7 +1099,7 @@ ${code}
693
1099
  styleUnitTransform(filePath, content) {
694
1100
  return __awaiter(this, void 0, void 0, function* () {
695
1101
  const postcssResult = yield (0, postcss_1.default)([unitTransform()]).process(content, {
696
- from: filePath
1102
+ from: filePath,
697
1103
  });
698
1104
  return postcssResult;
699
1105
  });
@@ -705,10 +1111,7 @@ ${code}
705
1111
  styleDist = path.dirname(styleDist);
706
1112
  while (token === null || token === void 0 ? void 0 : token.length) {
707
1113
  let url = token[1];
708
- if (url &&
709
- url.indexOf('data:') !== 0 &&
710
- url.indexOf('#') !== 0 &&
711
- !(/^[a-z]+:\/\//.test(url))) {
1114
+ if (url && url.indexOf('data:') !== 0 && url.indexOf('#') !== 0 && !/^[a-z]+:\/\//.test(url)) {
712
1115
  url = url.trim();
713
1116
  url.replace(/[/\\]/g, path.sep);
714
1117
  url = url.split('?')[0];
@@ -743,7 +1146,7 @@ ${code}
743
1146
  this.writeFileToTaro(styleDist, css);
744
1147
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '样式文件', this.generateShowPath(styleDist));
745
1148
  if (imports && imports.length) {
746
- imports.forEach(importItem => {
1149
+ imports.forEach((importItem) => {
747
1150
  const importPath = path.isAbsolute(importItem)
748
1151
  ? path.join(this.root, importItem)
749
1152
  : path.resolve(path.dirname(filePath), importItem);
@@ -773,44 +1176,48 @@ ${code}
773
1176
  typescript: false,
774
1177
  template: templateName,
775
1178
  framework: this.framework,
776
- compiler: 'webpack5'
1179
+ compiler: 'webpack5',
777
1180
  });
778
1181
  creator.template(templateName, path.join('config', 'index.js'), path.join(configDir, 'index.js'), {
779
1182
  date,
780
1183
  projectName,
781
1184
  framework: this.framework,
782
- compiler: 'webpack5'
1185
+ compiler: 'webpack5',
1186
+ typescript: false,
783
1187
  });
784
1188
  creator.template(templateName, path.join('config', 'dev.js'), path.join(configDir, 'dev.js'), {
785
- framework: this.framework
1189
+ framework: this.framework,
1190
+ compiler: 'webpack5',
1191
+ typescript: false,
786
1192
  });
787
1193
  creator.template(templateName, path.join('config', 'prod.js'), path.join(configDir, 'prod.js'), {
788
- framework: this.framework
1194
+ framework: this.framework,
1195
+ typescript: false,
789
1196
  });
790
1197
  creator.template(templateName, 'project.config.json', path.join(this.convertRoot, 'project.config.json'), {
791
1198
  description,
792
1199
  projectName,
793
- framework: this.framework
1200
+ framework: this.framework,
794
1201
  });
795
1202
  creator.template(templateName, '.gitignore', path.join(this.convertRoot, '.gitignore'));
796
1203
  creator.template(templateName, '.editorconfig', path.join(this.convertRoot, '.editorconfig'));
797
1204
  creator.template(templateName, '.eslintrc.js', path.join(this.convertRoot, '.eslintrc.js'), {
798
1205
  typescript: false,
799
- framework: this.framework
1206
+ framework: this.framework,
800
1207
  });
801
1208
  creator.template(templateName, 'babel.config.js', path.join(this.convertRoot, 'babel.config.js'), {
802
1209
  typescript: false,
803
- framework: this.framework
1210
+ framework: this.framework,
804
1211
  });
805
1212
  creator.template(templateName, path.join('src', 'index.html'), path.join(this.convertDir, 'index.html'), {
806
- projectName
1213
+ projectName,
807
1214
  });
808
1215
  creator.fs.commit(() => {
809
1216
  const pkgObj = JSON.parse(helper_1.fs.readFileSync(pkgPath).toString());
810
1217
  pkgObj.dependencies['@tarojs/with-weapp'] = `^${version}`;
811
1218
  helper_1.fs.writeJSONSync(pkgPath, pkgObj, {
812
1219
  spaces: 2,
813
- EOL: '\n'
1220
+ EOL: '\n',
814
1221
  });
815
1222
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(configDir, 'index.js')));
816
1223
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(configDir, 'dev.js')));
@@ -824,15 +1231,27 @@ ${code}
824
1231
  this.showLog();
825
1232
  });
826
1233
  }
1234
+ /**
1235
+ * generateReport: 为转换后的 taroConvert 工程添加转换报告
1236
+ */
1237
+ generateReport() {
1238
+ const reportDir = path.join(this.convertRoot, 'report');
1239
+ const reportBundleFilePath = path.resolve(__dirname, '../', 'report/bundle.js');
1240
+ const reportIndexFilePath = path.resolve(__dirname, '../', 'report/report.html');
1241
+ (0, util_1.generateReportFile)(reportBundleFilePath, reportDir, 'bundle.js', this.reportErroMsg);
1242
+ (0, util_1.generateReportFile)(reportIndexFilePath, reportDir, 'report.html');
1243
+ }
827
1244
  showLog() {
828
1245
  console.log();
829
1246
  console.log(`${helper_1.chalk.green('✔ ')} 转换成功,请进入 ${helper_1.chalk.bold('taroConvert')} 目录下使用 npm 或者 yarn 安装项目依赖后再运行!`);
1247
+ console.log(`转换报告已生成,请在浏览器中打开 ${path.join(this.convertRoot, 'report', 'report.html')} 查看转换报告`);
830
1248
  }
831
1249
  run() {
832
1250
  this.framework = 'react';
833
1251
  this.generateEntry();
834
1252
  this.traversePages();
835
1253
  this.generateConfigFiles();
1254
+ this.generateReport();
836
1255
  }
837
1256
  }
838
1257
  exports.default = Convertor;