/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const path = require('path'); const fs = require('fs'); const ts = require('typescript'); const ExcelJS = require('exceljs'); const compressing = require('compressing'); const { readFile, getSubsystemBySyscap, getApiInfoWithFlag, getApiInfoDeleteDtsPath } = require('./util'); const { parse } = require('./collect_base_api'); const { allMergeData } = require('./format_data'); let methodType = ''; function getSubsystemJson(jsonDir) { let fileContent = fs.readFileSync(jsonDir, 'utf-8'); let subsystems = JSON.parse(fileContent); const subsystemMap = new Map(); const fileNameMap = new Map(); subsystems.forEach(element => { subsystemMap.set(element.syscap, element.subsystem); fileNameMap.set(element.syscap, element.fileName); }); return { subsystemMap, fileNameMap }; } // 对比新旧版本文件列表 function compileFiles(newFiles, oldFiles) { const newFileNames = []; const oldFileNames = []; newFiles.forEach(file => { const fileName = path.basename(file).replace(/.d.ts$/g, '.ts'); newFileNames.push(fileName); }); oldFiles.forEach(file => { const fileName = path.basename(file).replace(/.d.ts$/g, '.ts'); oldFileNames.push(fileName); }); //保存有差异的信息 const compileApiInfos = []; // 旧版本不存在新版本中的文件,表示新增 newFileNames.forEach(fileName => { let index = oldFileNames.indexOf(fileName); if (index < 0) { compileApiInfos.push({ flag: '新版本新增', fileName: fileName, filePath: newFiles[newFileNames.indexOf(fileName)], }); } }); // 新版本不在在旧版本中的文件,表示删除 oldFileNames.forEach(fileName => { let index = newFileNames.indexOf(fileName); if (index < 0) { compileApiInfos.push({ flag: '新版本删除', fileName: fileName, filePath: oldFiles[oldFileNames.indexOf(fileName)], }); } }); return compileApiInfos; } // 根据文件列表获取api信息数组 function getFilesApi(files) { const fileContentList = []; files.forEach(file => { let fileContent = fs.readFileSync(file, 'utf-8'); fileContentList.push({ fileName: path.basename(file).replace(/.d.ts$/g, '.ts'), fileContent: fileContent, fileRoot: file, }); }); const api = parse(fileContentList); return api; } function getDIffApisWithCompile(newFiles, oldFiles) { const newFilesApi = getFilesApi(newFiles); const oldFilesApi = getFilesApi(oldFiles); // 去掉dtspath后的 const tmpNewApis = []; newFilesApi.forEach(newApi => { tmpNewApis.push(JSON.stringify(getApiInfoDeleteDtsPath(newApi))); }); const tmpOldApis = []; oldFilesApi.forEach(oldApi => { tmpOldApis.push(JSON.stringify(getApiInfoDeleteDtsPath(oldApi))); }); let hasFunTypeNewApis = []; let hasFunTypeOldApis = []; hasFunTypeNewApis = deleteRepeatApi(tmpOldApis, tmpNewApis, newFilesApi, oldFilesApi).newDiffApiArr; hasFunTypeOldApis = deleteRepeatApi(tmpOldApis, tmpNewApis, newFilesApi, oldFilesApi).oldDiffApiArr; let newDiffApis = []; let oldDiffApis = []; newDiffApis = collectSameTypeFun(hasFunTypeNewApis); oldDiffApis = collectSameTypeFun(hasFunTypeOldApis); const subsystemMap = getSubsystemJson(subsystemDir).subsystemMap; const fileNameMap = getSubsystemJson(subsystemDir).fileNameMap; const diffApis = []; getDiffApisBaseNew(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap); getDiffApisBaseOld(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap); return diffApis; } function deleteRepeatApi(oldApis, newApis, newFilesApi, oldFilesApi) { let newDiffApiArr = []; let oldDiffApiArr = []; for (let i = 0; i < newApis.length; i++) { const newApi = newApis[i]; let index = oldApis.indexOf(newApi); if (index < 0) { let includeTypeApi = addMethodType(newFilesApi[i]); newDiffApiArr.push(includeTypeApi); } } for (let i = 0; i < oldApis.length; i++) { const oldApi = oldApis[i]; let index = newApis.indexOf(oldApi); if (index < 0) { let includeTypeApi = addMethodType(oldFilesApi[i]); oldDiffApiArr.push(includeTypeApi); } } return { newDiffApiArr, oldDiffApiArr }; } function collectSameTypeFun(apiArr) { apiArr.forEach(api => { let sameNameFun = ''; // 标记既不是Promise也不是callback的同名函数 let number = 0; let sameNamePromiseText = ''; apiArr.forEach(newApi => { if (api.dtsPath.replace(newDir, '') === newApi.dtsPath.replace(newDir, '') && api.className === newApi.className && api.methodName === newApi.methodName && api.apiType === 'Method' && api.funType === newApi.funType) { if (sameNameFun.indexOf(newApi.methodText) < 0 && api.funType === 'callback') { sameNameFun += `\n${newApi.methodText}`; api.callbackMethodText = sameNameFun; } else if (sameNamePromiseText.indexOf(newApi.methodText) < 0 && api.funType === 'Promise') { sameNamePromiseText += `\n${newApi.methodText}`; api.promiseMethodText = sameNamePromiseText; } else if (!api.funType) { number++; api.note = number; } } }); }); return apiArr; } function addMethodType(baseApi) { let methodContent = `interface test{ ${baseApi.methodText} }`; getMethodType(methodContent, filterType); if (methodType === 'callback' || methodType === 'Promise') { baseApi.funType = methodType; } return baseApi; } function getMethodType(content, callback) { ts.transpileModule(content, { compilerOptions: { 'target': ts.ScriptTarget.ES2017, }, fileName: 'index.ets', transformers: { before: [callback()] }, }); } function filterType() { return (context) => { methodType = ''; return (node) => { getType(node); return node; }; function getType(node) { // add function type(callback or Promise) if (ts.isFunctionDeclaration(node) || ts.isMethodSignature(node)) { getFunType(node); } return ts.visitEachChild(node, getType, context); } }; } function getFunType(node) { if (node.type && ts.isTypeReferenceNode(node.type)) { methodType = node.type.typeName.escapedText; } else if (node.parameters.length > 0) { const parameter = node.parameters[node.parameters.length - 1]; if (parameter.name.escapedText === 'callback') { methodType = parameter.name.escapedText; } } else { methodType = ''; } } function collectDeprecatedDiff(newDeprecated, oldDeprecated, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { flag = '废弃版本有变化'; diffOld = startDiffOld + '废弃版本:' + oldDeprecated; const useinsteadInfo = newApi.useinsteadInfo instanceof Object ? newApi.useinsteadInfo.new : newApi.useinsteadInfo; if (newApi.useinsteadInfo) { diffNew = `${startDiffNew}废弃版本:${newDeprecated}\n代替接口:${useinsteadInfo}`; } else { diffNew = startDiffNew + '废弃版本:' + newDeprecated; } let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function getDiffApisBaseNew(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap) { const notes = ''; const diffMethodTextSet = new Set(); newDiffApis.forEach(newApi => { let diffOld = 'NA'; let diffNew = 'NA'; const tmpApis = []; oldDiffApis.forEach(oldApi => { if (newApi.dtsPath.replace(newDir, '') === oldApi.dtsPath.replace(oldDir, '')) { tmpApis.push(oldApi); } }); if (tmpApis.length === 0) { collectNewFileApi(newApi, subsystemMap, notes, fileNameMap, diffApis, diffOld); } else { if (newApi.apiType === 'import') { collectImportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap); } else if (newApi.apiType === 'export') { collectExportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap); } else { let oldSameClassApis = handleApiByClassName(tmpApis, newApi, newDiffApis).oldSameClassApi; let oldMethodTexts = handleApiByClassName(tmpApis, newApi, newDiffApis).oldMethodTexts; collectSameClassDiff(oldSameClassApis, newApi, diffNew, diffOld, diffApis, subsystemMap, fileNameMap, diffMethodTextSet); getNewAddApi(oldMethodTexts, diffApis, subsystemMap, fileNameMap, diffMethodTextSet, newApi); } } }); } function collectSameClassDiff(oldSameClassApis, newApi, diffNew, diffOld, diffApis, subsystemMap, fileNameMap, diffMethodTextSet) { const notes = ''; if (oldSameClassApis.length === 0) { flag = '新增'; if (newApi.methodName === '') { diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className; } else { diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className + '\n方法 or 属性:' + newApi.methodText; } let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } else { oldSameClassApis.forEach(oldApi => { if (newApi.methodName === oldApi.methodName && newApi.apiType.toString() === oldApi.apiType.toString()) { collectChangePart(newApi, oldApi, diffApis, subsystemMap, fileNameMap, diffMethodTextSet); } }); } } function getNewAddApi(oldMethodTexts, diffApis, subsystemMap, fileNameMap, diffMethodTextSet, newApi) { if (!oldMethodTexts.has(newApi.methodText.replace(/\r|\n|\s+|\,|\;/g, '')) && !diffMethodTextSet.has(newApi.methodText)) { const notes = ''; const flag = '新增'; const diffNew = '类名:' + newApi.className + '\n方法or属性:' + newApi.methodText; const diffOld = 'NA'; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } } function collectChangePart(newApi, oldApi, diffApis, subsystemMap, fileNameMap, diffMethodTextSet) { let startDiffOld = ''; let startDiffNew = ''; const NOTE_NUMBER = 2; if (newApi.methodName === '') { startDiffOld = '类名:' + oldApi.className + '\n'; startDiffNew = '类名:' + newApi.className + '\n'; } else { startDiffOld = '类名:' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText + '\n'; startDiffNew = '类名:' + newApi.className + '\n方法 or 属性:' + newApi.methodText + '\n'; } if (isCallbackTypeFun(newApi, oldApi, 'callback')) { diffMethodTextSet.add(newApi.methodText); collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.callbackMethodText, oldApi.callbackMethodText, subsystemMap, fileNameMap); } if (isPromiseTypeFun(newApi, oldApi, 'Promise')) { diffMethodTextSet.add(newApi.methodText); collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.promiseMethodText, oldApi.promiseMethodText, subsystemMap, fileNameMap); } if (!newApi.funType && !oldApi.funType && newApi.methodText !== oldApi.methodText && newApi.note < NOTE_NUMBER) { diffMethodTextSet.add(newApi.methodText); collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.methodText, oldApi.methodText, subsystemMap, fileNameMap); } if (newApi.methodText === oldApi.methodText) { collectNoteDiff(newApi.version, oldApi.version, newApi.deprecated, oldApi.deprecated, newApi.errorCode, oldApi.errorCode, newApi.sysCap, oldApi.sysCap, newApi.isSystemApi, oldApi.isSystemApi, newApi.permission, oldApi.permission, newApi.model, oldApi.model, newApi.typeInfo, oldApi.typeInfo, startDiffNew, startDiffOld, diffApis, subsystemMap, fileNameMap, newApi); } } function isCallbackTypeFun(newApi, oldApi, funType) { if (newApi.funType === funType && oldApi.funType === funType && newApi.callbackMethodText !== oldApi.callbackMethodText) { return true; } else { return false; } } function isPromiseTypeFun(newApi, oldApi, funType) { if (newApi.funType === funType && oldApi.funType === funType && newApi.promiseMethodText !== oldApi.promiseMethodText) { return true; } else { return false; } } function collectNoteDiff(newVersion, oldVersion, newDeprecated, oldDeprecated, newErrorCode, oldErrorCode, newSyscap, oldSyscap, newIsSystemApi, oldIsSystemApi, newPermission, oldPermission, newModel, oldModel, newTypeInfo, oldTypeInfo, startDiffNew, startDiffOld, diffApis, subsystemMap, fileNameMap, newApi) { const notes = ''; if (newVersion !== oldVersion) { collectVersionDiff(newVersion, oldVersion, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } if (newDeprecated !== oldDeprecated) { collectDeprecatedDiff(newDeprecated, oldDeprecated, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } if (newErrorCode !== oldErrorCode) { collectErrorCodeDiff(newErrorCode, oldErrorCode, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } if (newSyscap !== oldSyscap) { collectSyscapDiff(newSyscap, oldSyscap, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } if (newIsSystemApi !== oldIsSystemApi) { collectSystemApiDiff(newIsSystemApi, oldIsSystemApi, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } if (newPermission !== oldPermission) { collectPermissionDiff(newPermission, oldPermission, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } if (newModel !== oldModel) { collectModelDiff(newModel, oldModel, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } if (newTypeInfo !== oldTypeInfo) { collectTypeDiff(newTypeInfo, oldTypeInfo, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi); } } function collectTypeDiff(newType, oldType, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { let flag = ''; if (oldType !== newType) { flag = 'type有变化'; } if (flag) { diffOld = startDiffOld + 'type:' + oldType; diffNew = startDiffNew + 'type:' + newType; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } } function collectNewFileApi(newApi, subsystemMap, notes, fileNameMap, diffApis, diffOld) { const flag = '新增'; let diffNew = ''; if (newApi.apiType === 'import') { diffNew = '模块名: ' + newApi.packageName + '\nimport 信息: ' + newApi.headimport; } else if (newApi.apiType === 'export') { diffNew = '模块名: ' + newApi.packageName + '\nexport 信息: ' + newApi.endexport; } else if (newApi.methodName === '') { diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className; } else { diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className + '\n方法 or 属性: ' + newApi.methodText; } let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function collectImportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap) { const tmpApis2 = []; tmpApis.forEach(oldApi => { if (oldApi.apiType === 'import' && newApi.headimport === oldApi.headimport) { tmpApis2.push(oldApi); } }); if (tmpApis2.length === 0) { flag = '新增'; diffNew = '模块名: ' + newApi.packageName + '\nimport 信息: ' + newApi.headimport; } let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function collectExportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap) { const tmpApis3 = []; tmpApis.forEach(oldApi => { if (oldApi.apiType === 'export' && newApi.endexport === oldApi.endexport) { tmpApis3.push(oldApi); } }); if (tmpApis3.length === 0) { flag = '新增'; diffNew = '模块名: ' + newApi.packageName + '\nexport 信息: ' + newApi.endexport; } let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function handleApiByClassName(tmpApis, newApi, newDiffApis) { const oldSameClassApi = []; const newSameClassApi = []; const oldMethodTexts = new Set([]); const newMethodTexts = new Set([]); let equalClassName = 'N/A'; tmpApis.forEach(oldApi => { if (newApi.className === oldApi.className) { oldSameClassApi.push(oldApi); equalClassName = oldApi.className; oldMethodTexts.add(oldApi.methodText.replace(/\r|\n|\s+|\,|\;/g, '')); } }); newDiffApis.forEach(apiText => { if (apiText.className === equalClassName) { newMethodTexts.add(apiText.methodText.replace(/\r|\n|\s+|\,|\;/g, '')); newSameClassApi.push(apiText); } }); return { oldSameClassApi, oldMethodTexts, newMethodTexts }; } function collectVersionDiff(newVersion, oldVersion, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { flag = '起始版本有变化'; diffOld = startDiffOld + '起始版本:' + oldVersion; diffNew = startDiffNew + '起始版本:' + newVersion; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function collectModelDiff(newModel, oldModel, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { flag = 'model有变化'; diffOld = startDiffOld + 'model:' + oldModel; diffNew = startDiffNew + 'model:' + newModel; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function collectPermissionDiff(newPermission, oldPermission, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { flag = getPermissionFlag(oldPermission, newPermission); if (flag !== '格式变化') { diffOld = startDiffOld + '权限:' + oldPermission; diffNew = startDiffNew + '权限:' + newPermission; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } } function collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newMethodText, oldMethodText, subsystemMap, fileNameMap) { flag = getMethodFlag(oldMethodText, newMethodText); const note = '去重'; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); if (flag === '函数有变化') { diffOld = startDiffOld; diffNew = startDiffNew; diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, note, fileNameMap)); } } function collectErrorCodeDiff(newErrorCode, oldErrorCode, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { flag = oldErrorCode === 'N/A' ? '新增(错误码)' : 'API修改(错误码)'; if (flag === '新增(错误码)') { diffOld = 'NA'; } else if (flag === 'API修改(错误码)') { diffOld = startDiffOld + '错误码内容:' + oldErrorCode; } diffNew = startDiffNew + '错误码内容:' + newErrorCode; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function collectSyscapDiff(newSyscap, oldSyscap, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { flag = 'SysCap有变化'; diffOld = startDiffOld + 'SysCap:' + oldSyscap; diffNew = startDiffNew + 'SysCap:' + newSyscap; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function collectSystemApiDiff(newIsSystemApi, oldIsSystemApi, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) { flag = '访问级别有变化'; diffOld = startDiffOld + '访问级别:' + oldIsSystemApi; diffNew = startDiffNew + '访问级别:' + newIsSystemApi; let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap); diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } function getMethodFlag(methodTextOld, methodTextNew) { let methodTextOlds = methodTextOld.replace(/\r|\n|\s+|\,|\;/g, ''); let methodTextNews = methodTextNew.replace(/\r|\n|\s+|\,|\;/g, ''); if (methodTextOlds === methodTextNews) { return '函数格式变化'; } else { return '函数有变化'; } } function getPermissionFlag(permissionOld, permissionNew) { let permissionOlds = permissionOld.replace(/\r|\n|\s+|\.|\//g, ''); let permissionNews = permissionNew.replace(/\r|\n|\s+|\.|\//g, ''); if (permissionOlds === permissionNews) { return '格式变化'; } else if (permissionOld === 'N/A') { return '新增(权限)'; } else if (permissionNew === 'N/A') { return '删除(权限)'; } else { return '权限有变化'; } } function getDiffApisBaseOld(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap) { const notes = ''; oldDiffApis.forEach(oldApi => { let flag = ''; let diffOld = ''; let diffNew = 'NA'; const tmpApis = []; newDiffApis.forEach(newApi => { if (oldApi.dtsPath.replace(oldDir, '') === newApi.dtsPath.replace(newDir, '')) { tmpApis.push(newApi); } }); if (tmpApis.length === 0) { flag = deleteFileApi(oldApi, flag, diffOld).flag; diffOld = deleteFileApi(oldApi, flag, diffOld).diffOld; } else { if (oldApi.apiType === 'import') { flag = deleteImportApi(flag, diffOld, tmpApis, oldApi).flag; diffOld = deleteImportApi(flag, diffOld, tmpApis, oldApi).diffOld; } else if (oldApi.apiType === 'export') { flag = deleteExportApi(flag, diffOld, tmpApis, oldApi).flag; diffOld = deleteExportApi(flag, diffOld, tmpApis, oldApi).diffOld; } else { flag = collectDeleteApis(tmpApis, oldApi, flag, diffOld).flag; diffOld = collectDeleteApis(tmpApis, oldApi, flag, diffOld).diffOld; } } if (flag !== '') { let sysCapInfo = getSubsystemBySyscap(oldApi, oldApi.sysCap); diffApis.push(getApiInfoWithFlag(oldApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap)); } }); } function collectDeleteApis(tmpApis, oldApi, flag, diffOld) { const newSameClassApis = []; tmpApis.forEach(newApi => { if (oldApi.className === newApi.className) { newSameClassApis.push(newApi); } }); if (newSameClassApis.length === 0) { flag = '删除'; if (oldApi.methodName === '') { diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className; } else { diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText; } } else { let count = 0; newSameClassApis.forEach(newApi => { if (oldApi.methodName === newApi.methodName && oldApi.apiType.toString() === newApi.apiType.toString()) { count++; } }); if (count === 0) { flag = '删除'; if (oldApi.methodName === '') { diffOld = '模块名:' + oldApi.packageName + '\n类名:' + oldApi.className; } else { diffOld = '模块名:' + oldApi.packageName + '\n类名:' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText; } } } return { flag, diffOld }; } function deleteImportApi(flag, diffOld, tmpApis, oldApi) { const tmpApis2 = []; tmpApis.forEach(newApi => { if (newApi.apiType === 'import' && newApi.headimport === oldApi.headimport) { tmpApis2.push(newApi); } }); if (tmpApis2.length === 0) { flag = '删除'; diffOld = '模块名: ' + oldApi.packageName + '\nimport 信息: ' + oldApi.headimport; } return { flag, diffOld }; } function deleteExportApi(flag, diffOld, tmpApis, oldApi) { const tmpApis3 = []; tmpApis.forEach(newApi => { if (newApi.apiType === 'export' && newApi.endexport === oldApi.endexport) { tmpApis3.push(newApi); } }); if (tmpApis3.length === 0) { flag = '删除'; diffOld = '模块名: ' + oldApi.packageName + '\nexport 信息: ' + oldApi.endexport; } return { flag, diffOld }; } function deleteFileApi(oldApi, flag, diffOld) { flag = '删除'; if (oldApi.apiType === 'import') { diffOld = '模块名: ' + oldApi.packageName + '\nimport 信息: ' + oldApi.headimport; } else if (oldApi.apiType === 'export') { diffOld = '模块名: ' + oldApi.packageName + '\nexport 信息: ' + oldApi.endexport; } else if (oldApi.methodName === '') { diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className; } else { diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText; } return { flag, diffOld }; } // 输出新旧版本所有api对比结果 async function exportDiffApiInfo(exportType, compileApiInfos, exportFileName) { if (exportType === 'excel') { const workbook = new ExcelJS.Workbook(); const sheet = workbook.addWorksheet('api差异', { viers: [{ xSplit: 1 }] }); sheet.getRow(1).values = ['操作标记*', '差异项-旧版本', '差异项-新版本', 'd.ts文件', '归属子系统']; for (let i = 0; i < compileApiInfos.length; i++) { let apiData = compileApiInfos[i]; let fileName = apiData.dtsPath ? path.basename(apiData.dtsPath) : apiData.packageName; const ADD_NUMBER = 2; sheet.getRow(i + ADD_NUMBER).values = [apiData.flag, apiData.diffOld, apiData.diffNew, fileName, apiData.subsystem]; } const buffer = await workbook.xlsx.writeBuffer(); fs.writeFile(exportFileName, buffer, function (err) { if (err) { return; } }); } else if (exportType === 'json') { fs.writeFile(exportFileName, JSON.stringify(compileApiInfos), function (err) { if (err) { console.log('Write failed:' + err); return; } console.log(exportFileName + 'Write completed.'); }); } } function exportDiffMd(subsystem, diffInfos) { let finalContent = '| 操作 | 旧版本 | 新版本 | d.ts文件 |\n' + '| ---- | ------ | ------ | -------- |\n'; for (let i = 0; i < diffInfos.length; i++) { let apiData = diffInfos[i]; let fileName = apiData.dtsPath ? path.basename(apiData.dtsPath) : apiData.packageName; const oldData = apiData.diffOld.replace(/\r|\n/g, '
').replace(/\|/g, '\\|').replace(/\<(?!br>)/g, '\\<'); const newData = apiData.diffNew.replace(/\r|\n/g, '
').replace(/\|/g, '\\|').replace(/\<(?!br>)/g, '\\<'); finalContent += `|${apiData.flag}|${oldData}|${newData}|${fileName}|\n`; } const mdFilesDir = `${__dirname.replace('src', '')}diff合集`; if (!fs.existsSync(mdFilesDir)) { fs.mkdirSync('../diff合集'); } fs.writeFile(`../diff合集/js-apidiff-${subsystem}.md`, finalContent, function (err) { if (err) { console.log('WRITE FAILED:::', err); return; } console.log('WRITE SUCCESSED'); }); } function diffBySbusystem(compileApiInfos) { let filePath = __dirname.replace('\\src', '') + '\\subsystem.json'; let subsystemArr = JSON.parse(fs.readFileSync(filePath, 'utf-8')); let flagArr = ['新增', '删除', 'model有变化', '访问级别有变化', '废弃版本有变化', '起始版本有变化', '权限有变化', '删除(权限)', '新增(错误码)', '新增(权限)', '错误码有变化', 'SysCap有变化', '函数有变化']; subsystemArr.forEach(subsystem => { let diffInfos = []; compileApiInfos.forEach(api => { if (subsystem.subsystem === api.subsystem) { diffInfos.push(api); } }); if (diffInfos.length !== 0) { const sortDiffInfos = []; flagArr.forEach(flag => { diffInfos.forEach(diffInfo => { if (diffInfo.flag === flag) { sortDiffInfos.push(diffInfo); } }); }); exportDiffMd(subsystem.fileName, sortDiffInfos); } }); } // 读取路径下所有的zip文件路径 function readZipFile(dir, zipFiles) { try { const files = fs.readdirSync(dir); files.forEach(element => { const filePath = path.join(dir, element); const status = fs.statSync(filePath); if (status.isDirectory()) { readZipFile(filePath, zipFiles); } else { if (filePath.endsWith('.zip')) { zipFiles.push(filePath); } } }); } catch (error) { console.error('ETS ERROR:' + error); } } function unCompressAllZipFilesAndCompile(newDir, oldDir) { const zipFiles = []; readZipFile(newDir, zipFiles); readZipFile(oldDir, zipFiles); let count = 0; let countfile = 0; zipFiles.forEach(async element => { let filePath = element.replace(path.basename(element), ''); compressing.zip.uncompress(element, filePath).then((data) => { console.log('uncompress success:', data, '--' + element); count++; if ((count + countfile) === zipFiles.length) { compileAndExportToFile(); } }).catch(error => { console.log(('uncompress error:', error)); }); }); } function compileAndExportToFile() { const newFiles = []; const oldFiles = []; readFile(oldDir, oldFiles); readFile(newDir, newFiles); let diffApis = getDIffApisWithCompile(newFiles, oldFiles); let noRepeatDiffApi = []; let diffApisSet = new Set(); diffApis.map(api => diffApisSet.add(JSON.stringify(api))); diffApisSet.forEach(item => { noRepeatDiffApi.push(JSON.parse(item)); }); for (let i = 0; i < allMergeData.length; i++) { for (let j = 0; j < noRepeatDiffApi.length; j++) { if (allMergeData[i].packageName === noRepeatDiffApi[j].packageName && noRepeatDiffApi[j].flag === '删除' && allMergeData[i].diffOld === noRepeatDiffApi[j].methodText) { noRepeatDiffApi.splice(j, 1); j--; } else if (allMergeData[i].packageName === noRepeatDiffApi[j].packageName && noRepeatDiffApi[j].flag === '新增' && allMergeData[i].diffNew === noRepeatDiffApi[j].methodText) { noRepeatDiffApi.splice(j, 1); j--; } } } let afterMergeData = noRepeatDiffApi.concat(allMergeData); exportDiffApiInfo('excel', afterMergeData, 'Js_Api_Diff.xlsx'); diffBySbusystem(afterMergeData); } const subsystemDir = __dirname.replace('\\src', '') + '\\subsystem.json'; const urlObject = fs.readFileSync(__dirname.replace('\\src', '') + '\\url.json', 'utf-8'); const oldDir = JSON.parse(urlObject).oldDir; const newDir = JSON.parse(urlObject).newDir; unCompressAllZipFilesAndCompile(newDir, oldDir);