161847f8eSopenharmony_ci/* 261847f8eSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 361847f8eSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 461847f8eSopenharmony_ci * you may not use this file except in compliance with the License. 561847f8eSopenharmony_ci * You may obtain a copy of the License at 661847f8eSopenharmony_ci * 761847f8eSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 861847f8eSopenharmony_ci * 961847f8eSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1061847f8eSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1161847f8eSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1261847f8eSopenharmony_ci * See the License for the specific language governing permissions and 1361847f8eSopenharmony_ci * limitations under the License. 1461847f8eSopenharmony_ci */ 1561847f8eSopenharmony_ci 1661847f8eSopenharmony_ciconst fs = require('fs'); 1761847f8eSopenharmony_ciconst path = require('path'); 1861847f8eSopenharmony_ciconst { exportDiffInfo } = require('../../api_diff/src/api_diff'); 1961847f8eSopenharmony_ciconst { StatusCode } = require('../../api_diff/src/reporter'); 2061847f8eSopenharmony_ciconst { 2161847f8eSopenharmony_ci parseJsDoc, 2261847f8eSopenharmony_ci requireTypescriptModule, 2361847f8eSopenharmony_ci ErrorType, 2461847f8eSopenharmony_ci LogType, 2561847f8eSopenharmony_ci ErrorLevel, 2661847f8eSopenharmony_ci ErrorValueInfo, 2761847f8eSopenharmony_ci getCheckApiVersion, 2861847f8eSopenharmony_ci FUNCTION_TYPES, 2961847f8eSopenharmony_ci DIFF_INFO, 3061847f8eSopenharmony_ci createErrorInfo 3161847f8eSopenharmony_ci} = require('./utils'); 3261847f8eSopenharmony_ciconst ts = requireTypescriptModule(); 3361847f8eSopenharmony_ciconst { addAPICheckErrorLogs } = require('./compile_info'); 3461847f8eSopenharmony_ci 3561847f8eSopenharmony_ciconst changeErrors = []; 3661847f8eSopenharmony_ci 3761847f8eSopenharmony_ci/** 3861847f8eSopenharmony_ci * 检查历史JSDoc是否一致 3961847f8eSopenharmony_ci * @param {array} newNodeJSDocs 修改后API节点JSDoc数组 4061847f8eSopenharmony_ci * @param {array} oldNodeJSDocs 修改前API节点JSDoc数组 4161847f8eSopenharmony_ci * @returns {boolean} 4261847f8eSopenharmony_ci */ 4361847f8eSopenharmony_cifunction checkHistoryJSDoc(newNodeJSDocs, oldNodeJSDocs) { 4461847f8eSopenharmony_ci let checkEndJSDocIndex = isNewApi(oldNodeJSDocs) ? 1 : 0; 4561847f8eSopenharmony_ci for (let i = 0; i < oldNodeJSDocs.length - checkEndJSDocIndex; i++) { 4661847f8eSopenharmony_ci const oldDescription = oldNodeJSDocs[i].description; 4761847f8eSopenharmony_ci const oldTags = oldNodeJSDocs[i].tags; 4861847f8eSopenharmony_ci const newDescription = newNodeJSDocs[i].description; 4961847f8eSopenharmony_ci const newTags = newNodeJSDocs[i].tags; 5061847f8eSopenharmony_ci if (oldDescription !== newDescription || oldTags.length !== newTags.length) { 5161847f8eSopenharmony_ci return false; 5261847f8eSopenharmony_ci } 5361847f8eSopenharmony_ci for (let j = 0; j < oldTags.length; j++) { 5461847f8eSopenharmony_ci const oldTag = oldTags[j]; 5561847f8eSopenharmony_ci const newTag = newTags[j]; 5661847f8eSopenharmony_ci if ( 5761847f8eSopenharmony_ci oldTag.tag !== newTag.tag || 5861847f8eSopenharmony_ci oldTag.name !== newTag.name || 5961847f8eSopenharmony_ci oldTag.type !== newTag.type || 6061847f8eSopenharmony_ci oldTag.optional !== newTag.optional || 6161847f8eSopenharmony_ci oldTag.description !== newTag.description 6261847f8eSopenharmony_ci ) { 6361847f8eSopenharmony_ci return false; 6461847f8eSopenharmony_ci } 6561847f8eSopenharmony_ci } 6661847f8eSopenharmony_ci } 6761847f8eSopenharmony_ci return true; 6861847f8eSopenharmony_ci} 6961847f8eSopenharmony_ci 7061847f8eSopenharmony_ci/** 7161847f8eSopenharmony_ci * 根据JSDoc获取版本号 7261847f8eSopenharmony_ci * @param {JSDoc} JSDoc 7361847f8eSopenharmony_ci * @returns {number} 7461847f8eSopenharmony_ci */ 7561847f8eSopenharmony_cifunction getJSDocVersion(JSDoc) { 7661847f8eSopenharmony_ci if (JSDoc) { 7761847f8eSopenharmony_ci for (let i = 0; i < JSDoc.tags.length; i++) { 7861847f8eSopenharmony_ci if (JSDoc.tags[i].tag === 'since') { 7961847f8eSopenharmony_ci return JSDoc.tags[i].name; 8061847f8eSopenharmony_ci } 8161847f8eSopenharmony_ci } 8261847f8eSopenharmony_ci } 8361847f8eSopenharmony_ci return NaN; 8461847f8eSopenharmony_ci} 8561847f8eSopenharmony_ci 8661847f8eSopenharmony_ci/** 8761847f8eSopenharmony_ci * 检查API变更版本是否正确 8861847f8eSopenharmony_ci * @param {JSDoc} currentJSDoc 修改后API节点JSDoc 8961847f8eSopenharmony_ci * @param {JSDoc} lastJSDoc 修改前API节点JSDoc 9061847f8eSopenharmony_ci * @param {ts.Node} node 修改后API节点 9161847f8eSopenharmony_ci */ 9261847f8eSopenharmony_cifunction checkApiChangeVersion(currentJSDoc, lastJSDoc, node) { 9361847f8eSopenharmony_ci const currentVersion = getJSDocVersion(currentJSDoc); 9461847f8eSopenharmony_ci const lastVersion = getJSDocVersion(lastJSDoc); 9561847f8eSopenharmony_ci const checkApiVersion = getCheckApiVersion(); 9661847f8eSopenharmony_ci if (lastVersion === 0 || currentVersion !== checkApiVersion) { 9761847f8eSopenharmony_ci changeErrors.push({ 9861847f8eSopenharmony_ci node: node, 9961847f8eSopenharmony_ci errorInfo: createErrorInfo(ErrorValueInfo.ERROR_CHANGES_VERSION, [checkApiVersion]), 10061847f8eSopenharmony_ci LogType: LogType.LOG_JSDOC, 10161847f8eSopenharmony_ci }); 10261847f8eSopenharmony_ci } 10361847f8eSopenharmony_ci} 10461847f8eSopenharmony_ci 10561847f8eSopenharmony_ci/** 10661847f8eSopenharmony_ci * 检查JSDoc变更 10761847f8eSopenharmony_ci * @param {string} tagName 标签名称 10861847f8eSopenharmony_ci * @param {JSDoc} currentJSDoc 修改后API节点JSDoc 10961847f8eSopenharmony_ci * @param {JSDoc} lastJSDoc 修改前API节点JSDoc 11061847f8eSopenharmony_ci * @param {function} customCheckCallback 自定义检查规则 11161847f8eSopenharmony_ci */ 11261847f8eSopenharmony_cifunction checkJSDocChange(tagName, currentJSDoc, lastJSDoc, customCheckCallback) { 11361847f8eSopenharmony_ci const newTagValue = []; 11461847f8eSopenharmony_ci const oldTagValue = []; 11561847f8eSopenharmony_ci const addTags = []; 11661847f8eSopenharmony_ci if (currentJSDoc) { 11761847f8eSopenharmony_ci currentJSDoc.tags.forEach(tag => { 11861847f8eSopenharmony_ci if (tag.tag === tagName) { 11961847f8eSopenharmony_ci newTagValue.push(tag.name); 12061847f8eSopenharmony_ci } 12161847f8eSopenharmony_ci }); 12261847f8eSopenharmony_ci } 12361847f8eSopenharmony_ci if (lastJSDoc) { 12461847f8eSopenharmony_ci lastJSDoc.tags.forEach(tag => { 12561847f8eSopenharmony_ci if (tag.tag === tagName) { 12661847f8eSopenharmony_ci oldTagValue.push(tag.name); 12761847f8eSopenharmony_ci } 12861847f8eSopenharmony_ci }); 12961847f8eSopenharmony_ci } 13061847f8eSopenharmony_ci newTagValue.forEach(newValue => { 13161847f8eSopenharmony_ci if (!new Set(oldTagValue).has(newValue)) { 13261847f8eSopenharmony_ci addTags.push(newValue); 13361847f8eSopenharmony_ci } 13461847f8eSopenharmony_ci }); 13561847f8eSopenharmony_ci 13661847f8eSopenharmony_ci customCheckCallback(newTagValue, oldTagValue, addTags); 13761847f8eSopenharmony_ci} 13861847f8eSopenharmony_ci 13961847f8eSopenharmony_ci/** 14061847f8eSopenharmony_ci * 检查权限变化 14161847f8eSopenharmony_ci * @param { string } newPermission 14261847f8eSopenharmony_ci * @param { string } oldPermission 14361847f8eSopenharmony_ci * @returns { boolean } 14461847f8eSopenharmony_ci */ 14561847f8eSopenharmony_cifunction checkPermissionChange(newPermission, oldPermission) { 14661847f8eSopenharmony_ci const permissionChange = newPermission.replace(oldPermission, ''); 14761847f8eSopenharmony_ci return !newPermission.includes(oldPermission) || /\band\b/.test(permissionChange); 14861847f8eSopenharmony_ci} 14961847f8eSopenharmony_ci 15061847f8eSopenharmony_ci/** 15161847f8eSopenharmony_ci * 检查JSDoc变更 15261847f8eSopenharmony_ci * @param {array} newNodeJSDocs 修改后API节点JSDoc列表 15361847f8eSopenharmony_ci * @param {enum} statusCode api_diff工具返回的变更状态 15461847f8eSopenharmony_ci * @param {ts.Node} node 修改后API节点 15561847f8eSopenharmony_ci */ 15661847f8eSopenharmony_cifunction checkCurrentJSDocChange(newNodeJSDocs, statusCode, node) { 15761847f8eSopenharmony_ci const currentJSDoc = newNodeJSDocs[newNodeJSDocs.length - 1]; 15861847f8eSopenharmony_ci const lastJSDoc = 15961847f8eSopenharmony_ci newNodeJSDocs.length === DIFF_INFO.NEW_JSDOCS_LENGTH 16061847f8eSopenharmony_ci ? null 16161847f8eSopenharmony_ci : newNodeJSDocs[newNodeJSDocs.length - DIFF_INFO.NEW_JSDOC_INDEX]; 16261847f8eSopenharmony_ci 16361847f8eSopenharmony_ci checkApiChangeVersion(currentJSDoc, lastJSDoc, node); 16461847f8eSopenharmony_ci 16561847f8eSopenharmony_ci if (statusCode === StatusCode.ERRORCODE_CHANGES || statusCode === StatusCode.NEW_ERRORCODE) { 16661847f8eSopenharmony_ci checkJSDocChange('throws', currentJSDoc, lastJSDoc, (newTagValue, oldTagValue, addTags) => { 16761847f8eSopenharmony_ci if (addTags.length !== 0 && oldTagValue.length === 0) { 16861847f8eSopenharmony_ci changeErrors.push({ 16961847f8eSopenharmony_ci node: node, 17061847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_JSDOC_TRROWS, 17161847f8eSopenharmony_ci LogType: LogType.LOG_JSDOC, 17261847f8eSopenharmony_ci }); 17361847f8eSopenharmony_ci } 17461847f8eSopenharmony_ci }); 17561847f8eSopenharmony_ci } else if (statusCode === StatusCode.PERMISSION_CHANGES) { 17661847f8eSopenharmony_ci checkJSDocChange('permission', currentJSDoc, lastJSDoc, (newTagValue, oldTagValue, addTags) => { 17761847f8eSopenharmony_ci let checkResult = true; 17861847f8eSopenharmony_ci // 从无到有新增权限 17961847f8eSopenharmony_ci checkResult = !(newTagValue.length === 1 && oldTagValue.length === 0); 18061847f8eSopenharmony_ci // 权限值变更 18161847f8eSopenharmony_ci if (newTagValue.length === 1 && oldTagValue.length === 1) { 18261847f8eSopenharmony_ci const newPermission = newTagValue[0]; 18361847f8eSopenharmony_ci const oldPermission = oldTagValue[0]; 18461847f8eSopenharmony_ci checkResult = checkResult && 18561847f8eSopenharmony_ci !(newPermission !== oldPermission && checkPermissionChange(newPermission, oldPermission)); 18661847f8eSopenharmony_ci } 18761847f8eSopenharmony_ci 18861847f8eSopenharmony_ci if (!checkResult) { 18961847f8eSopenharmony_ci changeErrors.push({ 19061847f8eSopenharmony_ci node: node, 19161847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_JSDOC_PERMISSION, 19261847f8eSopenharmony_ci LogType: LogType.LOG_JSDOC, 19361847f8eSopenharmony_ci }); 19461847f8eSopenharmony_ci } 19561847f8eSopenharmony_ci }); 19661847f8eSopenharmony_ci } 19761847f8eSopenharmony_ci} 19861847f8eSopenharmony_ci 19961847f8eSopenharmony_ci/** 20061847f8eSopenharmony_ci * 检查API历史版本JSDoc是否包含废弃标签 20161847f8eSopenharmony_ci * 20261847f8eSopenharmony_ci * @param {array} historyJSDocs 历史接口JSDoc信息 20361847f8eSopenharmony_ci * @returns {boolean} 20461847f8eSopenharmony_ci */ 20561847f8eSopenharmony_cifunction checkApiDeprecatedStatus(historyJSDocs) { 20661847f8eSopenharmony_ci for (let i = 0; i < historyJSDocs.length; i++) { 20761847f8eSopenharmony_ci const doc = historyJSDocs[i]; 20861847f8eSopenharmony_ci for (let j = 0; j < doc.tags.length; j++) { 20961847f8eSopenharmony_ci const tag = doc.tags[j]; 21061847f8eSopenharmony_ci if (tag === 'deprecated') { 21161847f8eSopenharmony_ci return true; 21261847f8eSopenharmony_ci } 21361847f8eSopenharmony_ci } 21461847f8eSopenharmony_ci } 21561847f8eSopenharmony_ci return false; 21661847f8eSopenharmony_ci} 21761847f8eSopenharmony_ci 21861847f8eSopenharmony_ci/** 21961847f8eSopenharmony_ci * 检查JSDoc变更内容 22061847f8eSopenharmony_ci * @param {array} newNodeJSDocs 修改后API节点JSDoc数组 22161847f8eSopenharmony_ci * @param {array} oldNodeJSDocs 修改前API节点JSDoc数组 22261847f8eSopenharmony_ci * @param {object} change api_diff获取的变更数据 22361847f8eSopenharmony_ci */ 22461847f8eSopenharmony_cifunction checkJSDocChangeInfo(newNodeJSDocs, oldNodeJSDocs, change) { 22561847f8eSopenharmony_ci if (checkApiDeprecatedStatus(oldNodeJSDocs)) { 22661847f8eSopenharmony_ci changeErrors.push({ 22761847f8eSopenharmony_ci node: change.newNode, 22861847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_DEPRECATED, 22961847f8eSopenharmony_ci LogType: LogType.LOG_JSDOC, 23061847f8eSopenharmony_ci }); 23161847f8eSopenharmony_ci } 23261847f8eSopenharmony_ci if (newNodeJSDocs.length !== oldNodeJSDocs.length + 1 && !isNewApi(oldNodeJSDocs)) { 23361847f8eSopenharmony_ci changeErrors.push({ 23461847f8eSopenharmony_ci node: change.newNode, 23561847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_JSDOC_NUMBER, 23661847f8eSopenharmony_ci LogType: LogType.LOG_JSDOC, 23761847f8eSopenharmony_ci }); 23861847f8eSopenharmony_ci } else if (!checkHistoryJSDoc(newNodeJSDocs, oldNodeJSDocs)) { 23961847f8eSopenharmony_ci changeErrors.push({ 24061847f8eSopenharmony_ci node: change.newNode, 24161847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_JSDOC_CHANGE, 24261847f8eSopenharmony_ci LogType: LogType.LOG_JSDOC, 24361847f8eSopenharmony_ci }); 24461847f8eSopenharmony_ci } else { 24561847f8eSopenharmony_ci checkCurrentJSDocChange(newNodeJSDocs, change.statusCode, change.newNode); 24661847f8eSopenharmony_ci } 24761847f8eSopenharmony_ci} 24861847f8eSopenharmony_ci 24961847f8eSopenharmony_ci/** 25061847f8eSopenharmony_ci * 检查JSDoc变更 25161847f8eSopenharmony_ci * @param {object} change api_diff获取的变更数据 25261847f8eSopenharmony_ci */ 25361847f8eSopenharmony_cifunction checkJSDocChangeEntry(change) { 25461847f8eSopenharmony_ci const newNodeJSDocs = parseJsDoc(change.newNode); 25561847f8eSopenharmony_ci const oldNodeJSDocs = parseJsDoc(change.oldNode); 25661847f8eSopenharmony_ci 25761847f8eSopenharmony_ci checkJSDocChangeInfo(newNodeJSDocs, oldNodeJSDocs, change); 25861847f8eSopenharmony_ci} 25961847f8eSopenharmony_ci 26061847f8eSopenharmony_ci/** 26161847f8eSopenharmony_ci * 解析接口参数类型数据 26261847f8eSopenharmony_ci * @param {array} paramType 接口参数类型 26361847f8eSopenharmony_ci * @returns {array} 26461847f8eSopenharmony_ci */ 26561847f8eSopenharmony_cifunction analysisParamType(paramType) { 26661847f8eSopenharmony_ci const types = []; 26761847f8eSopenharmony_ci if (paramType.kind === ts.SyntaxKind.UnionType) { 26861847f8eSopenharmony_ci paramType.types.forEach(type => { 26961847f8eSopenharmony_ci types.push(type.getText()); 27061847f8eSopenharmony_ci }); 27161847f8eSopenharmony_ci } else { 27261847f8eSopenharmony_ci types.push(paramType.getText()); 27361847f8eSopenharmony_ci } 27461847f8eSopenharmony_ci return types; 27561847f8eSopenharmony_ci} 27661847f8eSopenharmony_ci 27761847f8eSopenharmony_ci/** 27861847f8eSopenharmony_ci * 检查API接口历史参数 27961847f8eSopenharmony_ci * @param {array} currentParameters 修改后API节点参数 28061847f8eSopenharmony_ci * @param {array} lastParameters 修改前API节点参数 28161847f8eSopenharmony_ci */ 28261847f8eSopenharmony_cifunction checkHistoryParameters(currentParameters, lastParameters, change) { 28361847f8eSopenharmony_ci for (let i = currentParameters.length - 1; i >= 0; i--) { 28461847f8eSopenharmony_ci const historyParamType = analysisParamType(lastParameters[i].type); 28561847f8eSopenharmony_ci const currentParamType = analysisParamType(currentParameters[i].type); 28661847f8eSopenharmony_ci 28761847f8eSopenharmony_ci // 拦截可选变必选 28861847f8eSopenharmony_ci if (currentParameters[i].isRequired && !lastParameters[i].isRequired) { 28961847f8eSopenharmony_ci changeErrors.push({ 29061847f8eSopenharmony_ci node: change.newNode, 29161847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_API_HISTORY_PARAM_REQUIRED_CHANGE, 29261847f8eSopenharmony_ci LogType: LogType.LOG_API, 29361847f8eSopenharmony_ci }); 29461847f8eSopenharmony_ci } 29561847f8eSopenharmony_ci 29661847f8eSopenharmony_ci // 变更后参数无类型定义 29761847f8eSopenharmony_ci if (currentParamType.length === 0) { 29861847f8eSopenharmony_ci changeErrors.push({ 29961847f8eSopenharmony_ci node: change.newNode, 30061847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_API_HISTORY_PARAM_WITHOUT_TYPE_CHANGE, 30161847f8eSopenharmony_ci LogType: LogType.LOG_API, 30261847f8eSopenharmony_ci }); 30361847f8eSopenharmony_ci // 变更后参数范围大于等于变更前 30461847f8eSopenharmony_ci } else if (currentParamType.length >= historyParamType.length) { 30561847f8eSopenharmony_ci checkHistoryParametersType(historyParamType, currentParamType, changeErrors, change); 30661847f8eSopenharmony_ci // 变更后参数范围小于变更前 30761847f8eSopenharmony_ci } else { 30861847f8eSopenharmony_ci changeErrors.push({ 30961847f8eSopenharmony_ci node: change.newNode, 31061847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_API_HISTORY_PARAM_RANGE_CHANGE, 31161847f8eSopenharmony_ci LogType: LogType.LOG_API, 31261847f8eSopenharmony_ci }); 31361847f8eSopenharmony_ci } 31461847f8eSopenharmony_ci } 31561847f8eSopenharmony_ci 31661847f8eSopenharmony_ci // 拦截参数位置变更 31761847f8eSopenharmony_ci for (let i = 0; i < currentParameters.length; i++) { 31861847f8eSopenharmony_ci for (let j = 0; j < lastParameters.length; j++) { 31961847f8eSopenharmony_ci if ( 32061847f8eSopenharmony_ci currentParameters[i].paramName === lastParameters[j].paramName && 32161847f8eSopenharmony_ci currentParameters[i].order !== lastParameters[j].order 32261847f8eSopenharmony_ci ) { 32361847f8eSopenharmony_ci changeErrors.push({ 32461847f8eSopenharmony_ci node: change.newNode, 32561847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_API_HISTORY_PARAM_POSITION_CHANGE, 32661847f8eSopenharmony_ci LogType: LogType.LOG_API, 32761847f8eSopenharmony_ci }); 32861847f8eSopenharmony_ci } 32961847f8eSopenharmony_ci } 33061847f8eSopenharmony_ci } 33161847f8eSopenharmony_ci} 33261847f8eSopenharmony_ci 33361847f8eSopenharmony_cifunction checkHistoryParametersType(historyParamType, currentParamType, changeErrors, change) { 33461847f8eSopenharmony_ci for (let j = 0; j < historyParamType.length; j++) { 33561847f8eSopenharmony_ci if (!new Set(currentParamType).has(historyParamType[j])) { 33661847f8eSopenharmony_ci changeErrors.push({ 33761847f8eSopenharmony_ci node: change.newNode, 33861847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_API_HISTORY_PARAM_TYPE_CHANGE, 33961847f8eSopenharmony_ci LogType: LogType.LOG_API, 34061847f8eSopenharmony_ci }); 34161847f8eSopenharmony_ci } 34261847f8eSopenharmony_ci } 34361847f8eSopenharmony_ci} 34461847f8eSopenharmony_ci 34561847f8eSopenharmony_ci/** 34661847f8eSopenharmony_ci * 检查API接口新增参数 34761847f8eSopenharmony_ci * @param {array} parameters 新增参数列表 34861847f8eSopenharmony_ci */ 34961847f8eSopenharmony_cifunction checkCurrentParameters(parameters, change) { 35061847f8eSopenharmony_ci for (let i = 0; i < parameters.length; i++) { 35161847f8eSopenharmony_ci if (parameters[i].isRequired) { 35261847f8eSopenharmony_ci changeErrors.push({ 35361847f8eSopenharmony_ci node: change.newNode, 35461847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_API_NEW_REQUIRED_PARAM, 35561847f8eSopenharmony_ci LogType: LogType.LOG_API, 35661847f8eSopenharmony_ci }); 35761847f8eSopenharmony_ci break; 35861847f8eSopenharmony_ci } 35961847f8eSopenharmony_ci } 36061847f8eSopenharmony_ci} 36161847f8eSopenharmony_ci 36261847f8eSopenharmony_ci/** 36361847f8eSopenharmony_ci * 解析接口参数数据 36461847f8eSopenharmony_ci * @param {array} params tsNode参数列表 36561847f8eSopenharmony_ci * @returns {array} 36661847f8eSopenharmony_ci */ 36761847f8eSopenharmony_cifunction analysisParameters(params) { 36861847f8eSopenharmony_ci const paramInfoData = []; 36961847f8eSopenharmony_ci params.forEach((param, index) => { 37061847f8eSopenharmony_ci const data = { 37161847f8eSopenharmony_ci paramName: param.name ? param.name.getText() : '', 37261847f8eSopenharmony_ci order: index, 37361847f8eSopenharmony_ci isRequired: param.questionToken && param.questionToken.kind === ts.SyntaxKind.QuestionToken ? false : true, 37461847f8eSopenharmony_ci type: param.type, 37561847f8eSopenharmony_ci }; 37661847f8eSopenharmony_ci paramInfoData.push(data); 37761847f8eSopenharmony_ci }); 37861847f8eSopenharmony_ci return paramInfoData; 37961847f8eSopenharmony_ci} 38061847f8eSopenharmony_ci 38161847f8eSopenharmony_ci/** 38261847f8eSopenharmony_ci * 判断是否为新增接口或已变更为最新版本接口 38361847f8eSopenharmony_ci * @param {array} oldNodeJSDocs 修改前API节点JSDoc数组 38461847f8eSopenharmony_ci */ 38561847f8eSopenharmony_cifunction isNewApi(oldNodeJSDocs) { 38661847f8eSopenharmony_ci const checkApiVersion = getCheckApiVersion(); 38761847f8eSopenharmony_ci const oldNodeVersion = getJSDocVersion(oldNodeJSDocs[oldNodeJSDocs.length - 1]); 38861847f8eSopenharmony_ci 38961847f8eSopenharmony_ci if (oldNodeVersion === checkApiVersion) { 39061847f8eSopenharmony_ci return true; 39161847f8eSopenharmony_ci } 39261847f8eSopenharmony_ci return false; 39361847f8eSopenharmony_ci} 39461847f8eSopenharmony_ci 39561847f8eSopenharmony_ci/** 39661847f8eSopenharmony_ci * 检查API变更 39761847f8eSopenharmony_ci * @param {object} change api_diff获取的变更数据 39861847f8eSopenharmony_ci */ 39961847f8eSopenharmony_cifunction checkApiChangeEntry(change) { 40061847f8eSopenharmony_ci // 检查JSDoc 40161847f8eSopenharmony_ci const newNodeJSDocs = parseJsDoc(change.newNode); 40261847f8eSopenharmony_ci const oldNodeJSDocs = parseJsDoc(change.oldNode); 40361847f8eSopenharmony_ci 40461847f8eSopenharmony_ci checkJSDocChangeInfo(newNodeJSDocs, oldNodeJSDocs, change); 40561847f8eSopenharmony_ci 40661847f8eSopenharmony_ci // 新增接口不检查接口变更 40761847f8eSopenharmony_ci if (isNewApi(oldNodeJSDocs) && oldNodeJSDocs.length === 1) { 40861847f8eSopenharmony_ci return; 40961847f8eSopenharmony_ci } 41061847f8eSopenharmony_ci const currentParameters = analysisParameters(change.newNode.parameters); 41161847f8eSopenharmony_ci const lastParameters = analysisParameters(change.oldNode.parameters); 41261847f8eSopenharmony_ci 41361847f8eSopenharmony_ci if (currentParameters.length === lastParameters.length) { 41461847f8eSopenharmony_ci checkHistoryParameters(currentParameters, lastParameters, change); 41561847f8eSopenharmony_ci } else if (currentParameters.length > lastParameters.length) { 41661847f8eSopenharmony_ci if (lastParameters.length !== 0) { 41761847f8eSopenharmony_ci checkHistoryParameters(currentParameters.slice(0, lastParameters.length), lastParameters, change); 41861847f8eSopenharmony_ci } 41961847f8eSopenharmony_ci checkCurrentParameters(currentParameters.slice(lastParameters.length, currentParameters.length), change); 42061847f8eSopenharmony_ci } else { 42161847f8eSopenharmony_ci changeErrors.push({ 42261847f8eSopenharmony_ci node: change.newNode, 42361847f8eSopenharmony_ci errorInfo: ErrorValueInfo.ERROR_CHANGES_API_DELETE_PARAM, 42461847f8eSopenharmony_ci LogType: LogType.LOG_API, 42561847f8eSopenharmony_ci }); 42661847f8eSopenharmony_ci } 42761847f8eSopenharmony_ci} 42861847f8eSopenharmony_ci 42961847f8eSopenharmony_ci/** 43061847f8eSopenharmony_ci * 分析变更内容 43161847f8eSopenharmony_ci * @param {array} changes api_diff获取的变更数据列表 43261847f8eSopenharmony_ci */ 43361847f8eSopenharmony_cifunction analyseChanges(changes) { 43461847f8eSopenharmony_ci const functionTypeSet = new Set(FUNCTION_TYPES); 43561847f8eSopenharmony_ci changes.forEach(change => { 43661847f8eSopenharmony_ci if ( 43761847f8eSopenharmony_ci change.statusCode === StatusCode.ERRORCODE_CHANGES || 43861847f8eSopenharmony_ci change.statusCode === StatusCode.NEW_ERRORCODE || 43961847f8eSopenharmony_ci change.statusCode === StatusCode.PERMISSION_CHANGES 44061847f8eSopenharmony_ci ) { 44161847f8eSopenharmony_ci checkJSDocChangeEntry(change); 44261847f8eSopenharmony_ci } else if ( 44361847f8eSopenharmony_ci change.statusCode === StatusCode.FUNCTION_CHANGES && 44461847f8eSopenharmony_ci functionTypeSet.has(change.oldNode.kind) && 44561847f8eSopenharmony_ci functionTypeSet.has(change.newNode.kind) 44661847f8eSopenharmony_ci ) { 44761847f8eSopenharmony_ci checkApiChangeEntry(change); 44861847f8eSopenharmony_ci } 44961847f8eSopenharmony_ci }); 45061847f8eSopenharmony_ci} 45161847f8eSopenharmony_ci 45261847f8eSopenharmony_ci/** 45361847f8eSopenharmony_ci * 封装错误信息 45461847f8eSopenharmony_ci */ 45561847f8eSopenharmony_cifunction logChangeErrors() { 45661847f8eSopenharmony_ci changeErrors.forEach(error => { 45761847f8eSopenharmony_ci const sourceFileNode = ts.getSourceFileOfNode(error.node); 45861847f8eSopenharmony_ci addAPICheckErrorLogs( 45961847f8eSopenharmony_ci error.node, 46061847f8eSopenharmony_ci sourceFileNode, 46161847f8eSopenharmony_ci sourceFileNode.fileName, 46261847f8eSopenharmony_ci ErrorType.API_CHANGE_ERRORS, 46361847f8eSopenharmony_ci error.errorInfo, 46461847f8eSopenharmony_ci error.LogType, 46561847f8eSopenharmony_ci ErrorLevel.MIDDLE 46661847f8eSopenharmony_ci ); 46761847f8eSopenharmony_ci }); 46861847f8eSopenharmony_ci} 46961847f8eSopenharmony_ci 47061847f8eSopenharmony_ci/** 47161847f8eSopenharmony_ci * API变更检查入口 47261847f8eSopenharmony_ci */ 47361847f8eSopenharmony_cifunction checkApiChanges(prId) { 47461847f8eSopenharmony_ci let isApiChanged = false; 47561847f8eSopenharmony_ci const oldFiles = []; 47661847f8eSopenharmony_ci // 编译流水线根目录 47761847f8eSopenharmony_ci const rootDir = path.resolve(__dirname, `../../../../../Archive/patch_info/openharmony_interface_sdk-js_${prId}`); 47861847f8eSopenharmony_ci if (!fs.existsSync(rootDir)) { 47961847f8eSopenharmony_ci return; 48061847f8eSopenharmony_ci } 48161847f8eSopenharmony_ci const oldApiPath = path.resolve(rootDir, './old'); 48261847f8eSopenharmony_ci const newFiles = []; 48361847f8eSopenharmony_ci const newApiPath = path.resolve(rootDir, './new'); 48461847f8eSopenharmony_ci const fileNames = fs.readdirSync(rootDir); 48561847f8eSopenharmony_ci let patchConfigPath = ''; 48661847f8eSopenharmony_ci for (let i = 0; i < fileNames.length; i++) { 48761847f8eSopenharmony_ci if (/\.json$/.test(fileNames[i])) { 48861847f8eSopenharmony_ci patchConfigPath = path.resolve(rootDir, fileNames[i]); 48961847f8eSopenharmony_ci break; 49061847f8eSopenharmony_ci } 49161847f8eSopenharmony_ci } 49261847f8eSopenharmony_ci const patchConfig = JSON.parse(fs.readFileSync(patchConfigPath)); 49361847f8eSopenharmony_ci for (const file in patchConfig) { 49461847f8eSopenharmony_ci // 判断为文件修改 49561847f8eSopenharmony_ci if (patchConfig[file] === 'M' && /\.d\.ts$/.test(file)) { 49661847f8eSopenharmony_ci const oldMdFilePath = path.resolve(oldApiPath, file); 49761847f8eSopenharmony_ci const newMdFilePath = path.resolve(newApiPath, file); 49861847f8eSopenharmony_ci 49961847f8eSopenharmony_ci if (fs.existsSync(oldMdFilePath) && fs.existsSync(newMdFilePath)) { 50061847f8eSopenharmony_ci oldFiles.push(oldMdFilePath); 50161847f8eSopenharmony_ci newFiles.push(newMdFilePath); 50261847f8eSopenharmony_ci isApiChanged = true; 50361847f8eSopenharmony_ci } 50461847f8eSopenharmony_ci } 50561847f8eSopenharmony_ci } 50661847f8eSopenharmony_ci 50761847f8eSopenharmony_ci if (isApiChanged) { 50861847f8eSopenharmony_ci const diffResult = exportDiffInfo(newFiles, oldFiles, newApiPath, oldApiPath); 50961847f8eSopenharmony_ci analyseChanges(diffResult); 51061847f8eSopenharmony_ci logChangeErrors(); 51161847f8eSopenharmony_ci } 51261847f8eSopenharmony_ci} 51361847f8eSopenharmony_ciexports.checkApiChanges = checkApiChanges; 514