@tarojs/cli-convertor 3.8.0-canary.0 → 3.8.0-canary.1

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,11 +9,14 @@ 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");
16
+ const binding_1 = require("@tarojs/binding");
15
17
  const cli_1 = require("@tarojs/cli");
16
18
  const helper_1 = require("@tarojs/helper");
19
+ const shared_1 = require("@tarojs/shared");
17
20
  const taroize = require("@tarojs/taroize");
18
21
  const transformer_wx_1 = require("@tarojs/transformer-wx");
19
22
  const path = require("path");
@@ -22,10 +25,11 @@ const unitTransform = require("postcss-taro-unit-transform");
22
25
  const prettier = require("prettier");
23
26
  const util_1 = require("./util");
24
27
  const astConvert_1 = require("./util/astConvert");
28
+ const global_1 = require("./util/global");
25
29
  const prettierJSConfig = {
26
30
  semi: false,
27
31
  singleQuote: true,
28
- parser: 'babel'
32
+ parser: 'babel',
29
33
  };
30
34
  const babylonConfig = {
31
35
  sourceType: 'module',
@@ -36,19 +40,18 @@ const babylonConfig = {
36
40
  'asyncGenerators',
37
41
  'objectRestSpread',
38
42
  'decorators',
39
- 'dynamicImport'
40
- ]
43
+ 'dynamicImport',
44
+ ],
41
45
  };
42
46
  const OUTPUT_STYLE_EXTNAME = '.scss';
