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