• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const path = require('path');
17const fs = require('fs');
18const ts = require('typescript');
19const ExcelJS = require('exceljs');
20const compressing = require('compressing');
21const { readFile, getSubsystemBySyscap, getApiInfoWithFlag, getApiInfoDeleteDtsPath } = require('./util');
22const { parse } = require('./collect_base_api');
23const { allMergeData } = require('./format_data');
24let methodType = '';
25
26function getSubsystemJson(jsonDir) {
27  let fileContent = fs.readFileSync(jsonDir, 'utf-8');
28  let subsystems = JSON.parse(fileContent);
29  const subsystemMap = new Map();
30  const fileNameMap = new Map();
31  subsystems.forEach(element => {
32    subsystemMap.set(element.syscap, element.subsystem);
33    fileNameMap.set(element.syscap, element.fileName);
34  });
35  return { subsystemMap, fileNameMap };
36}
37
38// 对比新旧版本文件列表
39function compileFiles(newFiles, oldFiles) {
40  const newFileNames = [];
41  const oldFileNames = [];
42  newFiles.forEach(file => {
43    const fileName = path.basename(file).replace(/.d.ts$/g, '.ts');
44    newFileNames.push(fileName);
45  });
46  oldFiles.forEach(file => {
47    const fileName = path.basename(file).replace(/.d.ts$/g, '.ts');
48    oldFileNames.push(fileName);
49  });
50
51  //保存有差异的信息
52  const compileApiInfos = [];
53  // 旧版本不存在新版本中的文件,表示新增
54  newFileNames.forEach(fileName => {
55    let index = oldFileNames.indexOf(fileName);
56    if (index < 0) {
57      compileApiInfos.push({
58        flag: '新版本新增',
59        fileName: fileName,
60        filePath: newFiles[newFileNames.indexOf(fileName)],
61      });
62    }
63  });
64  // 新版本不在在旧版本中的文件,表示删除
65  oldFileNames.forEach(fileName => {
66    let index = newFileNames.indexOf(fileName);
67    if (index < 0) {
68      compileApiInfos.push({
69        flag: '新版本删除',
70        fileName: fileName,
71        filePath: oldFiles[oldFileNames.indexOf(fileName)],
72      });
73    }
74  });
75
76  return compileApiInfos;
77}
78
79// 根据文件列表获取api信息数组
80function getFilesApi(files) {
81  const fileContentList = [];
82  files.forEach(file => {
83    let fileContent = fs.readFileSync(file, 'utf-8');
84    fileContentList.push({
85      fileName: path.basename(file).replace(/.d.ts$/g, '.ts'),
86      fileContent: fileContent,
87      fileRoot: file,
88    });
89
90  });
91  const api = parse(fileContentList);
92  return api;
93}
94
95function getDIffApisWithCompile(newFiles, oldFiles) {
96  const newFilesApi = getFilesApi(newFiles);
97  const oldFilesApi = getFilesApi(oldFiles);
98  // 去掉dtspath后的
99  const tmpNewApis = [];
100  newFilesApi.forEach(newApi => {
101    tmpNewApis.push(JSON.stringify(getApiInfoDeleteDtsPath(newApi)));
102  });
103  const tmpOldApis = [];
104  oldFilesApi.forEach(oldApi => {
105    tmpOldApis.push(JSON.stringify(getApiInfoDeleteDtsPath(oldApi)));
106  });
107
108  let hasFunTypeNewApis = [];
109  let hasFunTypeOldApis = [];
110  hasFunTypeNewApis = deleteRepeatApi(tmpOldApis, tmpNewApis, newFilesApi, oldFilesApi).newDiffApiArr;
111  hasFunTypeOldApis = deleteRepeatApi(tmpOldApis, tmpNewApis, newFilesApi, oldFilesApi).oldDiffApiArr;
112
113  let newDiffApis = [];
114  let oldDiffApis = [];
115  newDiffApis = collectSameTypeFun(hasFunTypeNewApis);
116  oldDiffApis = collectSameTypeFun(hasFunTypeOldApis);
117  const subsystemMap = getSubsystemJson(subsystemDir).subsystemMap;
118  const fileNameMap = getSubsystemJson(subsystemDir).fileNameMap;
119  const diffApis = [];
120  getDiffApisBaseNew(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap);
121  getDiffApisBaseOld(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap);
122  return diffApis;
123}
124
125function deleteRepeatApi(oldApis, newApis, newFilesApi, oldFilesApi) {
126  let newDiffApiArr = [];
127  let oldDiffApiArr = [];
128  for (let i = 0; i < newApis.length; i++) {
129    const newApi = newApis[i];
130    let index = oldApis.indexOf(newApi);
131    if (index < 0) {
132      let includeTypeApi = addMethodType(newFilesApi[i]);
133      newDiffApiArr.push(includeTypeApi);
134    }
135  }
136
137  for (let i = 0; i < oldApis.length; i++) {
138    const oldApi = oldApis[i];
139    let index = newApis.indexOf(oldApi);
140    if (index < 0) {
141      let includeTypeApi = addMethodType(oldFilesApi[i]);
142      oldDiffApiArr.push(includeTypeApi);
143    }
144  }
145  return { newDiffApiArr, oldDiffApiArr };
146}
147
148function collectSameTypeFun(apiArr) {
149  apiArr.forEach(api => {
150    let sameNameFun = '';
151    // 标记既不是Promise也不是callback的同名函数
152    let number = 0;
153    let sameNamePromiseText = '';
154    apiArr.forEach(newApi => {
155      if (api.dtsPath.replace(newDir, '') === newApi.dtsPath.replace(newDir, '') && api.className === newApi.className &&
156        api.methodName === newApi.methodName && api.apiType === 'Method' && api.funType === newApi.funType) {
157        if (sameNameFun.indexOf(newApi.methodText) < 0 && api.funType === 'callback') {
158          sameNameFun += `\n${newApi.methodText}`;
159          api.callbackMethodText = sameNameFun;
160        } else if (sameNamePromiseText.indexOf(newApi.methodText) < 0 && api.funType === 'Promise') {
161          sameNamePromiseText += `\n${newApi.methodText}`;
162          api.promiseMethodText = sameNamePromiseText;
163        } else if (!api.funType) {
164          number++;
165          api.note = number;
166        }
167      }
168    });
169  });
170  return apiArr;
171}
172
173function addMethodType(baseApi) {
174  let methodContent = `interface test{
175              ${baseApi.methodText}
176          }`;
177  getMethodType(methodContent, filterType);
178  if (methodType === 'callback' || methodType === 'Promise') {
179    baseApi.funType = methodType;
180  }
181  return baseApi;
182}
183
184function getMethodType(content, callback) {
185  ts.transpileModule(content, {
186    compilerOptions: {
187      'target': ts.ScriptTarget.ES2017,
188    },
189    fileName: 'index.ets',
190    transformers: { before: [callback()] },
191  });
192}
193
194function filterType() {
195  return (context) => {
196    methodType = '';
197    return (node) => {
198      getType(node);
199      return node;
200    };
201    function getType(node) {
202      // add function type(callback or Promise)
203      if (ts.isFunctionDeclaration(node) || ts.isMethodSignature(node)) {
204        getFunType(node);
205      }
206      return ts.visitEachChild(node, getType, context);
207    }
208  };
209}
210
211function getFunType(node) {
212  if (node.type && ts.isTypeReferenceNode(node.type)) {
213    methodType = node.type.typeName.escapedText;
214  } else if (node.parameters.length > 0) {
215    const parameter = node.parameters[node.parameters.length - 1];
216    if (parameter.name.escapedText === 'callback') {
217      methodType = parameter.name.escapedText;
218    }
219  } else {
220    methodType = '';
221  }
222}
223
224function collectDeprecatedDiff(newDeprecated, oldDeprecated, startDiffNew, startDiffOld, diffApis, subsystemMap,
225  notes, fileNameMap, newApi) {
226  flag = '废弃版本有变化';
227  diffOld = startDiffOld + '废弃版本:' + oldDeprecated;
228  const useinsteadInfo = newApi.useinsteadInfo instanceof Object ? newApi.useinsteadInfo.new : newApi.useinsteadInfo;
229  if (newApi.useinsteadInfo) {
230    diffNew = `${startDiffNew}废弃版本:${newDeprecated}\n代替接口:${useinsteadInfo}`;
231  } else {
232    diffNew = startDiffNew + '废弃版本:' + newDeprecated;
233  }
234  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
235  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
236}
237
238function getDiffApisBaseNew(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap) {
239  const notes = '';
240  const diffMethodTextSet = new Set();
241  newDiffApis.forEach(newApi => {
242    let diffOld = 'NA';
243    let diffNew = 'NA';
244    const tmpApis = [];
245
246    oldDiffApis.forEach(oldApi => {
247      if (newApi.dtsPath.replace(newDir, '') === oldApi.dtsPath.replace(oldDir, '')) {
248        tmpApis.push(oldApi);
249      }
250    });
251    if (tmpApis.length === 0) {
252      collectNewFileApi(newApi, subsystemMap, notes, fileNameMap, diffApis, diffOld);
253    } else {
254      if (newApi.apiType === 'import') {
255        collectImportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap);
256      } else if (newApi.apiType === 'export') {
257        collectExportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap);
258      } else {
259        let oldSameClassApis = handleApiByClassName(tmpApis, newApi, newDiffApis).oldSameClassApi;
260        let oldMethodTexts = handleApiByClassName(tmpApis, newApi, newDiffApis).oldMethodTexts;
261        collectSameClassDiff(oldSameClassApis, newApi, diffNew, diffOld, diffApis, subsystemMap, fileNameMap, diffMethodTextSet);
262        getNewAddApi(oldMethodTexts, diffApis, subsystemMap, fileNameMap, diffMethodTextSet, newApi);
263      }
264    }
265  });
266}
267function collectSameClassDiff(oldSameClassApis, newApi, diffNew, diffOld, diffApis, subsystemMap, fileNameMap, diffMethodTextSet) {
268  const notes = '';
269  if (oldSameClassApis.length === 0) {
270    flag = '新增';
271    if (newApi.methodName === '') {
272      diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className;
273    } else {
274      diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className +
275        '\n方法 or 属性:' + newApi.methodText;
276    }
277    let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
278    diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
279  } else {
280    oldSameClassApis.forEach(oldApi => {
281      if (newApi.methodName === oldApi.methodName && newApi.apiType.toString() === oldApi.apiType.toString()) {
282        collectChangePart(newApi, oldApi, diffApis, subsystemMap, fileNameMap, diffMethodTextSet);
283      }
284    });
285
286  }
287}
288function getNewAddApi(oldMethodTexts, diffApis, subsystemMap, fileNameMap, diffMethodTextSet, newApi) {
289  if (!oldMethodTexts.has(newApi.methodText.replace(/\r|\n|\s+|\,|\;/g, '')) &&
290    !diffMethodTextSet.has(newApi.methodText)) {
291    const notes = '';
292    const flag = '新增';
293    const diffNew = '类名:' + newApi.className + '\n方法or属性:' + newApi.methodText;
294    const diffOld = 'NA';
295    let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
296    diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
297  }
298}
299function collectChangePart(newApi, oldApi, diffApis, subsystemMap, fileNameMap, diffMethodTextSet) {
300  let startDiffOld = '';
301  let startDiffNew = '';
302  const NOTE_NUMBER = 2;
303  if (newApi.methodName === '') {
304    startDiffOld = '类名:' + oldApi.className + '\n';
305    startDiffNew = '类名:' + newApi.className + '\n';
306  } else {
307    startDiffOld = '类名:' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText + '\n';
308    startDiffNew = '类名:' + newApi.className + '\n方法 or 属性:' + newApi.methodText + '\n';
309  }
310  if (isCallbackTypeFun(newApi, oldApi, 'callback')) {
311    diffMethodTextSet.add(newApi.methodText);
312    collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.callbackMethodText,
313      oldApi.callbackMethodText, subsystemMap, fileNameMap);
314  }
315  if (isPromiseTypeFun(newApi, oldApi, 'Promise')) {
316    diffMethodTextSet.add(newApi.methodText);
317    collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.promiseMethodText,
318      oldApi.promiseMethodText, subsystemMap, fileNameMap);
319  }
320  if (!newApi.funType && !oldApi.funType && newApi.methodText !== oldApi.methodText && newApi.note < NOTE_NUMBER) {
321    diffMethodTextSet.add(newApi.methodText);
322    collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.methodText,
323      oldApi.methodText, subsystemMap, fileNameMap);
324  }
325  if (newApi.methodText === oldApi.methodText) {
326    collectNoteDiff(newApi.version, oldApi.version, newApi.deprecated, oldApi.deprecated, newApi.errorCode,
327      oldApi.errorCode, newApi.sysCap, oldApi.sysCap, newApi.isSystemApi, oldApi.isSystemApi, newApi.permission,
328      oldApi.permission, newApi.model, oldApi.model, newApi.typeInfo, oldApi.typeInfo, startDiffNew, startDiffOld,
329      diffApis, subsystemMap, fileNameMap, newApi);
330  }
331
332}
333function isCallbackTypeFun(newApi, oldApi, funType) {
334  if (newApi.funType === funType && oldApi.funType === funType &&
335    newApi.callbackMethodText !== oldApi.callbackMethodText) {
336    return true;
337  } else {
338    return false;
339  }
340}
341function isPromiseTypeFun(newApi, oldApi, funType) {
342  if (newApi.funType === funType && oldApi.funType === funType &&
343    newApi.promiseMethodText !== oldApi.promiseMethodText) {
344    return true;
345  } else {
346    return false;
347  }
348}
349
350function collectNoteDiff(newVersion, oldVersion, newDeprecated, oldDeprecated, newErrorCode, oldErrorCode, newSyscap,
351  oldSyscap, newIsSystemApi, oldIsSystemApi, newPermission, oldPermission, newModel, oldModel, newTypeInfo,
352  oldTypeInfo, startDiffNew, startDiffOld, diffApis, subsystemMap, fileNameMap, newApi) {
353  const notes = '';
354  if (newVersion !== oldVersion) {
355    collectVersionDiff(newVersion, oldVersion, startDiffNew, startDiffOld,
356      diffApis, subsystemMap, notes, fileNameMap, newApi);
357  }
358  if (newDeprecated !== oldDeprecated) {
359    collectDeprecatedDiff(newDeprecated, oldDeprecated, startDiffNew, startDiffOld,
360      diffApis, subsystemMap, notes, fileNameMap, newApi);
361  }
362  if (newErrorCode !== oldErrorCode) {
363    collectErrorCodeDiff(newErrorCode, oldErrorCode, startDiffNew, startDiffOld,
364      diffApis, subsystemMap, notes, fileNameMap, newApi);
365  }
366  if (newSyscap !== oldSyscap) {
367    collectSyscapDiff(newSyscap, oldSyscap, startDiffNew, startDiffOld,
368      diffApis, subsystemMap, notes, fileNameMap, newApi);
369  }
370  if (newIsSystemApi !== oldIsSystemApi) {
371    collectSystemApiDiff(newIsSystemApi, oldIsSystemApi, startDiffNew, startDiffOld,
372      diffApis, subsystemMap, notes, fileNameMap, newApi);
373  }
374  if (newPermission !== oldPermission) {
375    collectPermissionDiff(newPermission, oldPermission, startDiffNew, startDiffOld,
376      diffApis, subsystemMap, notes, fileNameMap, newApi);
377  }
378  if (newModel !== oldModel) {
379    collectModelDiff(newModel, oldModel, startDiffNew, startDiffOld,
380      diffApis, subsystemMap, notes, fileNameMap, newApi);
381  }
382  if (newTypeInfo !== oldTypeInfo) {
383    collectTypeDiff(newTypeInfo, oldTypeInfo, startDiffNew, startDiffOld,
384      diffApis, subsystemMap, notes, fileNameMap, newApi);
385  }
386}
387
388function collectTypeDiff(newType, oldType, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) {
389  let flag = '';
390  if (oldType !== newType) {
391    flag = 'type有变化';
392  }
393  if (flag) {
394    diffOld = startDiffOld + 'type:' + oldType;
395    diffNew = startDiffNew + 'type:' + newType;
396    let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
397    diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
398  }
399}
400
401function collectNewFileApi(newApi, subsystemMap, notes, fileNameMap, diffApis, diffOld) {
402  const flag = '新增';
403  let diffNew = '';
404  if (newApi.apiType === 'import') {
405    diffNew = '模块名: ' + newApi.packageName + '\nimport 信息: ' + newApi.headimport;
406  } else if (newApi.apiType === 'export') {
407    diffNew = '模块名: ' + newApi.packageName + '\nexport 信息: ' + newApi.endexport;
408  } else if (newApi.methodName === '') {
409    diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className;
410  } else {
411    diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className + '\n方法 or 属性: ' + newApi.methodText;
412  }
413  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
414  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
415}
416
417function collectImportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap) {
418  const tmpApis2 = [];
419  tmpApis.forEach(oldApi => {
420    if (oldApi.apiType === 'import' && newApi.headimport === oldApi.headimport) {
421      tmpApis2.push(oldApi);
422    }
423  });
424
425  if (tmpApis2.length === 0) {
426    flag = '新增';
427    diffNew = '模块名: ' + newApi.packageName + '\nimport 信息: ' + newApi.headimport;
428  }
429  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
430  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
431}
432
433function collectExportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap) {
434  const tmpApis3 = [];
435  tmpApis.forEach(oldApi => {
436    if (oldApi.apiType === 'export' && newApi.endexport === oldApi.endexport) {
437      tmpApis3.push(oldApi);
438    }
439  });
440  if (tmpApis3.length === 0) {
441    flag = '新增';
442    diffNew = '模块名: ' + newApi.packageName + '\nexport 信息: ' + newApi.endexport;
443  }
444  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
445  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
446}
447
448function handleApiByClassName(tmpApis, newApi, newDiffApis) {
449  const oldSameClassApi = [];
450  const newSameClassApi = [];
451  const oldMethodTexts = new Set([]);
452  const newMethodTexts = new Set([]);
453  let equalClassName = 'N/A';
454  tmpApis.forEach(oldApi => {
455    if (newApi.className === oldApi.className) {
456      oldSameClassApi.push(oldApi);
457      equalClassName = oldApi.className;
458      oldMethodTexts.add(oldApi.methodText.replace(/\r|\n|\s+|\,|\;/g, ''));
459    }
460  });
461  newDiffApis.forEach(apiText => {
462    if (apiText.className === equalClassName) {
463      newMethodTexts.add(apiText.methodText.replace(/\r|\n|\s+|\,|\;/g, ''));
464      newSameClassApi.push(apiText);
465    }
466  });
467  return { oldSameClassApi, oldMethodTexts, newMethodTexts };
468}
469
470function collectVersionDiff(newVersion, oldVersion, startDiffNew, startDiffOld, diffApis,
471  subsystemMap, notes, fileNameMap, newApi) {
472  flag = '起始版本有变化';
473  diffOld = startDiffOld + '起始版本:' + oldVersion;
474  diffNew = startDiffNew + '起始版本:' + newVersion;
475  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
476  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
477}
478
479function collectModelDiff(newModel, oldModel, startDiffNew, startDiffOld, diffApis,
480  subsystemMap, notes, fileNameMap, newApi) {
481  flag = 'model有变化';
482  diffOld = startDiffOld + 'model:' + oldModel;
483  diffNew = startDiffNew + 'model:' + newModel;
484  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
485  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
486}
487
488function collectPermissionDiff(newPermission, oldPermission, startDiffNew, startDiffOld, diffApis,
489  subsystemMap, notes, fileNameMap, newApi) {
490  flag = getPermissionFlag(oldPermission, newPermission);
491  if (flag !== '格式变化') {
492    diffOld = startDiffOld + '权限:' + oldPermission;
493    diffNew = startDiffNew + '权限:' + newPermission;
494    let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
495    diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
496  }
497}
498
499function collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newMethodText, oldMethodText,
500  subsystemMap, fileNameMap) {
501  flag = getMethodFlag(oldMethodText, newMethodText);
502  const note = '去重';
503  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
504  if (flag === '函数有变化') {
505    diffOld = startDiffOld;
506    diffNew = startDiffNew;
507    diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, note, fileNameMap));
508  }
509}
510
511function collectErrorCodeDiff(newErrorCode, oldErrorCode, startDiffNew, startDiffOld, diffApis, subsystemMap, notes,
512  fileNameMap, newApi) {
513  flag = oldErrorCode === 'N/A' ? '新增(错误码)' : 'API修改(错误码)';
514  if (flag === '新增(错误码)') {
515    diffOld = 'NA';
516  } else if (flag === 'API修改(错误码)') {
517    diffOld = startDiffOld + '错误码内容:' + oldErrorCode;
518  }
519  diffNew = startDiffNew + '错误码内容:' + newErrorCode;
520  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
521  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
522}
523
524function collectSyscapDiff(newSyscap, oldSyscap, startDiffNew, startDiffOld, diffApis, subsystemMap, notes,
525  fileNameMap, newApi) {
526  flag = 'SysCap有变化';
527  diffOld = startDiffOld + 'SysCap:' + oldSyscap;
528  diffNew = startDiffNew + 'SysCap:' + newSyscap;
529  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
530  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
531}
532
533function collectSystemApiDiff(newIsSystemApi, oldIsSystemApi, startDiffNew, startDiffOld, diffApis, subsystemMap,
534  notes, fileNameMap, newApi) {
535  flag = '访问级别有变化';
536  diffOld = startDiffOld + '访问级别:' + oldIsSystemApi;
537  diffNew = startDiffNew + '访问级别:' + newIsSystemApi;
538  let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
539  diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
540}
541
542function getMethodFlag(methodTextOld, methodTextNew) {
543  let methodTextOlds = methodTextOld.replace(/\r|\n|\s+|\,|\;/g, '');
544  let methodTextNews = methodTextNew.replace(/\r|\n|\s+|\,|\;/g, '');
545  if (methodTextOlds === methodTextNews) {
546    return '函数格式变化';
547  } else {
548    return '函数有变化';
549  }
550}
551
552function getPermissionFlag(permissionOld, permissionNew) {
553  let permissionOlds = permissionOld.replace(/\r|\n|\s+|\.|\//g, '');
554  let permissionNews = permissionNew.replace(/\r|\n|\s+|\.|\//g, '');
555  if (permissionOlds === permissionNews) {
556    return '格式变化';
557  } else if (permissionOld === 'N/A') {
558    return '新增(权限)';
559  } else if (permissionNew === 'N/A') {
560    return '删除(权限)';
561  } else {
562    return '权限有变化';
563  }
564}
565
566function getDiffApisBaseOld(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap) {
567  const notes = '';
568  oldDiffApis.forEach(oldApi => {
569    let flag = '';
570    let diffOld = '';
571    let diffNew = 'NA';
572    const tmpApis = [];
573    newDiffApis.forEach(newApi => {
574      if (oldApi.dtsPath.replace(oldDir, '') === newApi.dtsPath.replace(newDir, '')) {
575        tmpApis.push(newApi);
576      }
577    });
578    if (tmpApis.length === 0) {
579      flag = deleteFileApi(oldApi, flag, diffOld).flag;
580      diffOld = deleteFileApi(oldApi, flag, diffOld).diffOld;
581    } else {
582      if (oldApi.apiType === 'import') {
583        flag = deleteImportApi(flag, diffOld, tmpApis, oldApi).flag;
584        diffOld = deleteImportApi(flag, diffOld, tmpApis, oldApi).diffOld;
585      } else if (oldApi.apiType === 'export') {
586        flag = deleteExportApi(flag, diffOld, tmpApis, oldApi).flag;
587        diffOld = deleteExportApi(flag, diffOld, tmpApis, oldApi).diffOld;
588      } else {
589        flag = collectDeleteApis(tmpApis, oldApi, flag, diffOld).flag;
590        diffOld = collectDeleteApis(tmpApis, oldApi, flag, diffOld).diffOld;
591      }
592    }
593    if (flag !== '') {
594      let sysCapInfo = getSubsystemBySyscap(oldApi, oldApi.sysCap);
595      diffApis.push(getApiInfoWithFlag(oldApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
596    }
597  });
598}
599
600function collectDeleteApis(tmpApis, oldApi, flag, diffOld) {
601  const newSameClassApis = [];
602  tmpApis.forEach(newApi => {
603    if (oldApi.className === newApi.className) {
604      newSameClassApis.push(newApi);
605    }
606  });
607  if (newSameClassApis.length === 0) {
608    flag = '删除';
609    if (oldApi.methodName === '') {
610      diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className;
611    } else {
612      diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText;
613    }
614  } else {
615    let count = 0;
616    newSameClassApis.forEach(newApi => {
617      if (oldApi.methodName === newApi.methodName && oldApi.apiType.toString() === newApi.apiType.toString()) {
618        count++;
619      }
620    });
621
622    if (count === 0) {
623      flag = '删除';
624      if (oldApi.methodName === '') {
625        diffOld = '模块名:' + oldApi.packageName + '\n类名:' + oldApi.className;
626      } else {
627        diffOld = '模块名:' + oldApi.packageName + '\n类名:' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText;
628      }
629    }
630  }
631  return { flag, diffOld };
632}
633
634function deleteImportApi(flag, diffOld, tmpApis, oldApi) {
635  const tmpApis2 = [];
636  tmpApis.forEach(newApi => {
637    if (newApi.apiType === 'import' && newApi.headimport === oldApi.headimport) {
638      tmpApis2.push(newApi);
639    }
640  });
641
642  if (tmpApis2.length === 0) {
643    flag = '删除';
644    diffOld = '模块名: ' + oldApi.packageName + '\nimport 信息: ' + oldApi.headimport;
645  }
646  return { flag, diffOld };
647}
648
649function deleteExportApi(flag, diffOld, tmpApis, oldApi) {
650  const tmpApis3 = [];
651  tmpApis.forEach(newApi => {
652    if (newApi.apiType === 'export' && newApi.endexport === oldApi.endexport) {
653      tmpApis3.push(newApi);
654    }
655  });
656  if (tmpApis3.length === 0) {
657    flag = '删除';
658    diffOld = '模块名: ' + oldApi.packageName + '\nexport 信息: ' + oldApi.endexport;
659  }
660  return { flag, diffOld };
661}
662
663function deleteFileApi(oldApi, flag, diffOld) {
664  flag = '删除';
665  if (oldApi.apiType === 'import') {
666    diffOld = '模块名: ' + oldApi.packageName + '\nimport 信息: ' + oldApi.headimport;
667  } else if (oldApi.apiType === 'export') {
668    diffOld = '模块名: ' + oldApi.packageName + '\nexport 信息: ' + oldApi.endexport;
669  } else if (oldApi.methodName === '') {
670    diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className;
671  } else {
672    diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText;
673  }
674  return { flag, diffOld };
675}
676
677// 输出新旧版本所有api对比结果
678async function exportDiffApiInfo(exportType, compileApiInfos, exportFileName) {
679  if (exportType === 'excel') {
680    const workbook = new ExcelJS.Workbook();
681    const sheet = workbook.addWorksheet('api差异', { viers: [{ xSplit: 1 }] });
682    sheet.getRow(1).values = ['操作标记*', '差异项-旧版本', '差异项-新版本', 'd.ts文件', '归属子系统'];
683    for (let i = 0; i < compileApiInfos.length; i++) {
684      let apiData = compileApiInfos[i];
685      let fileName = apiData.dtsPath ? path.basename(apiData.dtsPath) : apiData.packageName;
686      const ADD_NUMBER = 2;
687      sheet.getRow(i + ADD_NUMBER).values = [apiData.flag, apiData.diffOld, apiData.diffNew, fileName,
688        apiData.subsystem];
689    }
690    const buffer = await workbook.xlsx.writeBuffer();
691    fs.writeFile(exportFileName, buffer, function (err) {
692      if (err) {
693        return;
694      }
695    });
696  } else if (exportType === 'json') {
697    fs.writeFile(exportFileName, JSON.stringify(compileApiInfos), function (err) {
698      if (err) {
699        console.log('Write failed:' + err);
700        return;
701      }
702      console.log(exportFileName + 'Write completed.');
703    });
704  }
705}
706
707function exportDiffMd(subsystem, diffInfos) {
708  let finalContent = '| 操作 | 旧版本 | 新版本 | d.ts文件 |\n' + '| ---- | ------ | ------ | -------- |\n';
709  for (let i = 0; i < diffInfos.length; i++) {
710    let apiData = diffInfos[i];
711    let fileName = apiData.dtsPath ? path.basename(apiData.dtsPath) : apiData.packageName;
712    const oldData = apiData.diffOld.replace(/\r|\n/g, '<br>').replace(/\|/g, '\\|').replace(/\<(?!br>)/g, '\\<');
713    const newData = apiData.diffNew.replace(/\r|\n/g, '<br>').replace(/\|/g, '\\|').replace(/\<(?!br>)/g, '\\<');
714    finalContent += `|${apiData.flag}|${oldData}|${newData}|${fileName}|\n`;
715  }
716  const mdFilesDir = `${__dirname.replace('src', '')}diff合集`;
717  if (!fs.existsSync(mdFilesDir)) {
718    fs.mkdirSync('../diff合集');
719  }
720
721  fs.writeFile(`../diff合集/js-apidiff-${subsystem}.md`, finalContent, function (err) {
722    if (err) {
723      console.log('WRITE FAILED:::', err);
724      return;
725    }
726    console.log('WRITE SUCCESSED');
727  });
728
729}
730
731function diffBySbusystem(compileApiInfos) {
732  let filePath = __dirname.replace('\\src', '') + '\\subsystem.json';
733  let subsystemArr = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
734  let flagArr = ['新增', '删除', 'model有变化', '访问级别有变化', '废弃版本有变化', '起始版本有变化', '权限有变化',
735    '删除(权限)', '新增(错误码)', '新增(权限)', '错误码有变化', 'SysCap有变化', '函数有变化'];
736  subsystemArr.forEach(subsystem => {
737    let diffInfos = [];
738    compileApiInfos.forEach(api => {
739      if (subsystem.subsystem === api.subsystem) {
740        diffInfos.push(api);
741      }
742    });
743    if (diffInfos.length !== 0) {
744      const sortDiffInfos = [];
745      flagArr.forEach(flag => {
746        diffInfos.forEach(diffInfo => {
747          if (diffInfo.flag === flag) {
748            sortDiffInfos.push(diffInfo);
749          }
750        });
751      });
752      exportDiffMd(subsystem.fileName, sortDiffInfos);
753    }
754
755  });
756}
757// 读取路径下所有的zip文件路径
758function readZipFile(dir, zipFiles) {
759  try {
760    const files = fs.readdirSync(dir);
761    files.forEach(element => {
762      const filePath = path.join(dir, element);
763      const status = fs.statSync(filePath);
764      if (status.isDirectory()) {
765        readZipFile(filePath, zipFiles);
766      } else {
767        if (filePath.endsWith('.zip')) {
768          zipFiles.push(filePath);
769        }
770      }
771    });
772  } catch (error) {
773    console.error('ETS ERROR:' + error);
774  }
775}
776
777function unCompressAllZipFilesAndCompile(newDir, oldDir) {
778  const zipFiles = [];
779  readZipFile(newDir, zipFiles);
780  readZipFile(oldDir, zipFiles);
781  let count = 0;
782  let countfile = 0;
783  zipFiles.forEach(async element => {
784    let filePath = element.replace(path.basename(element), '');
785    compressing.zip.uncompress(element, filePath).then((data) => {
786      console.log('uncompress success:', data, '--' + element);
787      count++;
788      if ((count + countfile) === zipFiles.length) {
789        compileAndExportToFile();
790      }
791    }).catch(error => {
792      console.log(('uncompress error:', error));
793    });
794  });
795}
796
797function compileAndExportToFile() {
798  const newFiles = [];
799  const oldFiles = [];
800  readFile(oldDir, oldFiles);
801  readFile(newDir, newFiles);
802  let diffApis = getDIffApisWithCompile(newFiles, oldFiles);
803  let noRepeatDiffApi = [];
804  let diffApisSet = new Set();
805  diffApis.map(api => diffApisSet.add(JSON.stringify(api)));
806  diffApisSet.forEach(item => {
807    noRepeatDiffApi.push(JSON.parse(item));
808  });
809  for (let i = 0; i < allMergeData.length; i++) {
810    for (let j = 0; j < noRepeatDiffApi.length; j++) {
811      if (allMergeData[i].packageName === noRepeatDiffApi[j].packageName && noRepeatDiffApi[j].flag === '删除' &&
812        allMergeData[i].diffOld === noRepeatDiffApi[j].methodText) {
813        noRepeatDiffApi.splice(j, 1);
814        j--;
815      } else if (allMergeData[i].packageName === noRepeatDiffApi[j].packageName &&
816        noRepeatDiffApi[j].flag === '新增' && allMergeData[i].diffNew === noRepeatDiffApi[j].methodText) {
817        noRepeatDiffApi.splice(j, 1);
818        j--;
819      }
820
821    }
822
823  }
824  let afterMergeData = noRepeatDiffApi.concat(allMergeData);
825  exportDiffApiInfo('excel', afterMergeData, 'Js_Api_Diff.xlsx');
826  diffBySbusystem(afterMergeData);
827}
828
829const subsystemDir = __dirname.replace('\\src', '') + '\\subsystem.json';
830const urlObject = fs.readFileSync(__dirname.replace('\\src', '') + '\\url.json', 'utf-8');
831const oldDir = JSON.parse(urlObject).oldDir;
832const newDir = JSON.parse(urlObject).newDir;
833unCompressAllZipFilesAndCompile(newDir, oldDir);
834