43
- const WX_GLOBAL_FN = new Set(['getApp', 'getCurrentPages', 'requirePlugin', 'Behavior']);
47
+ const WX_GLOBAL_FN = new Set(['getApp', 'getCurrentPages', 'Behavior']);
44
48
  function processStyleImports(content, processFn) {
45
- const style = [];
46
- const imports = [];
49
+ // 获取css中的引用样式文件路径集合
50
+ const imports = (0, util_1.getWxssImports)(content);
51
+ // 将引用的样式文件路径转换为相对路径,后缀名转换为.scss
47
52
  const styleReg = new RegExp('.wxss');
48
53
  content = content.replace(helper_1.CSS_IMPORT_REG, (m, _$1, $2) => {
49
54
  if (styleReg.test($2)) {
50
- style.push(m);
51
- imports.push($2);
52
55
  if (processFn) {
53
56
  return processFn(m, $2);
54
57
  }
@@ -61,57 +64,229 @@ function processStyleImports(content, processFn) {
61
64
  });
62
65
  return {
63
66
  content,
64
- style,
65
- imports
67
+ imports,
66
68
  };
67
69
  }
68
70
  class Convertor {
69
- constructor(root) {
71
+ constructor(root, isTsProject) {
70
72
  this.wxsIncrementId = (0, util_1.incrementId)();
71
73
  this.root = root;
72
74
  this.convertRoot = path.join(this.root, 'taroConvert');
73
75
  this.convertDir = path.join(this.convertRoot, 'src');
74
76
  this.importsDir = path.join(this.convertDir, 'imports');
77
+ this.isTsProject = isTsProject;
78
+ if (isTsProject) {
79
+ this.miniprogramRoot = path.join(this.root, 'miniprogram');
80
+ }
75
81
  this.fileTypes = {
76
82
  TEMPL: '.wxml',
77
83
  STYLE: '.wxss',
78
84
  CONFIG: '.json',
79
- SCRIPT: '.js'
85
+ SCRIPT: isTsProject ? '.ts' : '.js',
80
86
  };
81
87
  this.pages = new Set();
82
88
  this.components = new Set();
83
89
  this.hadBeenCopyedFiles = new Set();
84
90
  this.hadBeenBuiltComponents = new Set();
85
91
  this.hadBeenBuiltImports = new Set();
92
+ this.projectConfig = { pluginRoot: '', compileType: '' };
93
+ this.pluginInfo = {
94
+ pluginRoot: '',
95
+ pluginName: '',
96
+ pages: new Set(),
97
+ pagesMap: new Map(),
98
+ publicComponents: new Set(),
99
+ entryFilePath: '',
100
+ };
86
101
  this.init();
87
102
  }
88
103
  init() {
89
104
  console.log(helper_1.chalk.green('开始代码转换...'));
90
- this.initConvert();
91
- this.getApp();
92
- this.getPages();
93
- this.getSitemapLocation();
94
- this.getSubPackages();
105
+ try {
106
+ this.initConvert();
107
+ this.getApp();
108
+ this.getPages();
109
+ this.getSitemapLocation();
110
+ this.getSubPackages();
111
+ }
112
+ catch (error) {
113
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] init - 初始化异常 ${(0, util_1.getLineBreak)()}${error} ${(0, util_1.getLineBreak)()}`);
114
+ (0, util_1.printToLogFile)();
115
+ throw new Error(`初始化失败 ${(0, util_1.getLineBreak)()} ${error.message}`);
116
+ }
95
117
  }
96
118
  initConvert() {
97
- if (helper_1.fs.existsSync(this.convertRoot)) {
98
- (0, helper_1.emptyDirectory)(this.convertRoot, { excludes: ['node_modules'] });
119
+ try {
120
+ // 清空taroConvert目录,保留taroConvert下node_modules目录
121
+ if (helper_1.fs.existsSync(this.convertRoot)) {
122
+ (0, helper_1.emptyDirectory)(this.convertRoot, { excludes: ['node_modules'] });
123
+ }
124
+ else {
125
+ helper_1.fs.ensureDirSync(this.convertRoot);
126
+ }
127
+ // 创建.convert目录,存放转换中间数据,如日志数据
128
+ (0, util_1.generateDir)(path.join(this.convertRoot, '.convert'));
129
+ global_1.globals.logFilePath = path.join(this.convertRoot, '.convert', 'convert.log');
130
+ // 转换自定义配置文件,如:tsconfig.json
131
+ this.convertSelfDefinedConfig();
132
+ // 读取convert.config.json配置文件
133
+ this.getConvertConfig();
134
+ // 读取project.config.json文件
135
+ this.parseProjectConfig();
136
+ // 解析插件的配置信息
137
+ if (this.projectConfig.compileType === "plugin" /* Constants.PLUGIN */) {
138
+ this.parsePluginConfig(this.pluginInfo);
139
+ }
99
140
  }
100
- else {
101
- helper_1.fs.ensureDirSync(this.convertRoot);
141
+ catch (error) {
142
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] init - 初始化convert异常 ${(0, util_1.getLineBreak)()}${error} ${(0, util_1.getLineBreak)()}`);
143
+ throw new Error(`初始化convert失败 ${(0, util_1.getLineBreak)()} ${error.message}`);
102
144
  }
103
145
  }
104
- parseAst({ ast, sourceFilePath, outputFilePath, importStylePath, depComponents, imports = [] }) {
146
+ /**
147
+ * 遍历AST,为元素或方法可能为undefined的数据添加可选链操作符
148
+ * @param ast
149
+ */
150
+ convertToOptional(ast) {
151
+ // 需要添加可选链运算符的数据
152
+ const optionalData = new Set();
153
+ const thisData = new Set();
154
+ (0, traverse_1.default)(ast, {
155
+ ObjectProperty(astPath) {
156
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] convertToOptional - 解析ObjectProperty ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
157
+ // xxx({ data: {...} }),获取data属性中符合的数据
158
+ const node = astPath.node;
159
+ const key = node.key;
160
+ if (!t.isIdentifier(key) || key.name !== 'data') {
161
+ return;
162
+ }
163
+ const value = node.value;
164
+ if (!t.isObjectExpression(value)) {
165
+ return;
166
+ }
167
+ const properties = value.properties;
168
+ properties.forEach((property) => {
169
+ if (!t.isObjectProperty(property)) {
170
+ return;
171
+ }
172
+ const key = property.key;
173
+ if (!t.isIdentifier(key)) {
174
+ return;
175
+ }
176
+ const data = key.name;
177
+ thisData.add(data);
178
+ // 数据初始化为undefined、空字符串''、空数组[],收集
179
+ const assign = property.value;
180
+ const isUndefined = t.isIdentifier(assign) && assign.name === 'undefined';
181
+ const isEmptyString = t.isStringLiteral(assign) && assign.value === '';
182
+ const isEmptyArray = t.isArrayExpression(assign) && assign.elements.length === 0;
183
+ if (isUndefined || isEmptyString || isEmptyArray) {
184
+ optionalData.add(data);
185
+ }
186
+ });
187
+ },
188
+ CallExpression(astPath) {
189
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] convertToOptional - 解析CallExpression ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
190
+ // 用setData进行初始化的数据
191
+ const node = astPath.node;
192
+ const callee = node.callee;
193
+ if (!t.isMemberExpression(callee)) {
194
+ return;
195
+ }
196
+ const property = callee.property;
197
+ if (!t.isIdentifier(property) || property.name !== 'setData') {
198
+ return;
199
+ }
200
+ if (node.arguments.length === 0) {
201
+ return;
202
+ }
203
+ const arg = node.arguments[0];
204
+ // 除去data中的数据,setData中其余全部的数据都收集
205
+ if (arg.type === 'ObjectExpression') {
206
+ arg.properties.forEach((property) => {
207
+ if (!t.isObjectProperty(property)) {
208
+ return;
209
+ }
210
+ const key = property.key;
211
+ if (!t.isIdentifier(key)) {
212
+ return;
213
+ }
214
+ const data = key.name;
215
+ if (thisData.has(data)) {
216
+ return;
217
+ }
218
+ optionalData.add(data);
219
+ });
220
+ }
221
+ },
222
+ ClassBody(astPath) {
223
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] convertToOptional - 解析ClassBody ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
224
+ astPath.traverse({
225
+ MemberExpression(path) {
226
+ var _a, _b, _c;
227
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] convertToOptional - 解析MemberExpression ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
228
+ // 遇到成员表达式,抽取表达式的来源数据
229
+ const code = path.toString();
230
+ const optionMatch = (_a = code.match(/^(.*?)\./)) === null || _a === void 0 ? void 0 : _a[1];
231
+ let data;
232
+ if (optionMatch) {
233
+ const computedMatch = (_b = optionMatch.match(/^(.*?)\[/)) === null || _b === void 0 ? void 0 : _b[1];
234
+ data = computedMatch || optionMatch;
235
+ }
236
+ else {
237
+ const computedMatch = (_c = code.match(/^(.*?)\[/)) === null || _c === void 0 ? void 0 : _c[1];
238
+ if (!computedMatch) {
239
+ return;
240
+ }
241
+ data = computedMatch;
242
+ }
243
+ // 如果数据不需要添加可选链操作符,返回
244
+ if (!optionalData.has(data)) {
245
+ return;
246
+ }
247
+ // 利用正则表达式匹配,添加可选链操作符
248
+ const parentPath = path.parentPath;
249
+ if (parentPath.isCallExpression()) {
250
+ path.replaceWithSourceString(code.replace(/\./g, '?.').replace(/\[/g, '?.['));
251
+ const callee = parentPath.node.callee;
252
+ const args = parentPath.node.arguments;
253
+ parentPath.replaceWith(t.optionalCallExpression(callee, args, false));
254
+ }
255
+ else {
256
+ path.replaceWithSourceString(code.replace(/\./g, '?.').replace(/\[/g, '?.['));
257
+ }
258
+ },
259
+ });
260
+ },
261
+ });
262
+ }
263
+ parseAst({ ast, sourceFilePath, outputFilePath, importStylePath, depComponents, imports = [], pluginComponents, }) {
264
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 入参 ${(0, util_1.getLineBreak)()}${JSON.stringify({
265
+ sourceFilePath,
266
+ outputFilePath,
267
+ importStylePath,
268
+ depComponents,
269
+ imports,
270
+ pluginComponents,
271
+ })} ${(0, util_1.getLineBreak)()}`);
105
272
  const scriptFiles = new Set();
106
273
  // eslint-disable-next-line @typescript-eslint/no-this-alias
107
274
  const self = this;
275
+ // 转换后js页面的所有自定义标签
276
+ const scriptComponents = [];
277
+ // js页面所有的导入模块
278
+ const scriptImports = [];
108
279
  let componentClassName;
109
280
  let needInsertImportTaro = false;
281
+ let hasCacheOptionsRequired = false;
282
+ let hasDatasetRequired = false;
283
+ const set = new Set();
110
284
  (0, traverse_1.default)(ast, {
111
285
  Program: {
112
286
  enter(astPath) {
113
287
  astPath.traverse({
114
288
  ClassDeclaration(astPath) {
289
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析ClassDeclaration ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
115
290
  const node = astPath.node;
116
291
  let isTaroComponent = false;
117
292
  if (node.superClass) {
@@ -121,45 +296,48 @@ class Convertor {
121
296
  astPath.traverse({
122
297
  JSXElement() {
123
298
  isTaroComponent = true;
124
- }
299
+ },
125
300
  });
126
301
  }
127
- }
302
+ },
128
303
  });
129
304
  if (isTaroComponent) {
130
305
  componentClassName = node.id.name;
131
306
  }
132
307
  }
133
308
  },
134
- ClassExpression(astPath) {
135
- const node = astPath.node;
136
- if (node.superClass) {
137
- let isTaroComponent = false;
138
- astPath.traverse({
139
- ClassMethod(astPath) {
140
- if (astPath.get('key').isIdentifier({ name: 'render' })) {
141
- astPath.traverse({
142
- JSXElement() {
143
- isTaroComponent = true;
144
- }
145
- });
146
- }
147
- }
148
- });
149
- if (isTaroComponent) {
150
- if (node.id === null) {
151
- const parentNode = astPath.parentPath.node;
152
- if (t.isVariableDeclarator(astPath.parentPath)) {
153
- componentClassName = parentNode.id.name;
154
- }
155
- }
156
- else {
157
- componentClassName = node.id.name;
158
- }
159
- }
160
- }
161
- },
309
+ // ClassExpression (astPath) {
310
+ // updateLogFileContent(
311
+ // `INFO [taro-cli-convertor] parseAst - 解析ClassExpression ${getLineBreak()}${astPath} ${getLineBreak()}`
312
+ // )
313
+ // const node = astPath.node
314
+ // if (node.superClass) {
315
+ // let isTaroComponent = false
316
+ // astPath.traverse({
317
+ // ClassMethod (astPath) {
318
+ // if (astPath.get('key').isIdentifier({ name: 'render' })) {
319
+ // astPath.traverse({
320
+ // JSXElement () {
321
+ // isTaroComponent = true
322
+ // },
323
+ // })
324
+ // }
325
+ // },
326
+ // })
327
+ // if (isTaroComponent) {
328
+ // if (node.id === null) {
329
+ // const parentNode = astPath.parentPath.node as t.VariableDeclarator
330
+ // if (t.isVariableDeclarator(astPath.parentPath)) {
331
+ // componentClassName = (parentNode.id as t.Identifier).name
332
+ // }
333
+ // } else {
334
+ // componentClassName = node.id!.name
335
+ // }
336
+ // }
337
+ // }
338
+ // },
162
339
  ExportDefaultDeclaration(astPath) {
340
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析ExportDefaultDeclaration ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
163
341
  const node = astPath.node;
164
342
  const declaration = node.declaration;
165
343
  if (declaration && (declaration.type === 'ClassDeclaration' || declaration.type === 'ClassExpression')) {
@@ -172,10 +350,10 @@ class Convertor {
172
350
  astPath.traverse({
173
351
  JSXElement() {
174
352
  isTaroComponent = true;
175
- }
353
+ },
176
354
  });
177
355
  }
178
- }
356
+ },
179
357
  });
180
358
  if (isTaroComponent) {
181
359
  componentClassName = declaration.id.name;
@@ -184,46 +362,270 @@ class Convertor {
184
362
  }
185
363
  },
186
364
  ImportDeclaration(astPath) {
365
+ var _a;
366
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析ImportDeclaration ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
187
367
  const node = astPath.node;
188
368
  const source = node.source;
189
369
  const value = source.value;
190
- (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, source, value);
370
+ (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, source, value, self.isTsProject, self.pluginInfo.pluginName, (_a = self.entryJSON) === null || _a === void 0 ? void 0 : _a.resolveAlias);
371
+ // 获取导入语句中的所有导入名称(importName)并将其添加到scriptImports里面
372
+ const specifiers = node.specifiers;
373
+ specifiers.forEach((specifier) => {
374
+ const importName = specifier.local.name;
375
+ scriptImports.push(importName);
376
+ });
377
+ },
378
+ // export全部导入写法
379
+ ExportAllDeclaration(astPath) {
380
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析ExportAllDeclaration ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
381
+ const node = astPath.node;
382
+ const source = node.source;
383
+ const value = source.value;
384
+ (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, source, value, self.isTsProject, self.pluginInfo.pluginName);
385
+ },
386
+ // export部分导入写法
387
+ ExportNamedDeclaration(astPath) {
388
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析ExportNamedDeclaration ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
389
+ const node = astPath.node;
390
+ const source = node.source || '';
391
+ if (source) {
392
+ const value = source.value;
393
+ (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, source, value, self.isTsProject, self.pluginInfo.pluginName);
394
+ }
191
395
  },
192
396
  CallExpression(astPath) {
397
+ var _a, _b, _c, _d, _e;
398
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析CallExpression ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
193
399
  const node = astPath.node;
194
400
  const calleePath = astPath.get('callee');
195
401
  const callee = calleePath.node;
402
+ const args = astPath.get('arguments');
196
403
  if (callee.type === 'Identifier') {
197
404
  if (callee.name === 'require') {
198
405
  const args = node.arguments;
406
+ if (args.length === 0) {
407
+ // require()
408
+ return;
409
+ }
410
+ if (!t.isStringLiteral(args[0])) {
411
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] parseAst - require 暂不支持动态导入 ${(0, util_1.getLineBreak)()}filePath: ${sourceFilePath} ${(0, util_1.getLineBreak)()}context: ${astPath} ${(0, util_1.getLineBreak)()}`);
412
+ const position = {
413
+ col: ((_b = (_a = astPath.node.loc) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.column) || 0,
414
+ row: ((_d = (_c = astPath.node.loc) === null || _c === void 0 ? void 0 : _c.start) === null || _d === void 0 ? void 0 : _d.line) || 0,
415
+ };
416
+ throw new util_1.IReportError(`require暂不支持动态导入, filePath: ${sourceFilePath}, context: ${astPath}`, 'DynamicImportNotSupportedError', sourceFilePath, (0, util_1.astToCode)(astPath.node) || '', position);
417
+ }
199
418
  const value = args[0].value;
200
- (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, args[0], value);
419
+ (0, util_1.analyzeImportUrl)(self.root, sourceFilePath, scriptFiles, args[0], value, self.isTsProject, self.pluginInfo.pluginName, (_e = self.entryJSON) === null || _e === void 0 ? void 0 : _e.resolveAlias);
201
420
  }
202
421
  else if (WX_GLOBAL_FN.has(callee.name)) {
203
422
  calleePath.replaceWith(t.memberExpression(t.identifier('Taro'), callee));
204
423
  needInsertImportTaro = true;
205
424
  }
425
+ else if (callee.name === 'Page' || callee.name === 'Component' || callee.name === 'App') {
426
+ // 将 App() Page() Component() 改为 cacheOptions.setOptionsToCache() 的形式去初始化页面数据
427
+ const arg = astPath.get('arguments')[0];
428
+ const cacheOptionsAstNode = t.callExpression(t.memberExpression(t.identifier('cacheOptions'), t.identifier('setOptionsToCache')), [arg.node]);
429
+ astPath.replaceWith(cacheOptionsAstNode);
430
+ // 创建导入 cacheOptions 对象的 ast 节点
431
+ const requireCacheOptionsAst = t.variableDeclaration('const', [
432
+ t.variableDeclarator(t.objectPattern([
433
+ t.objectProperty(t.identifier('cacheOptions'), t.identifier('cacheOptions'), false, true),
434
+ ]), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
435
+ ]);
436
+ // 若已经引入过 cacheOptions 则不在引入,防止重复引入问题
437
+ if (!hasCacheOptionsRequired) {
438
+ ast.program.body.unshift(requireCacheOptionsAst);
439
+ hasCacheOptionsRequired = true;
440
+ }
441
+ }
442
+ else if (callee.name === 'requirePlugin') {
443
+ if (args.length === 1 && args[0].isStringLiteral()) {
444
+ // 在小程序中调用plugin中模块,相对路径需要使用转换后的
445
+ const pluginEntryFilePathTrans = self.pluginInfo.entryFilePath.replace(self.pluginInfo.pluginRoot, path.join(self.convertDir, self.pluginInfo.pluginName));
446
+ const sourceFilePathTarns = self.getDistFilePath(sourceFilePath);
447
+ const newRequire = t.callExpression(t.identifier('require'), [
448
+ t.stringLiteral((0, helper_1.normalizePath)(path.relative(path.dirname(sourceFilePathTarns), pluginEntryFilePathTrans))),
449
+ ]);
450
+ astPath.replaceWith(newRequire);
451
+ }
452
+ }
206
453
  }
207
454
  },
208
455
  MemberExpression(astPath) {
456
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析MemberExpression ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
209
457
  const node = astPath.node;
210
458
  const object = node.object;
459
+ const prettier = node.property;
211
460
  if (t.isIdentifier(object) && object.name === 'wx') {
212
461
  node.object = t.identifier('Taro');
213
462
  needInsertImportTaro = true;
214
463
  }
215
- }
464
+ else if (t.isIdentifier(prettier) && prettier.name === 'dataset') {
465
+ node.object = t.callExpression(t.identifier('getTarget'), [object, t.identifier('Taro')]);
466
+ // 创建导入 cacheOptions 对象的 ast 节点
467
+ if (!hasDatasetRequired) {
468
+ const requireCacheOptionsAst = t.variableDeclaration('const', [
469
+ t.variableDeclarator(t.objectPattern([
470
+ t.objectProperty(t.identifier('getTarget'), t.identifier('getTarget'), false, true),
471
+ ]), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
472
+ ]);
473
+ ast.program.body.unshift(requireCacheOptionsAst);
474
+ hasDatasetRequired = true;
475
+ needInsertImportTaro = true;
476
+ }
477
+ }
478
+ },
479
+ OptionalMemberExpression(astPath) {
480
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析OptionalMemberExpression ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
481
+ const node = astPath.node;
482
+ const object = node.object;
483
+ const prettier = node.property;
484
+ if (t.isIdentifier(prettier) && prettier.name === 'dataset') {
485
+ node.object = t.callExpression(t.identifier('getTarget'), [object, t.identifier('Taro')]);
486
+ // 创建导入 getTarget 对象的 ast 节点, 并且防止重复引用
487
+ if (!hasDatasetRequired) {
488
+ const requireCacheOptionsAst = t.variableDeclaration('const', [
489
+ t.variableDeclarator(t.objectPattern([
490
+ t.objectProperty(t.identifier('getTarget'), t.identifier('getTarget'), false, true),
491
+ ]), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
492
+ ]);
493
+ ast.program.body.unshift(requireCacheOptionsAst);
494
+ hasDatasetRequired = true;
495
+ needInsertImportTaro = true;
496
+ }
497
+ }
498
+ },
499
+ // 获取js界面所有用到的自定义标签,不重复
500
+ JSXElement(astPath) {
501
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析JSXElement ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
502
+ const openingElement = astPath.get('openingElement');
503
+ const jsxName = openingElement.get('name');
504
+ if (jsxName.isJSXIdentifier()) {
505
+ const componentName = jsxName.node.name;
506
+ if (!util_1.DEFAULT_Component_SET.has(componentName) && scriptComponents.indexOf(componentName) === -1) {
507
+ // 比较引入组件名和标签名是否同名,若同名,则在组件名上加入后缀Component
508
+ if (scriptImports.includes(componentName)) {
509
+ jsxName.node.name = `${componentName}Component`;
510
+ }
511
+ scriptComponents.push(componentName);
512
+ }
513
+ if (/^\S(\S)*Tmpl$/.test(componentName)) {
514
+ const templateImport = imports.find((tmplImport) => tmplImport.name === `${componentName}`);
515
+ const templateFuncs = templateImport === null || templateImport === void 0 ? void 0 : templateImport.funcs;
516
+ if (templateFuncs && templateFuncs.size > 0) {
517
+ const attributes = openingElement.node.attributes;
518
+ templateFuncs.forEach((templateFunc) => {
519
+ const memberExpression = t.memberExpression(t.thisExpression(), t.identifier(templateFunc));
520
+ const value = t.jsxExpressionContainer(memberExpression);
521
+ const name = t.jsxIdentifier(templateFunc);
522
+ // 传递的方法插入到Tmpl标签属性中
523
+ attributes.push(t.jsxAttribute(name, value));
524
+ });
525
+ }
526
+ }
527
+ else if (componentName === 'Template') {
528
+ // 处理没被成功转换的模板, 如果被转换了就不会还是Template
529
+ const attrs = openingElement.get('attributes');
530
+ const is = attrs.find((attr) => t.isJSXAttribute(attr) &&
531
+ t.isJSXIdentifier(attr.get('name')) &&
532
+ t.isJSXAttribute(attr.node) &&
533
+ attr.node.name.name === 'is');
534
+ // 处理<template is=包含变量的情况(组件的动态名称)
535
+ if (is && t.isJSXAttribute(is.node)) {
536
+ const value = is.node.value;
537
+ if (value && t.isJSXExpressionContainer(value)) {
538
+ const expression = value.expression;
539
+ // 1、<template is={{var}}> 2、<template is="string{{var}}">
540
+ if (t.isIdentifier(expression) ||
541
+ (t.isBinaryExpression(expression) && expression.operator === '+')) {
542
+ // 加上map, template原名和新名字的映射
543
+ const componentMapList = [];
544
+ for (const order in imports) {
545
+ for (const key in imports[order]) {
546
+ if (key === 'tmplName') {
547
+ const tmplName = imports[order][key];
548
+ const tmplLastName = imports[order].name;
549
+ // imports去重可能会把map里的去掉, 所以要加回去
550
+ if (!scriptComponents.includes(tmplLastName)) {
551
+ scriptComponents.push(tmplLastName);
552
+ }
553
+ componentMapList.push(t.objectProperty(t.stringLiteral('' + tmplName), t.identifier(tmplLastName)));
554
+ }
555
+ }
556
+ }
557
+ const withWeappPath = astPath.findParent((p) => p.isClassDeclaration());
558
+ if (withWeappPath) {
559
+ const MapVariableDeclaration = t.variableDeclaration('const', [
560
+ t.variableDeclarator(t.identifier('ComponentMap'), t.objectExpression(componentMapList)),
561
+ ]);
562
+ withWeappPath.insertBefore(MapVariableDeclaration);
563
+ }
564
+ // 加上用map给新标签赋值
565
+ const returnPath = astPath.findParent((p) => p.isReturnStatement());
566
+ if (returnPath) {
567
+ const ComponentNameVariableDeclaration = t.variableDeclaration('let', [
568
+ t.variableDeclarator(t.identifier('ComponentName'), t.memberExpression(t.identifier('ComponentMap'), expression, true)),
569
+ ]);
570
+ returnPath.insertBefore(ComponentNameVariableDeclaration);
571
+ }
572
+ // 标签非Template的情况下不会加spread, 删除spread属性; 更改开闭合标签为ComponentName
573
+ const attributes = [];
574
+ const data = attrs.find((attr) => t.isJSXAttribute(attr) &&
575
+ t.isJSXIdentifier(attr.get('name')) &&
576
+ t.isJSXAttribute(attr.node) &&
577
+ attr.node.name.name === 'data');
578
+ if (data && t.isJSXAttribute(data.node)) {
579
+ attributes.push(data.node);
580
+ }
581
+ astPath.replaceWith(t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('ComponentName'), attributes), t.jSXClosingElement(t.jSXIdentifier('ComponentName')), [], true));
582
+ }
583
+ }
584
+ }
585
+ }
586
+ }
587
+ },
588
+ // 处理this.data.xx = XXX 的情况,因为此表达式在taro暂不支持, 转为setData
589
+ AssignmentExpression(astPath) {
590
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析AssignmentExpression ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
591
+ const node = astPath.node;
592
+ if (t.isMemberExpression(node.left) &&
593
+ t.isMemberExpression(node.left.object) &&
594
+ t.isThisExpression(node.left.object.object) &&
595
+ t.isIdentifier(node.left.object.property)) {
596
+ // 确认左边是this.data
597
+ if (node.left.object.property.name === 'data' && t.isIdentifier(node.left.property)) {
598
+ const lastName = node.left.property.name;
599
+ // 右边不能确定数据类型,所以直接存整个对象
600
+ const rightValue = node.right;
601
+ // 由于合并setData会导致打乱代码顺序, 影响代码逻辑, 所以每一句this.data.xx单独转成一句setData
602
+ const memberExp = t.memberExpression(t.thisExpression(), t.identifier('setData'));
603
+ const objExp = t.objectExpression([t.objectProperty(t.identifier(lastName), rightValue)]);
604
+ astPath.replaceWith(t.expressionStatement(t.callExpression(memberExp, [objExp])));
605
+ console.log(`转换 语法 this.data.xx=XX暂不支持,原地替换为setData()`);
606
+ }
607
+ }
608
+ },
216
609
  });
217
610
  },
218
611
  exit(astPath) {
219
612
  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')));
613
+ const lastImport = bodyNode.filter((p) => p.isImportDeclaration() || (0, astConvert_1.isCommonjsImport)(p)).pop();
614
+ if (needInsertImportTaro && !(0, astConvert_1.hasTaroImport)(bodyNode)) {
615
+ // 根据模块类型(commonjs/es6) 确定导入taro模块的类型
616
+ if ((0, astConvert_1.isCommonjsModule)(ast.program.body)) {
617
+ astPath.node.body.unshift(t.variableDeclaration('const', [
618
+ t.variableDeclarator(t.identifier('Taro'), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/taro')])),
619
+ ]));
620
+ }
621
+ else {
622
+ astPath.node.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier('Taro'))], t.stringLiteral('@tarojs/taro')));
623
+ }
224
624
  }
225
625
  astPath.traverse({
226
626
  StringLiteral(astPath) {
627
+ var _a, _b, _c, _d;
628
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析StringLiteral ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
227
629
  const value = astPath.node.value;
228
630
  const extname = path.extname(value);
229
631
  if (extname && helper_1.REG_IMAGE.test(extname) && !helper_1.REG_URL.test(value)) {
@@ -232,16 +634,22 @@ class Convertor {
232
634
  sourceImagePath = path.join(self.root, value);
233
635
  }
234
636
  else {
235
- sourceImagePath = path.resolve(sourceFilePath, '..', value);
637
+ sourceImagePath = path.join(sourceFilePath, '..', value);
236
638
  }
237
639
  const imageRelativePath = (0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, sourceImagePath));
238
640
  const outputImagePath = self.getDistFilePath(sourceImagePath);
239
641
  if (helper_1.fs.existsSync(sourceImagePath)) {
240
- self.copyFileToTaro(sourceImagePath, outputImagePath);
642
+ (0, util_1.copyFileToTaro)(sourceImagePath, outputImagePath);
241
643
  (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, '图片', self.generateShowPath(outputImagePath));
242
644
  }
243
645
  else if (!t.isBinaryExpression(astPath.parent) || astPath.parent.operator !== '+') {
646
+ const position = {
647
+ row: ((_b = (_a = astPath.node.loc) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.line) || 0,
648
+ col: ((_d = (_c = astPath.node.loc) === null || _c === void 0 ? void 0 : _c.start) === null || _d === void 0 ? void 0 : _d.column) || 0,
649
+ };
650
+ (0, util_1.createErrorCodeMsg)('ImageNotFound', '图片不存在', (0, util_1.astToCode)(astPath.node) || '', sourceFilePath, position);
244
651
  (0, helper_1.printLog)("error" /* processTypeEnum.ERROR */, '图片不存在', self.generateShowPath(sourceImagePath));
652
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] parseAst - 图片不存在 ${(0, util_1.getLineBreak)()}${self.generateShowPath(sourceImagePath)} ${(0, util_1.getLineBreak)()}`);
245
653
  }
246
654
  if (astPath.parentPath.isVariableDeclarator()) {
247
655
  astPath.replaceWith(t.callExpression(t.identifier('require'), [t.stringLiteral(imageRelativePath)]));
@@ -250,46 +658,233 @@ class Convertor {
250
658
  astPath.replaceWith(t.jSXExpressionContainer(t.callExpression(t.identifier('require'), [t.stringLiteral(imageRelativePath)])));
251
659
  }
252
660
  }
253
- }
661
+ },
254
662
  });
255
663
  if (lastImport) {
256
664
  if (importStylePath) {
257
- lastImport.insertAfter(t.importDeclaration([], t.stringLiteral((0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, importStylePath)))));
665
+ if ((0, astConvert_1.isCommonjsModule)(ast.program.body)) {
666
+ lastImport.insertAfter(t.callExpression(t.identifier('require'), [
667
+ t.stringLiteral((0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, importStylePath))),
668
+ ]));
669
+ }
670
+ else {
671
+ lastImport.insertAfter(t.importDeclaration([], t.stringLiteral((0, helper_1.promoteRelativePath)(path.relative(sourceFilePath, importStylePath)))));
672
+ }
258
673
  }
259
674
  if (imports && imports.length) {
260
675
  imports.forEach(({ name, ast, wxs }) => {
261
- const importName = wxs ? name : (0, helper_1.pascalCase)(name);
262
- if (componentClassName === importName) {
676
+ if (componentClassName === name) {
263
677
  return;
264
678
  }
265
- const importPath = path.join(self.importsDir, importName + (wxs ? self.wxsIncrementId() : '') + '.js');
679
+ const importPath = path.join(self.importsDir, name + (wxs ? self.wxsIncrementId() : '') + (self.isTsProject ? '.ts' : '.js'));
266
680
  if (!self.hadBeenBuiltImports.has(importPath)) {
267
681
  self.hadBeenBuiltImports.add(importPath);
268
682
  self.writeFileToTaro(importPath, prettier.format((0, astConvert_1.generateMinimalEscapeCode)(ast), prettierJSConfig));
269
683
  }
270
- lastImport.insertAfter((0, template_1.default)(`import ${importName} from '${(0, helper_1.promoteRelativePath)(path.relative(outputFilePath, importPath))}'`, babylonConfig)());
684
+ if (scriptComponents.indexOf(name) !== -1 || (wxs && wxs === true)) {
685
+ lastImport.insertAfter((0, template_1.default)(`import ${name} from '${(0, helper_1.promoteRelativePath)(path.relative(outputFilePath, importPath))}'`, babylonConfig)());
686
+ }
271
687
  });
272
688
  }
273
689
  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)());
690
+ depComponents.forEach((componentObj) => {
691
+ let name = (0, helper_1.pascalCase)(componentObj.name.toLowerCase());
692
+ // 如果不是js页面用到的组件,无需导入
693
+ if (scriptComponents.indexOf(name) === -1) {
694
+ return;
695
+ }
696
+ // 如果用到了,从scriptComponents中移除
697
+ const index = scriptComponents.indexOf(name);
698
+ scriptComponents.splice(index, 1);
699
+ // 同名的自定义组件名称加后缀区分后,其组件标签也要加上Component保持统一
700
+ if (scriptImports.includes(name)) {
701
+ name = `${name}Component`;
702
+ }
703
+ let componentPath = componentObj.path;
704
+ if (!componentPath.startsWith(self.root) && !componentPath.startsWith(self.pluginInfo.pluginRoot)) {
705
+ (0, util_1.createErrorCodeMsg)('invalidComponentPath', `exception: 无效的组件路径,componentPath: ${componentPath}, 请在${outputFilePath}中手动引入`, `${componentObj.name}: ${componentObj.path}`, global_1.globals.currentParseFile);
706
+ console.error(`exception: 无效的组件路径,componentPath: ${componentPath}, 请在${outputFilePath}中手动引入`);
707
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] parseAst - 无效的组件路径 ${(0, util_1.getLineBreak)()}${componentPath} ${(0, util_1.getLineBreak)()}`);
708
+ return;
709
+ }
710
+ componentPath = path.relative(sourceFilePath, componentPath);
711
+ lastImport.insertAfter((0, template_1.default)(`import ${name} from '${(0, helper_1.promoteRelativePath)(componentPath)}'`, babylonConfig)());
278
712
  });
279
713
  }
714
+ // 页面中引用的插件组件增加引用信息
715
+ if (pluginComponents && pluginComponents.size) {
716
+ pluginComponents.forEach((pluginComponent) => {
717
+ const componentName = (0, helper_1.pascalCase)(pluginComponent.name.toLowerCase());
718
+ const componentPath = pluginComponent.path;
719
+ if (!componentPath.startsWith(self.pluginInfo.pluginRoot)) {
720
+ console.error(`exception: 在页面${sourceFilePath}引用了无效的插件组件路径${componentPath}, 请在${outputFilePath}中手动引入`);
721
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] parseAst - ${sourceFilePath} 页面引用了无效的插件组件路径 ${(0, util_1.getLineBreak)()}${componentPath} ${(0, util_1.getLineBreak)()}`);
722
+ return;
723
+ }
724
+ // 插件组件转换后的绝对路径
725
+ const conponentTransPath = componentPath.replace(self.pluginInfo.pluginRoot, path.join(self.convertDir, self.pluginInfo.pluginName));
726
+ // 由于插件转换后路径的变化,此处需根据转换后的路径获取相对路径
727
+ const componentRelPath = path.relative(self.getDistFilePath(sourceFilePath), conponentTransPath);
728
+ lastImport.insertAfter((0, template_1.default)(`import ${componentName} from '${(0, helper_1.promoteRelativePath)(componentRelPath)}'`, babylonConfig)());
729
+ });
730
+ }
731
+ }
732
+ },
733
+ },
734
+ });
735
+ this.convertToOptional(ast);
736
+ // 遍历 ast ,将多次 const { xxx } = require('@tarojs/with-weapp') 引入压缩为一次引入
737
+ (0, traverse_1.default)(ast, {
738
+ VariableDeclaration(astPath) {
739
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] parseAst - 解析VariableDeclaration ${(0, util_1.getLineBreak)()}${astPath} ${(0, util_1.getLineBreak)()}`);
740
+ const { kind, declarations } = astPath.node;
741
+ let currentAstIsWithWeapp = false;
742
+ if (kind === 'const') {
743
+ declarations.forEach((declaration) => {
744
+ const { id, init } = declaration;
745
+ if (t.isObjectPattern(id) &&
746
+ t.isCallExpression(init) &&
747
+ t.isIdentifier(init.callee) &&
748
+ t.isStringLiteral(init.arguments[0])) {
749
+ const name = init.callee.name;
750
+ const args = init.arguments[0].value;
751
+ if (name === 'require' && args === '@tarojs/with-weapp') {
752
+ currentAstIsWithWeapp = true;
753
+ id.properties.forEach((propertie) => {
754
+ if (t.isObjectProperty(propertie) && t.isIdentifier(propertie.value)) {
755
+ set.add(propertie.value.name);
756
+ }
757
+ });
758
+ }
759
+ }
760
+ });
761
+ }
762
+ if (currentAstIsWithWeapp) {
763
+ astPath.remove();
764
+ }
765
+ },
766
+ });
767
+ // 若 set 为空则不引入 @tarojs/with-weapp
768
+ if (set.size !== 0) {
769
+ if ((0, astConvert_1.isCommonjsModule)(ast.program.body)) {
770
+ const objectPropertyArray = [];
771
+ set.forEach((key) => {
772
+ if (key === 'withWeapp') {
773
+ objectPropertyArray.push(t.objectProperty(t.identifier('default'), t.identifier('withWeapp'), false, true));
774
+ }
775
+ else {
776
+ objectPropertyArray.push(t.objectProperty(t.identifier(key), t.identifier(key), false, true));
777
+ }
778
+ });
779
+ const requireWithWeappAst = t.variableDeclaration('const', [
780
+ t.variableDeclarator(t.objectPattern(objectPropertyArray), t.callExpression(t.identifier('require'), [t.stringLiteral('@tarojs/with-weapp')])),
781
+ ]);
782
+ ast.program.body.unshift(requireWithWeappAst);
783
+ }
784
+ else {
785
+ const objectPropertyArray = [];
786
+ let hasWithWeapp = false;
787
+ set.forEach((key) => {
788
+ if (key === 'withWeapp') {
789
+ hasWithWeapp = true;
280
790
  }
791
+ else {
792
+ objectPropertyArray.push(t.importSpecifier(t.identifier(key), t.identifier(key)));
793
+ }
794
+ });
795
+ if (hasWithWeapp) {
796
+ objectPropertyArray.unshift(t.importDefaultSpecifier(t.identifier('withWeapp')));
281
797
  }
798
+ const importWithWeapp = t.importDeclaration(objectPropertyArray, t.stringLiteral('@tarojs/with-weapp'));
799
+ ast.program.body.unshift(importWithWeapp);
282
800
  }
283
- });
801
+ }
284
802
  return {
285
803
  ast,
286
- scriptFiles
804
+ scriptFiles,
287
805
  };
288
806
  }
807
+ convertSelfDefinedConfig() {
808
+ // 搬运自定义的配置文件
809
+ const selfDefinedConfig = [];
810
+ // 目前只有tsconfig.json,还有的话继续加到array里
811
+ selfDefinedConfig[0] = `tsconfig${this.fileTypes.CONFIG}`;
812
+ for (const tempConfig of selfDefinedConfig) {
813
+ const tempConfigPath = path.join(this.root, tempConfig);
814
+ if (helper_1.fs.existsSync(tempConfig)) {
815
+ try {
816
+ const outputFilePath = path.join(this.convertRoot, tempConfig);
817
+ (0, util_1.copyFileToTaro)(tempConfigPath, outputFilePath);
818
+ }
819
+ catch (err) {
820
+ (0, util_1.createErrorCodeMsg)('TsConfigCopyError', `tsconfig${this.fileTypes.CONFIG} 拷贝失败,请检查!`, '', path.join(this.root, `tsconfig${this.fileTypes.CONFIG}`));
821
+ // 失败不退出,仅提示
822
+ console.log(helper_1.chalk.red(`tsconfig${this.fileTypes.CONFIG} 拷贝失败,请检查!`));
823
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] convertSelfDefinedConfig - tsconfig${this.fileTypes.CONFIG} 文件拷贝异常 ${err} ${(0, util_1.getLineBreak)()}`);
824
+ }
825
+ }
826
+ }
827
+ }
828
+ getConvertConfig() {
829
+ // 处理convert.config.json,并存储到convertConfig中
830
+ const convertJsonPath = path.join(this.root, `convert.config${this.fileTypes.CONFIG}`);
831
+ if (helper_1.fs.existsSync(convertJsonPath)) {
832
+ try {
833
+ const convertJson = JSON.parse(String(helper_1.fs.readFileSync(convertJsonPath)));
834
+ this.convertConfig = Object.assign({}, convertJson);
835
+ this.convertConfig.external = (0, util_1.transRelToAbsPath)(convertJsonPath, this.convertConfig.external);
836
+ }
837
+ catch (err) {
838
+ (0, util_1.createErrorCodeMsg)('ConvertConfigReadError', `convert.config${this.fileTypes.CONFIG} 读取失败,请检查!`, '', convertJsonPath);
839
+ console.log(helper_1.chalk.red(`convert.config${this.fileTypes.CONFIG} 读取失败,请检查!`));
840
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] getConvertConfig - convert.config${this.fileTypes.CONFIG} 文件读取异常 ${(0, util_1.getLineBreak)()}${err} ${(0, util_1.getLineBreak)()}`);
841
+ process.exit(1);
842
+ }
843
+ }
844
+ }
845
+ /**
846
+ * 解析project.config.json配置文件
847
+ *
848
+ */
849
+ parseProjectConfig() {
850
+ // 处理project.config.json,并存储到projectConfig中
851
+ const projectConfigFilePath = path.join(this.root, `project.config${this.fileTypes.CONFIG}`);
852
+ if (helper_1.fs.existsSync(projectConfigFilePath)) {
853
+ try {
854
+ const projectConfigJson = JSON.parse(String(helper_1.fs.readFileSync(projectConfigFilePath, 'utf8')));
855
+ if (projectConfigJson && projectConfigJson.compileType === "plugin" /* Constants.PLUGIN */) {
856
+ const pluginRoot = projectConfigJson.pluginRoot;
857
+ if (pluginRoot === '' || (0, shared_1.isNull)(pluginRoot) || (0, shared_1.isUndefined)(pluginRoot)) {
858
+ (0, util_1.createErrorCodeMsg)('emptyPluginRoot', 'project.config,json中pluginRoot为空或未配置,请确认配置是否正确', '', projectConfigFilePath);
859
+ console.log('project.config.json中pluginRoot为空或未配置,请确认配置是否正确');
860
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] parseProjectConfig - project.config.json 中 pluginRoot 为空或未配置 ${(0, util_1.getLineBreak)()}`);
861
+ process.exit(1);
862
+ }
863
+ this.projectConfig = Object.assign({}, projectConfigJson);
864
+ this.pluginInfo.pluginRoot = path.join(this.root, projectConfigJson.pluginRoot.replace(/\/+$/, ''));
865
+ }
866
+ // 解析miniprogramRoot字段,如果存在则更新小程序root
867
+ if (projectConfigJson.miniprogramRoot) {
868
+ this.root = path.join(this.root, projectConfigJson.miniprogramRoot.replace(/\/+$/, ''));
869
+ }
870
+ }
871
+ catch (err) {
872
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] parseProjectConfig - project.config${this.fileTypes.CONFIG} 文件解析异常 ${(0, util_1.getLineBreak)()}${err} ${(0, util_1.getLineBreak)()}`);
873
+ throw new util_1.IReportError(`project.config${this.fileTypes.CONFIG} 解析失败,请检查!`, 'ProjectConfigParsingError', projectConfigFilePath, '');
874
+ }
875
+ }
876
+ }
289
877
  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}`);
878
+ if (this.isTsProject) {
879
+ this.entryJSPath = path.join(this.miniprogramRoot, `app${this.fileTypes.SCRIPT}`);
880
+ this.entryJSONPath = path.join(this.miniprogramRoot, `app${this.fileTypes.CONFIG}`);
881
+ this.entryStylePath = path.join(this.miniprogramRoot, `app${this.fileTypes.STYLE}`);
882
+ }
883
+ else {
884
+ this.entryJSPath = path.join(this.root, `app${this.fileTypes.SCRIPT}`);
885
+ this.entryJSONPath = path.join(this.root, `app${this.fileTypes.CONFIG}`);
886
+ this.entryStylePath = path.join(this.root, `app${this.fileTypes.STYLE}`);
887
+ }
293
888
  try {
294
889
  this.entryJSON = JSON.parse(String(helper_1.fs.readFileSync(this.entryJSONPath)));
295
890
  const using = this.entryJSON.usingComponents;
@@ -298,11 +893,18 @@ class Convertor {
298
893
  if (using[key].startsWith('plugin://'))
299
894
  continue;
300
895
  const componentPath = using[key];
301
- using[key] = path.join(this.root, componentPath);
896
+ // 非三方库的路径需要处理
897
+ if (!this.isThirdPartyLib(componentPath, this.root)) {
898
+ using[key] = path.join(this.root, componentPath);
899
+ }
302
900
  }
303
901
  this.entryUsingComponents = using;
304
902
  delete this.entryJSON.usingComponents;
305
903
  }
904
+ // 当小程序中包含plugin时,从app.json中解析pluginName,当前只支持一个plugin
905
+ if (this.projectConfig && this.projectConfig.compileType === "plugin" /* Constants.PLUGIN */) {
906
+ this.parsePluginName(this.entryJSON);
907
+ }
306
908
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '入口文件', this.generateShowPath(this.entryJSPath));
307
909
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '入口配置', this.generateShowPath(this.entryJSONPath));
308
910
  if (helper_1.fs.existsSync(this.entryStylePath)) {
@@ -312,14 +914,35 @@ class Convertor {
312
914
  }
313
915
  catch (err) {
314
916
  this.entryJSON = {};
917
+ (0, util_1.createErrorCodeMsg)('AppConfigReadError', `app${this.fileTypes.CONFIG} 读取失败,请检查!`, '', this.entryJSONPath);
315
918
  console.log(helper_1.chalk.red(`app${this.fileTypes.CONFIG} 读取失败,请检查!`));
919
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] getApp - app${this.fileTypes.CONFIG} 文件读取异常 ${(0, util_1.getLineBreak)()}${err} ${(0, util_1.getLineBreak)()}`);
920
+ process.exit(1);
921
+ }
922
+ }
923
+ /**
924
+ * 从app.json中解析pluginName,当前只支持一个plugin
925
+ *
926
+ * @param app.json
927
+ */
928
+ parsePluginName(entryJSON) {
929
+ const plugins = entryJSON.plugins;
930
+ if (plugins && Object.keys(plugins).length) {
931
+ this.pluginInfo.pluginName = Object.keys(plugins)[0];
932
+ }
933
+ else {
934
+ (0, util_1.createErrorCodeMsg)('unregisteredPlugin', '当前应用没有注册插件,请检查app.json中的plugins字段是否配置正确', '', this.entryJSONPath);
935
+ console.log('当前应用没有注册插件,请检查app.json中的plugins字段是否配置正确');
936
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] parsePluginName - 当前应用没有注册插件,请检查 app.json 中的 plugins 字段 ${(0, util_1.getLineBreak)()}`);
316
937
  process.exit(1);
317
938
  }
318
939
  }
319
940
  getPages() {
320
941
  const pages = this.entryJSON.pages;
321
942
  if (!pages || !pages.length) {
943
+ (0, util_1.createErrorCodeMsg)('missingPageConfig', `app${this.fileTypes.CONFIG} 配置有误,缺少页面相关配置`, '', this.entryJSONPath);
322
944
  console.log(helper_1.chalk.red(`app${this.fileTypes.CONFIG} 配置有误,缺少页面相关配置`));
945
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] getPages - app${this.fileTypes.CONFIG} 文件配置异常 ${(0, util_1.getLineBreak)()}`);
323
946
  return;
324
947
  }
325
948
  this.pages = new Set(pages);
@@ -329,10 +952,10 @@ class Convertor {
329
952
  if (!subPackages || !subPackages.length) {
330
953
  return;
331
954
  }
332
- subPackages.forEach(item => {
955
+ subPackages.forEach((item) => {
333
956
  if (item.pages && item.pages.length) {
334
957
  const root = item.root;
335
- item.pages.forEach(page => {
958
+ item.pages.forEach((page) => {
336
959
  let pagePath = `${root}/${page}`;
337
960
  pagePath = pagePath.replace(/\/{2,}/g, '/');
338
961
  this.pages.add(pagePath);
@@ -347,41 +970,63 @@ class Convertor {
347
970
  const sitemapFilePath = path.join(this.root, sitemapLocation);
348
971
  if (helper_1.fs.existsSync(sitemapFilePath)) {
349
972
  const outputFilePath = path.join(this.convertRoot, sitemapLocation);
350
- this.copyFileToTaro(sitemapFilePath, outputFilePath);
973
+ (0, util_1.copyFileToTaro)(sitemapFilePath, outputFilePath);
351
974
  }
352
975
  }
353
976
  }
354
977
  generateScriptFiles(files) {
355
978
  if (!files) {
979
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] generateScriptFiles - 文件不存在 ${(0, util_1.getLineBreak)()}`);
356
980
  return;
357
981
  }
358
982
  if (files.size) {
359
- files.forEach(file => {
983
+ files.forEach((file) => {
984
+ var _a, _b;
985
+ // 处理三方库引用,可在convert.config.json中nodePath字段自定义配置配置,默认node_modules
986
+ if (!path.isAbsolute(file)) {
987
+ (0, util_1.handleThirdPartyLib)(file, (_a = this.convertConfig) === null || _a === void 0 ? void 0 : _a.nodePath, this.root, this.convertRoot);
988
+ return;
989
+ }
360
990
  if (!helper_1.fs.existsSync(file) || this.hadBeenCopyedFiles.has(file)) {
361
991
  return;
362
992
  }
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';
368
- }
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);
993
+ // 处理不转换的目录,可在convert.config.json中external字段配置
994
+ const matchUnconvertDir = (0, util_1.getMatchUnconvertDir)(file, (_b = this.convertConfig) === null || _b === void 0 ? void 0 : _b.external);
995
+ if (matchUnconvertDir !== null) {
996
+ (0, util_1.handleUnconvertDir)(matchUnconvertDir, this.root, this.convertDir);
997
+ return;
998
+ }
999
+ try {
1000
+ const code = helper_1.fs.readFileSync(file).toString();
1001
+ let outputFilePath = this.getDistFilePath(file);
1002
+ const extname = path.extname(outputFilePath);
1003
+ if (/\.wxs/.test(extname)) {
1004
+ outputFilePath += '.js';
1005
+ }
1006
+ const transformResult = (0, transformer_wx_1.default)({
1007
+ code,
1008
+ sourcePath: file,
1009
+ isNormal: true,
1010
+ isTyped: helper_1.REG_TYPESCRIPT.test(file),
1011
+ logFilePath: global_1.globals.logFilePath,
1012
+ });
1013
+ const { ast, scriptFiles } = this.parseAst({
1014
+ ast: transformResult.ast,
1015
+ outputFilePath,
1016
+ sourceFilePath: file,
1017
+ });
1018
+ const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
1019
+ this.writeFileToTaro(outputFilePath, prettier.format(jsCode, prettierJSConfig));
1020
+ (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, 'JS 文件', this.generateShowPath(outputFilePath));
1021
+ this.hadBeenCopyedFiles.add(file);
1022
+ global_1.globals.currentParseFile = file;
1023
+ this.generateScriptFiles(scriptFiles);
1024
+ }
1025
+ catch (error) {
1026
+ (0, util_1.parseError)(error, file, '');
1027
+ console.log(`转换文件${file}异常,errorMessage:${error}`);
1028
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] generateScriptFiles - ${file} 文件转换异常 ${(0, util_1.getLineBreak)()}${error} ${(0, util_1.getLineBreak)()}`);
1029
+ }
385
1030
  });
386
1031
  }
387
1032
  }
@@ -389,19 +1034,29 @@ class Convertor {
389
1034
  helper_1.fs.ensureDirSync(path.dirname(dist));
390
1035
  helper_1.fs.writeFileSync(dist, code);
391
1036
  }
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);
1037
+ // 自定义组件,如果组件文件命名为index,引入时可省略index这一层,解析时需加上
1038
+ getComponentPath(component, extname) {
1039
+ if (helper_1.fs.existsSync(component + extname))
1040
+ return component + extname;
1041
+ else
1042
+ return component + '/index' + extname;
400
1043
  }
1044
+ /**
1045
+ * 根据源文件路径获取转换后文件路径
1046
+ *
1047
+ * @param { string } src 源文件路径
1048
+ * @param { 文件后缀 } extname
1049
+ * @returns { string } 转换后文件路径
1050
+ */
401
1051
  getDistFilePath(src, extname) {
402
- if (!extname)
403
- return src.replace(this.root, this.convertDir);
404
- return src.replace(this.root, this.convertDir).replace(path.extname(src), extname);
1052
+ let filePath;
1053
+ if (this.isTraversePlugin) {
1054
+ filePath = src.replace(this.pluginInfo.pluginRoot, path.join(this.convertDir, this.pluginInfo.pluginName));
1055
+ }
1056
+ else {
1057
+ filePath = src.replace(this.root, this.convertDir);
1058
+ }
1059
+ return extname ? filePath.replace(path.extname(src), extname) : filePath;
405
1060
  }
406
1061
  getConfigFilePath(src) {
407
1062
  const { dir, name } = path.parse(src);
@@ -413,15 +1068,12 @@ class Convertor {
413
1068
  this.writeFileToTaro(configSrc, prettier.format(code, prettierJSConfig));
414
1069
  }
415
1070
  generateShowPath(filePath) {
416
- return filePath
417
- .replace(path.join(this.root, '/'), '')
418
- .split(path.sep)
419
- .join('/');
1071
+ return filePath.replace(path.join(this.root, '/'), '').split(path.sep).join('/');
420
1072
  }
421
1073
  formatFile(jsCode, template = '') {
422
1074
  let code = jsCode;
423
1075
  const config = Object.assign({}, prettierJSConfig);
424
- if (this.framework === 'vue') {
1076
+ if (this.framework === "Vue" /* FrameworkType.Vue */) {
425
1077
  code = `
426
1078
  ${template}
427
1079
  <script>
@@ -437,16 +1089,19 @@ ${code}
437
1089
  generateEntry() {
438
1090
  try {
439
1091
  const entryJS = String(helper_1.fs.readFileSync(this.entryJSPath));
440
- const entryJSON = JSON.stringify(this.entryJSON);
1092
+ let entryJSON = JSON.stringify(this.entryJSON);
441
1093
  const entryDistJSPath = this.getDistFilePath(this.entryJSPath);
442
1094
  const taroizeResult = taroize({
443
1095
  json: entryJSON,
444
1096
  script: entryJS,
1097
+ scriptPath: this.entryJSPath,
445
1098
  path: this.root,
446
1099
  rootPath: this.root,
447
1100
  framework: this.framework,
448
- isApp: true
1101
+ isApp: true,
1102
+ logFilePath: global_1.globals.logFilePath,
449
1103
  });
1104
+ global_1.globals.errCodeMsgs.push(...taroizeResult.errCodeMsgs);
450
1105
  const { ast, scriptFiles } = this.parseAst({
451
1106
  ast: taroizeResult.ast,
452
1107
  sourceFilePath: this.entryJSPath,
@@ -454,8 +1109,12 @@ ${code}
454
1109
  importStylePath: this.entryStyle
455
1110
  ? this.entryStylePath.replace(path.extname(this.entryStylePath), OUTPUT_STYLE_EXTNAME)
456
1111
  : null,
457
- isApp: true
1112
+ isApp: true,
458
1113
  });
1114
+ // 将插件信息转换为子包信息添加到入口配置文件中
1115
+ if (this.projectConfig.compileType === "plugin" /* Constants.PLUGIN */) {
1116
+ entryJSON = this.addSubpackages(this.entryJSON);
1117
+ }
459
1118
  const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
460
1119
  this.writeFileToTaro(entryDistJSPath, jsCode);
461
1120
  this.writeFileToConfig(entryDistJSPath, entryJSON);
@@ -463,6 +1122,7 @@ ${code}
463
1122
  if (this.entryStyle) {
464
1123
  this.traverseStyle(this.entryStylePath, this.entryStyle);
465
1124
  }
1125
+ global_1.globals.currentParseFile = this.entryJSPath;
466
1126
  this.generateScriptFiles(scriptFiles);
467
1127
  if (this.entryJSON.tabBar) {
468
1128
  this.generateTabBarIcon(this.entryJSON.tabBar);
@@ -470,14 +1130,42 @@ ${code}
470
1130
  }
471
1131
  }
472
1132
  catch (err) {
473
- console.log(err);
1133
+ (0, util_1.parseError)(err, this.entryJSPath, '');
1134
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] generateEntry - ${this.entryJSPath} 入口文件生成异常 ${(0, util_1.getLineBreak)()}${err} ${(0, util_1.getLineBreak)()}`);
1135
+ }
1136
+ }
1137
+ /**
1138
+ * 将plugin信息转换为subpackage并添加到入口配置文件中
1139
+ *
1140
+ * @param entryJSON
1141
+ * @returns
1142
+ */
1143
+ addSubpackages(entryJSON) {
1144
+ // 删除plugins字段
1145
+ if (entryJSON && entryJSON.plugins) {
1146
+ delete entryJSON.plugins;
1147
+ }
1148
+ const subPackageInfo = {
1149
+ root: `${this.pluginInfo.pluginName}/`,
1150
+ pages: [...this.pluginInfo.pages],
1151
+ };
1152
+ // 子包的字段可以为subpackages 或 subPackages
1153
+ if (entryJSON.subpackages) {
1154
+ entryJSON.subpackages.push(subPackageInfo);
1155
+ }
1156
+ else if (entryJSON.subPackages) {
1157
+ entryJSON.subPackages.push(subPackageInfo);
1158
+ }
1159
+ else {
1160
+ entryJSON.subPackages = [subPackageInfo];
474
1161
  }
1162
+ return JSON.stringify(entryJSON);
475
1163
  }
476
1164
  generateTabBarIcon(tabBar) {
477
1165
  const { list = [] } = tabBar;
478
1166
  const icons = new Set();
479
1167
  if (Array.isArray(list) && list.length) {
480
- list.forEach(item => {
1168
+ list.forEach((item) => {
481
1169
  if (typeof item.iconPath === 'string')
482
1170
  icons.add(item.iconPath);
483
1171
  if (typeof item.selectedIconPath === 'string')
@@ -485,10 +1173,10 @@ ${code}
485
1173
  });
486
1174
  if (icons.size > 0) {
487
1175
  Array.from(icons)
488
- .map(icon => path.join(this.root, icon))
489
- .forEach(iconPath => {
1176
+ .map((icon) => path.join(this.root, icon))
1177
+ .forEach((iconPath) => {
490
1178
  const iconDistPath = this.getDistFilePath(iconPath);
491
- this.copyFileToTaro(iconPath, iconDistPath);
1179
+ (0, util_1.copyFileToTaro)(iconPath, iconDistPath);
492
1180
  (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, 'TabBar 图标', this.generateShowPath(iconDistPath));
493
1181
  });
494
1182
  }
@@ -500,28 +1188,71 @@ ${code}
500
1188
  const customTabbarPath = path.join(this.root, 'custom-tab-bar');
501
1189
  if (helper_1.fs.existsSync(customTabbarPath)) {
502
1190
  const customTabbarDistPath = this.getDistFilePath(customTabbarPath);
503
- this.copyFileToTaro(customTabbarPath, customTabbarDistPath);
1191
+ (0, util_1.copyFileToTaro)(customTabbarPath, customTabbarDistPath);
504
1192
  (0, helper_1.printLog)("copy" /* processTypeEnum.COPY */, '自定义 TabBar', this.generateShowPath(customTabbarDistPath));
505
1193
  }
506
1194
  }
507
1195
  getComponentDest(file) {
508
- if (this.framework === 'react') {
1196
+ if (this.framework === "React" /* FrameworkType.React */) {
509
1197
  return file;
510
1198
  }
511
1199
  return path.join(path.dirname(file), path.basename(file, path.extname(file)) + '.vue');
512
1200
  }
513
- traversePages() {
514
- this.pages.forEach(page => {
515
- const pagePath = path.join(this.root, page);
516
- const pageJSPath = pagePath + this.fileTypes.SCRIPT;
1201
+ // 判断是否是三方库
1202
+ isThirdPartyLib(modulePath, curPageDir) {
1203
+ // 相对路径和带根目录的路径都不是三方库
1204
+ if (modulePath.indexOf('.') === 0 || modulePath.indexOf('/') === 0 || modulePath.indexOf(this.root) !== -1) {
1205
+ return false;
1206
+ }
1207
+ // 通过格式如component/component引用组件
1208
+ // app.json中引用组件
1209
+ if (curPageDir === this.root) {
1210
+ if (helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(path.join(curPageDir, modulePath)))) {
1211
+ return false;
1212
+ }
1213
+ }
1214
+ else {
1215
+ // 页面中引用组件
1216
+ if (helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(path.join(curPageDir, modulePath))) ||
1217
+ helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(path.join(this.root, modulePath)))) {
1218
+ return false;
1219
+ }
1220
+ }
1221
+ return true;
1222
+ }
1223
+ // 判断三方库是否安装
1224
+ // isInNodeModule (modulePath: string) {
1225
+ // const nodeModules = path.resolve(this.root, 'node_modules')
1226
+ // if (!fs.existsSync(nodeModules)) {
1227
+ // return false
1228
+ // }
1229
+ // const modules = fs.readdirSync(nodeModules)
1230
+ // const parts = modulePath.split('/')
1231
+ // if (modules.indexOf(parts[0]) === -1) {
1232
+ // return false
1233
+ // }
1234
+ // return true
1235
+ // }
1236
+ traversePages(root, pages) {
1237
+ pages.forEach((page) => {
1238
+ var _a;
1239
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] traversePages - 开始转换页面 ${(0, util_1.getLineBreak)()}${page} ${(0, util_1.getLineBreak)()}`);
1240
+ const pagePath = this.isTsProject ? path.join(this.miniprogramRoot, page) : path.join(root, page);
1241
+ // 处理不转换的页面,可在convert.config.json中external字段配置
1242
+ const matchUnconvertDir = (0, util_1.getMatchUnconvertDir)(pagePath, (_a = this.convertConfig) === null || _a === void 0 ? void 0 : _a.external);
1243
+ if (matchUnconvertDir !== null) {
1244
+ (0, util_1.handleUnconvertDir)(matchUnconvertDir, root, this.convertDir);
1245
+ return;
1246
+ }
1247
+ const pageJSPath = pagePath + this.fileTypes.SCRIPT; // .js文件
517
1248
  const pageDistJSPath = this.getDistFilePath(pageJSPath);
518
- const pageConfigPath = pagePath + this.fileTypes.CONFIG;
519
- const pageStylePath = pagePath + this.fileTypes.STYLE;
520
- const pageTemplPath = pagePath + this.fileTypes.TEMPL;
1249
+ const pageConfigPath = pagePath + this.fileTypes.CONFIG; // .json文件
1250
+ const pageStylePath = pagePath + this.fileTypes.STYLE; // .wxss文件
1251
+ const pageTemplPath = pagePath + this.fileTypes.TEMPL; // .wxml文件
521
1252
  try {
522
- const depComponents = new Set();
523
1253
  if (!helper_1.fs.existsSync(pageJSPath)) {
524
- throw new Error(`页面 ${page} 没有 JS 文件!`);
1254
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] traversePages - 页面 ${page} 没有 JS 文件 ${(0, util_1.getLineBreak)()}`);
1255
+ throw new util_1.IReportError(`页面 ${page} 没有 JS 文件!`, 'MissingJSFileError', pagePath, '');
525
1256
  }
526
1257
  const param = {};
527
1258
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '页面文件', this.generateShowPath(pageJSPath));
@@ -534,33 +1265,47 @@ ${code}
534
1265
  else if (this.entryUsingComponents) {
535
1266
  pageConfig = {};
536
1267
  }
1268
+ const depComponents = new Set();
1269
+ const pluginComponents = new Set();
537
1270
  if (pageConfig) {
538
- if (this.entryUsingComponents) {
1271
+ // app.json中注册的组件为公共组件
1272
+ if (this.entryUsingComponents && !this.isTraversePlugin) {
539
1273
  pageConfig.usingComponents = Object.assign(Object.assign({}, pageConfig.usingComponents), this.entryUsingComponents);
540
1274
  }
541
1275
  const pageUsingComponents = pageConfig.usingComponents;
542
1276
  if (pageUsingComponents) {
543
1277
  // 页面依赖组件
544
1278
  const usingComponents = {};
545
- Object.keys(pageUsingComponents).forEach(component => {
1279
+ Object.keys(pageUsingComponents).forEach((component) => {
1280
+ var _a;
546
1281
  const unResolveComponentPath = pageUsingComponents[component];
1282
+ let componentPath;
547
1283
  if (unResolveComponentPath.startsWith('plugin://')) {
548
- usingComponents[component] = unResolveComponentPath;
1284
+ global_1.globals.currentParseFile = pageConfigPath;
1285
+ componentPath = (0, util_1.replacePluginComponentUrl)(unResolveComponentPath, this.pluginInfo);
1286
+ pluginComponents.add({
1287
+ name: component,
1288
+ path: componentPath,
1289
+ });
1290
+ }
1291
+ else if (this.isThirdPartyLib(unResolveComponentPath, path.resolve(pagePath, '..'))) {
1292
+ global_1.globals.currentParseFile = pageConfigPath;
1293
+ (0, util_1.handleThirdPartyLib)(unResolveComponentPath, (_a = this.convertConfig) === null || _a === void 0 ? void 0 : _a.nodePath, root, this.convertRoot);
549
1294
  }
550
1295
  else {
551
- let componentPath;
552
- if (unResolveComponentPath.startsWith(this.root)) {
1296
+ if (unResolveComponentPath.startsWith(root)) {
553
1297
  componentPath = unResolveComponentPath;
554
1298
  }
555
1299
  else {
556
- componentPath = path.resolve(pageConfigPath, '..', pageUsingComponents[component]);
1300
+ componentPath = path.join(pageConfigPath, '..', pageUsingComponents[component]);
1301
+ // 支持将组件库放在工程根目录下
557
1302
  if (!helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(componentPath))) {
558
- componentPath = path.join(this.root, pageUsingComponents[component]);
1303
+ componentPath = path.join(root, pageUsingComponents[component]);
559
1304
  }
560
1305
  }
561
1306
  depComponents.add({
562
1307
  name: component,
563
- path: componentPath
1308
+ path: componentPath,
564
1309
  });
565
1310
  }
566
1311
  });
@@ -574,6 +1319,7 @@ ${code}
574
1319
  param.json = JSON.stringify(pageConfig);
575
1320
  }
576
1321
  param.script = String(helper_1.fs.readFileSync(pageJSPath));
1322
+ param.scriptPath = pageJSPath;
577
1323
  if (helper_1.fs.existsSync(pageTemplPath)) {
578
1324
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '页面模板', this.generateShowPath(pageTemplPath));
579
1325
  param.wxml = String(helper_1.fs.readFileSync(pageTemplPath));
@@ -584,29 +1330,39 @@ ${code}
584
1330
  pageStyle = String(helper_1.fs.readFileSync(pageStylePath));
585
1331
  }
586
1332
  param.path = path.dirname(pageJSPath);
587
- param.rootPath = this.root;
1333
+ param.rootPath = root;
1334
+ param.pluginInfo = this.pluginInfo;
1335
+ param.logFilePath = global_1.globals.logFilePath;
1336
+ param.templatePath = pageTemplPath;
588
1337
  const taroizeResult = taroize(Object.assign(Object.assign({}, param), { framework: this.framework }));
1338
+ global_1.globals.errCodeMsgs.push(...taroizeResult.errCodeMsgs);
1339
+ global_1.globals.currentParseFile = pageConfigPath;
589
1340
  const { ast, scriptFiles } = this.parseAst({
590
1341
  ast: taroizeResult.ast,
591
1342
  sourceFilePath: pageJSPath,
592
1343
  outputFilePath: pageDistJSPath,
593
1344
  importStylePath: pageStyle ? pageStylePath.replace(path.extname(pageStylePath), OUTPUT_STYLE_EXTNAME) : null,
594
- depComponents,
595
- imports: taroizeResult.imports
1345
+ depComponents: depComponents,
1346
+ imports: taroizeResult.imports,
1347
+ pluginComponents: pluginComponents,
596
1348
  });
597
1349
  const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
598
1350
  this.writeFileToTaro(this.getComponentDest(pageDistJSPath), this.formatFile(jsCode, taroizeResult.template));
1351
+ (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, 'writeFileToTaro', this.generateShowPath(pageDistJSPath));
599
1352
  this.writeFileToConfig(pageDistJSPath, param.json);
600
1353
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '页面文件', this.generateShowPath(pageDistJSPath));
601
1354
  if (pageStyle) {
602
1355
  this.traverseStyle(pageStylePath, pageStyle);
603
1356
  }
1357
+ global_1.globals.currentParseFile = pageJSPath;
604
1358
  this.generateScriptFiles(scriptFiles);
605
1359
  this.traverseComponents(depComponents);
606
1360
  }
607
1361
  catch (err) {
608
1362
  (0, helper_1.printLog)("error" /* processTypeEnum.ERROR */, '页面转换', this.generateShowPath(pageJSPath));
609
- console.log(err);
1363
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] processStyleAssets - 页面转换异常 ${(0, util_1.getLineBreak)()}Path: ${this.generateShowPath(pageJSPath)} ${(0, util_1.getLineBreak)()}${err.message} ${(0, util_1.getLineBreak)()}`);
1364
+ (0, util_1.parseError)(err, pageJSPath, pageTemplPath);
1365
+ console.log(`页面: ${page}转换失败 ${err.message}`);
610
1366
  }
611
1367
  });
612
1368
  }
@@ -614,41 +1370,83 @@ ${code}
614
1370
  if (!components || !components.size) {
615
1371
  return;
616
1372
  }
617
- components.forEach(componentObj => {
1373
+ components.forEach((componentObj) => {
1374
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] traverseComponents - 开始转换组件 ${(0, util_1.getLineBreak)()}${componentObj.path} ${(0, util_1.getLineBreak)()}`);
618
1375
  const component = componentObj.path;
619
1376
  if (this.hadBeenBuiltComponents.has(component))
620
1377
  return;
621
1378
  this.hadBeenBuiltComponents.add(component);
622
- const componentJSPath = component + this.fileTypes.SCRIPT;
1379
+ const componentJSPath = this.getComponentPath(component, this.fileTypes.SCRIPT);
623
1380
  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;
1381
+ const componentConfigPath = this.getComponentPath(component, this.fileTypes.CONFIG);
1382
+ const componentStylePath = this.getComponentPath(component, this.fileTypes.STYLE);
1383
+ const componentTemplPath = this.getComponentPath(component, this.fileTypes.TEMPL);
627
1384
  try {
628
1385
  const param = {};
629
1386
  const depComponents = new Set();
1387
+ const pluginComponents = new Set();
630
1388
  if (!helper_1.fs.existsSync(componentJSPath)) {
631
- throw new Error(`组件 ${component} 没有 JS 文件!`);
1389
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] traverseComponents - 自定义组件 ${component} 没有 JS 文件 ${(0, util_1.getLineBreak)()}`);
1390
+ throw new util_1.IReportError(`自定义组件 ${component} 没有 JS 文件!`, 'MissingJSFileError', componentJSPath, '');
632
1391
  }
633
1392
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '组件文件', this.generateShowPath(componentJSPath));
1393
+ let componentConfig;
634
1394
  if (helper_1.fs.existsSync(componentConfigPath)) {
635
1395
  (0, helper_1.printLog)("convert" /* processTypeEnum.CONVERT */, '组件配置', this.generateShowPath(componentConfigPath));
636
1396
  const componentConfigStr = String(helper_1.fs.readFileSync(componentConfigPath));
637
- const componentConfig = JSON.parse(componentConfigStr);
1397
+ componentConfig = JSON.parse(componentConfigStr);
1398
+ }
1399
+ else if (this.entryUsingComponents) {
1400
+ componentConfig = {};
1401
+ }
1402
+ if (componentConfig) {
1403
+ // app.json中注册的组件为公共组件
1404
+ if (this.entryUsingComponents && !this.isTraversePlugin) {
1405
+ componentConfig.usingComponents = Object.assign(Object.assign({}, componentConfig.usingComponents), this.entryUsingComponents);
1406
+ }
638
1407
  const componentUsingComponnets = componentConfig.usingComponents;
639
1408
  if (componentUsingComponnets) {
640
1409
  // 页面依赖组件
641
- Object.keys(componentUsingComponnets).forEach(component => {
642
- let componentPath = path.resolve(componentConfigPath, '..', componentUsingComponnets[component]);
643
- if (!helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(componentPath))) {
644
- componentPath = path.join(this.root, componentUsingComponnets[component]);
1410
+ const usingComponents = {};
1411
+ Object.keys(componentUsingComponnets).forEach((component) => {
1412
+ var _a;
1413
+ const unResolveUseComponentPath = componentUsingComponnets[component];
1414
+ let componentPath;
1415
+ if (unResolveUseComponentPath.startsWith('plugin://')) {
1416
+ componentPath = (0, util_1.replacePluginComponentUrl)(unResolveUseComponentPath, this.pluginInfo);
1417
+ pluginComponents.add({
1418
+ name: component,
1419
+ path: componentPath,
1420
+ });
1421
+ }
1422
+ else if (this.isThirdPartyLib(unResolveUseComponentPath, path.resolve(component, '..'))) {
1423
+ (0, util_1.handleThirdPartyLib)(unResolveUseComponentPath, (_a = this.convertConfig) === null || _a === void 0 ? void 0 : _a.nodePath, this.root, this.convertRoot);
1424
+ }
1425
+ else {
1426
+ if (unResolveUseComponentPath.startsWith(this.root)) {
1427
+ componentPath = unResolveUseComponentPath;
1428
+ }
1429
+ else {
1430
+ componentPath = path.join(componentConfigPath, '..', componentUsingComponnets[component]);
1431
+ if (!helper_1.fs.existsSync((0, helper_1.resolveScriptPath)(componentPath))) {
1432
+ componentPath = path.join(this.root, componentUsingComponnets[component]);
1433
+ }
1434
+ if (!helper_1.fs.existsSync(componentPath + this.fileTypes.SCRIPT)) {
1435
+ componentPath = path.join(componentPath, `/index`);
1436
+ }
1437
+ }
1438
+ depComponents.add({
1439
+ name: component,
1440
+ path: componentPath,
1441
+ });
645
1442
  }
646
- depComponents.add({
647
- name: component,
648
- path: componentPath
649
- });
650
1443
  });
651
- delete componentConfig.usingComponents;
1444
+ if (Object.keys(usingComponents).length === 0) {
1445
+ delete componentConfig.usingComponents;
1446
+ }
1447
+ else {
1448
+ componentConfig.usingComponents = usingComponents;
1449
+ }
652
1450
  }
653
1451
  param.json = JSON.stringify(componentConfig);
654
1452
  }
@@ -664,7 +1462,11 @@ ${code}
664
1462
  }
665
1463
  param.path = path.dirname(componentJSPath);
666
1464
  param.rootPath = this.root;
1465
+ param.logFilePath = global_1.globals.logFilePath;
1466
+ param.templatePath = componentTemplPath;
667
1467
  const taroizeResult = taroize(Object.assign(Object.assign({}, param), { framework: this.framework }));
1468
+ global_1.globals.errCodeMsgs.push(...taroizeResult.errCodeMsgs);
1469
+ global_1.globals.currentParseFile = componentConfigPath;
668
1470
  const { ast, scriptFiles } = this.parseAst({
669
1471
  ast: taroizeResult.ast,
670
1472
  sourceFilePath: componentJSPath,
@@ -673,7 +1475,8 @@ ${code}
673
1475
  ? componentStylePath.replace(path.extname(componentStylePath), OUTPUT_STYLE_EXTNAME)
674
1476
  : null,
675
1477
  depComponents,
676
- imports: taroizeResult.imports
1478
+ imports: taroizeResult.imports,
1479
+ pluginComponents: pluginComponents,
677
1480
  });
678
1481
  const jsCode = (0, astConvert_1.generateMinimalEscapeCode)(ast);
679
1482
  this.writeFileToTaro(this.getComponentDest(componentDistJSPath), this.formatFile(jsCode, taroizeResult.template));
@@ -681,19 +1484,22 @@ ${code}
681
1484
  if (componentStyle) {
682
1485
  this.traverseStyle(componentStylePath, componentStyle);
683
1486
  }
1487
+ global_1.globals.currentParseFile = componentJSPath;
684
1488
  this.generateScriptFiles(scriptFiles);
685
1489
  this.traverseComponents(depComponents);
686
1490
  }
687
1491
  catch (err) {
688
1492
  (0, helper_1.printLog)("error" /* processTypeEnum.ERROR */, '组件转换', this.generateShowPath(componentJSPath));
689
- console.log(err);
1493
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] traverseComponents - 组件转换异常 ${(0, util_1.getLineBreak)()}Path: ${this.generateShowPath(componentJSPath)} ${(0, util_1.getLineBreak)()}${err} ${(0, util_1.getLineBreak)()}`);
1494
+ console.log(`组件转换失败 ${err.message}`);
1495
+ (0, util_1.parseError)(err, componentJSPath, componentTemplPath);
690
1496
  }
691
1497
  });
692
1498
  }
693
1499
  styleUnitTransform(filePath, content) {
694
1500
  return __awaiter(this, void 0, void 0, function* () {
695
1501
  const postcssResult = yield (0, postcss_1.default)([unitTransform()]).process(content, {
696
- from: filePath
1502
+ from: filePath,
697
1503
  });
698
1504
  return postcssResult;
699
1505
  });
@@ -705,19 +1511,17 @@ ${code}
705
1511
  styleDist = path.dirname(styleDist);
706
1512
  while (token === null || token === void 0 ? void 0 : token.length) {
707
1513
  let url = token[1];
708
- if (url &&
709
- url.indexOf('data:') !== 0 &&
710
- url.indexOf('#') !== 0 &&
711
- !(/^[a-z]+:\/\//.test(url))) {
1514
+ if (url && url.indexOf('data:') !== 0 && url.indexOf('#') !== 0 && !/^[a-z]+:\/\//.test(url)) {
712
1515
  url = url.trim();
713
1516
  url.replace(/[/\\]/g, path.sep);
714
1517
  url = url.split('?')[0];
715
1518
  url = url.split('#')[0];
716
- const originPath = path.resolve(stylePath, url);
717
- const destPath = path.resolve(styleDist, url);
1519
+ const originPath = path.join(stylePath, url);
1520
+ const destPath = path.join(styleDist, url);
718
1521
  const destDir = path.dirname(destPath);
719
1522
  if (!helper_1.fs.existsSync(originPath)) {
720
1523
  (0, helper_1.printLog)("warning" /* processTypeEnum.WARNING */, '静态资源', `找不到资源:${originPath}`);
1524
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] processStyleAssets - 找不到资源 ${(0, util_1.getLineBreak)()}${originPath} ${(0, util_1.getLineBreak)()}`);
721
1525
  }
722
1526
  else if (!helper_1.fs.existsSync(destPath)) {
723
1527
  helper_1.fs.ensureDirSync(destDir);
@@ -730,6 +1534,7 @@ ${code}
730
1534
  }
731
1535
  traverseStyle(filePath, style) {
732
1536
  return __awaiter(this, void 0, void 0, function* () {
1537
+ (0, util_1.updateLogFileContent)(`INFO [taro-cli-convertor] traverseStyle - 开始转换样式 ${(0, util_1.getLineBreak)()}${filePath} ${(0, util_1.getLineBreak)()}`);
733
1538
  const { imports, content } = processStyleImports(style, (str, stylePath) => {
734
1539
  let relativePath = stylePath;
735
1540
  if (path.isAbsolute(relativePath)) {
@@ -743,10 +1548,10 @@ ${code}
743
1548
  this.writeFileToTaro(styleDist, css);
744
1549
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '样式文件', this.generateShowPath(styleDist));
745
1550
  if (imports && imports.length) {
746
- imports.forEach(importItem => {
1551
+ imports.forEach((importItem) => {
747
1552
  const importPath = path.isAbsolute(importItem)
748
1553
  ? path.join(this.root, importItem)
749
- : path.resolve(path.dirname(filePath), importItem);
1554
+ : path.join(path.dirname(filePath), importItem);
750
1555
  if (helper_1.fs.existsSync(importPath)) {
751
1556
  const styleText = helper_1.fs.readFileSync(importPath).toString();
752
1557
  this.traverseStyle(importPath, styleText);
@@ -755,67 +1560,114 @@ ${code}
755
1560
  }
756
1561
  });
757
1562
  }
1563
+ /**
1564
+ * 转换插件
1565
+ */
1566
+ traversePlugin() {
1567
+ if (this.projectConfig.compileType !== "plugin" /* Constants.PLUGIN */) {
1568
+ return;
1569
+ }
1570
+ this.isTraversePlugin = true;
1571
+ // 转换插件plugin.json中导出的页面
1572
+ this.traversePages(this.pluginInfo.pluginRoot, this.pluginInfo.pages);
1573
+ // 转换插件plugin.json中导出的组件
1574
+ this.traverseComponents(this.pluginInfo.publicComponents);
1575
+ // 转换插件的工具文件
1576
+ global_1.globals.currentParseFile = this.pluginInfo.entryFilePath;
1577
+ this.generateScriptFiles(new Set([this.pluginInfo.entryFilePath]));
1578
+ }
1579
+ /**
1580
+ * 解析插件配置信息
1581
+ *
1582
+ * @param pluginInfo
1583
+ */
1584
+ parsePluginConfig(pluginInfo) {
1585
+ // 处理plugin.json,并存储到pluginInfo中
1586
+ const pluginConfigPath = path.join(pluginInfo.pluginRoot, "plugin.json" /* Constants.PLUGIN_JSON */);
1587
+ if (helper_1.fs.existsSync(pluginConfigPath)) {
1588
+ try {
1589
+ const pluginConfigJson = JSON.parse(String(helper_1.fs.readFileSync(pluginConfigPath)));
1590
+ if (!pluginConfigJson) {
1591
+ (0, util_1.createErrorCodeMsg)('emptyPluginConfig', '插件配置信息为空,请检查!', '', pluginConfigPath);
1592
+ console.log('插件配置信息为空,请检查!');
1593
+ (0, util_1.updateLogFileContent)(`WARN [taro-cli-convertor] parsePluginConfig - 插件配置信息为空 ${(0, util_1.getLineBreak)()}`);
1594
+ return;
1595
+ }
1596
+ // 解析publicComponents信息
1597
+ const publicComponents = pluginConfigJson.publicComponents;
1598
+ if (publicComponents && Object.keys(publicComponents).length) {
1599
+ for (const key in publicComponents) {
1600
+ pluginInfo.publicComponents.add({
1601
+ name: key,
1602
+ path: path.join(pluginInfo.pluginRoot, publicComponents[key]),
1603
+ });
1604
+ }
1605
+ }
1606
+ // 解析pages信息
1607
+ const pages = pluginConfigJson.pages;
1608
+ if (pages && Object.keys(pages).length) {
1609
+ for (const pageName in pages) {
1610
+ const pagePath = pages[pageName];
1611
+ pluginInfo.pages.add(pagePath);
1612
+ pluginInfo.pagesMap.set(pageName, pagePath);
1613
+ }
1614
+ }
1615
+ // 解析入口文件信息
1616
+ const entryFilePath = pluginConfigJson.main;
1617
+ if (entryFilePath) {
1618
+ pluginInfo.entryFilePath = path.join(pluginInfo.pluginRoot, entryFilePath);
1619
+ }
1620
+ }
1621
+ catch (err) {
1622
+ (0, util_1.createErrorCodeMsg)('PluginJsonParsingError', '解析plugin.json失败,请检查!', '', pluginConfigPath);
1623
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] parsePluginConfig - plugin.json 解析异常 ${(0, util_1.getLineBreak)()}${err} ${(0, util_1.getLineBreak)()}`);
1624
+ console.log('解析plugin.json失败,请检查!');
1625
+ process.exit(1);
1626
+ }
1627
+ }
1628
+ }
758
1629
  generateConfigFiles() {
759
- const creator = new cli_1.Creator();
1630
+ const creator = new binding_1.Creator((0, cli_1.getRootPath)(), this.convertRoot);
1631
+ const dateObj = new Date();
1632
+ const date = `${dateObj.getFullYear()}-${dateObj.getMonth() + 1}-${dateObj.getDate()}`;
760
1633
  const templateName = 'default';
761
- const configDir = path.join(this.convertRoot, 'config');
762
- const pkgPath = path.join(this.convertRoot, 'package.json');
763
1634
  const projectName = 'taroConvert';
764
- const description = '';
765
1635
  const version = (0, util_1.getPkgVersion)();
766
- const dateObj = new Date();
767
- const date = `${dateObj.getFullYear()}-${dateObj.getMonth() + 1}-${dateObj.getDate()}`;
768
- creator.template(templateName, 'package.json.tmpl', pkgPath, {
1636
+ const description = '';
1637
+ const ps = [];
1638
+ const createOpts = {
1639
+ css: "Sass" /* CSSType.Sass */,
1640
+ cssExt: '.scss',
1641
+ framework: this.framework,
769
1642
  description,
770
1643
  projectName,
771
1644
  version,
772
- css: 'sass',
773
- typescript: false,
774
- template: templateName,
775
- framework: this.framework,
776
- compiler: 'webpack5'
777
- });
778
- creator.template(templateName, path.join('config', 'index.js'), path.join(configDir, 'index.js'), {
779
1645
  date,
780
- projectName,
781
- framework: this.framework,
782
- compiler: 'webpack5'
783
- });
784
- creator.template(templateName, path.join('config', 'dev.js'), path.join(configDir, 'dev.js'), {
785
- framework: this.framework
786
- });
787
- creator.template(templateName, path.join('config', 'prod.js'), path.join(configDir, 'prod.js'), {
788
- framework: this.framework
789
- });
790
- creator.template(templateName, 'project.config.json', path.join(this.convertRoot, 'project.config.json'), {
791
- description,
792
- projectName,
793
- framework: this.framework
794
- });
795
- creator.template(templateName, '.gitignore', path.join(this.convertRoot, '.gitignore'));
796
- creator.template(templateName, '.editorconfig', path.join(this.convertRoot, '.editorconfig'));
797
- creator.template(templateName, '.eslintrc.js', path.join(this.convertRoot, '.eslintrc.js'), {
798
- typescript: false,
799
- framework: this.framework
800
- });
801
- creator.template(templateName, 'babel.config.js', path.join(this.convertRoot, 'babel.config.js'), {
802
1646
  typescript: false,
803
- framework: this.framework
804
- });
805
- creator.template(templateName, path.join('src', 'index.html'), path.join(this.convertDir, 'index.html'), {
806
- projectName
807
- });
808
- creator.fs.commit(() => {
809
- const pkgObj = JSON.parse(helper_1.fs.readFileSync(pkgPath).toString());
1647
+ template: templateName,
1648
+ compiler: "Webpack5" /* CompilerType.Webpack5 */,
1649
+ };
1650
+ ps.push(creator.createFileFromTemplate(templateName, 'package.json.tmpl', 'package.json', createOpts));
1651
+ ps.push(creator.createFileFromTemplate(templateName, 'config/index.js', 'config/index.js', createOpts));
1652
+ ps.push(creator.createFileFromTemplate(templateName, 'config/dev.js', 'config/dev.js', createOpts));
1653
+ ps.push(creator.createFileFromTemplate(templateName, 'config/prod.js', 'config/prod.js', createOpts));
1654
+ ps.push(creator.createFileFromTemplate(templateName, 'project.config.json', 'project.config.json', createOpts));
1655
+ ps.push(creator.createFileFromTemplate(templateName, '_gitignore', '.gitignore', createOpts));
1656
+ ps.push(creator.createFileFromTemplate(templateName, '_editorconfig', '.editorconfig', createOpts));
1657
+ ps.push(creator.createFileFromTemplate(templateName, '_eslintrc', '.eslintrc', createOpts));
1658
+ ps.push(creator.createFileFromTemplate(templateName, 'babel.config.js', 'babel.config.js', createOpts));
1659
+ ps.push(creator.createFileFromTemplate(templateName, 'src/index.html', 'src/index.html', createOpts));
1660
+ Promise.all(ps).then(() => {
1661
+ const pkgObj = JSON.parse(helper_1.fs.readFileSync(path.join(this.convertRoot, 'package.json')).toString());
810
1662
  pkgObj.dependencies['@tarojs/with-weapp'] = `^${version}`;
811
- helper_1.fs.writeJSONSync(pkgPath, pkgObj, {
1663
+ helper_1.fs.writeJSONSync(path.join(this.convertRoot, 'package.json'), pkgObj, {
812
1664
  spaces: 2,
813
- EOL: '\n'
1665
+ EOL: '\n',
814
1666
  });
815
- (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(configDir, 'index.js')));
816
- (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(configDir, 'dev.js')));
817
- (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(configDir, 'prod.js')));
818
- (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(pkgPath));
1667
+ (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(this.convertRoot, 'package.json')));
1668
+ (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(this.convertRoot, 'config/index.js')));
1669
+ (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(this.convertRoot, 'config/dev.js')));
1670
+ (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(this.convertRoot, 'config/prod')));
819
1671
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(this.convertRoot, 'project.config.json')));
820
1672
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(this.convertRoot, '.gitignore')));
821
1673
  (0, helper_1.printLog)("generate" /* processTypeEnum.GENERATE */, '文件', this.generateShowPath(path.join(this.convertRoot, '.editorconfig')));
@@ -824,15 +1676,56 @@ ${code}
824
1676
  this.showLog();
825
1677
  });
826
1678
  }
1679
+ /**
1680
+ * generateReport: 为转换后的 taroConvert 工程添加转换报告
1681
+ */
1682
+ generateReport() {
1683
+ const reportDir = path.join(this.convertRoot, 'report');
1684
+ const iconFilePath = path.join(__dirname, '../', 'report/favicon.ico');
1685
+ const reportIndexFilePath = path.join(__dirname, '../', 'report/index.html');
1686
+ const reportBundleFilePath = path.join(__dirname, '../', 'report/static/js/bundle.js');
1687
+ const reportStyleFilePath = path.join(__dirname, '../', 'report/static/css/main.css');
1688
+ const fontBlodFilePath = path.join(__dirname, '../', 'report/static/media/HarmonyOS_Sans_SC_Bold.ttf');
1689
+ const fontMediumFilePath = path.join(__dirname, '../', 'report/static/media/HarmonyOS_Sans_SC_Medium.ttf');
1690
+ const errMsgList = (0, util_1.paseGlobalErrMsgs)(global_1.globals.errCodeMsgs);
1691
+ const reportData = {
1692
+ projectName: (0, util_1.parseProjectName)(this.root),
1693
+ projectPath: this.root,
1694
+ pagesNum: this.pages.size,
1695
+ filesNum: (0, util_1.computeProjectFileNums)(this.root),
1696
+ errMsgList: errMsgList,
1697
+ };
1698
+ try {
1699
+ (0, util_1.generateReportFile)(iconFilePath, reportDir, 'favicon.ico');
1700
+ (0, util_1.generateReportFile)(reportIndexFilePath, reportDir, 'index.html');
1701
+ (0, util_1.generateReportFile)(reportBundleFilePath, path.join(reportDir, '/static/js'), 'bundle.js', reportData);
1702
+ (0, util_1.generateReportFile)(reportStyleFilePath, path.join(reportDir, '/static/css'), 'main.css');
1703
+ (0, util_1.generateReportFile)(fontBlodFilePath, path.join(reportDir, '/static/media'), 'HarmonyOS_Sans_SC_Bold.ttf');
1704
+ (0, util_1.generateReportFile)(fontMediumFilePath, path.join(reportDir, '/static/media'), 'HarmonyOS_Sans_SC_Medium.ttf');
1705
+ console.log(`转换报告已生成,请在浏览器中打开 ${path.join(this.convertRoot, 'report', 'report.html')} 查看转换报告`);
1706
+ }
1707
+ catch (error) {
1708
+ console.log(`报告生成失败 ${error.message}`);
1709
+ }
1710
+ }
827
1711
  showLog() {
828
- console.log();
829
1712
  console.log(`${helper_1.chalk.green('✔ ')} 转换成功,请进入 ${helper_1.chalk.bold('taroConvert')} 目录下使用 npm 或者 yarn 安装项目依赖后再运行!`);
830
1713
  }
831
1714
  run() {
832
- this.framework = 'react';
833
- this.generateEntry();
834
- this.traversePages();
835
- this.generateConfigFiles();
1715
+ try {
1716
+ this.framework = "React" /* FrameworkType.React */;
1717
+ this.generateEntry();
1718
+ this.traversePages(this.root, this.pages);
1719
+ this.traversePlugin();
1720
+ this.generateConfigFiles();
1721
+ }
1722
+ catch (error) {
1723
+ (0, util_1.updateLogFileContent)(`ERROR [taro-cli-convertor] run - 转换异常 ${(0, util_1.getLineBreak)()}${error} ${(0, util_1.getLineBreak)()}`);
1724
+ }
1725
+ finally {
1726
+ (0, util_1.printToLogFile)();
1727
+ this.generateReport();
1728
+ }
836
1729
  }
837
1730
  }
838
1731
  exports.default = Convertor;