From 7773f14512566166a6b6564e9c75d614b1441bb0 Mon Sep 17 00:00:00 2001 From: yan-hanlin Date: Tue, 20 Jun 2023 15:46:22 +0800 Subject: [PATCH] Add optional check in event subscription check tools Signed-off-by: yan-hanlin --- .../src/check_event_subscription.js | 172 ++++++++++-------- build-tools/api_check_plugin/src/utils.js | 6 + 2 files changed, 99 insertions(+), 79 deletions(-) diff --git a/build-tools/api_check_plugin/src/check_event_subscription.js b/build-tools/api_check_plugin/src/check_event_subscription.js index ab7ccad2fe..c82c147bcc 100644 --- a/build-tools/api_check_plugin/src/check_event_subscription.js +++ b/build-tools/api_check_plugin/src/check_event_subscription.js @@ -13,7 +13,7 @@ * limitations under the License. */ -const { ErrorType, ErrorLevel, LogType, requireTypescriptModule, checkVersionNeedCheck } = require('./utils'); +const { ErrorType, ErrorLevel, LogType, requireTypescriptModule, checkVersionNeedCheck, createErrorInfo, ErrorValueInfo } = require('./utils'); const { addAPICheckErrorLogs } = require('./compile_info'); const { checkSmallHump } = require('./check_hump'); const ts = requireTypescriptModule(); @@ -22,14 +22,14 @@ const ts = requireTypescriptModule(); function checkOnAndOffAppearInPair(node, sourcefile, fileName, onEventAllNames, onEventCheckNames, offEventAllNames, offEventCheckNames) { for (const value of onEventCheckNames) { if (!offEventAllNames.has(value)) { - const checkErrorResult = 'The on and off event subscription methods do not appear in pair.'; + const checkErrorResult = createErrorInfo(ErrorValueInfo.ERROR_EVENT_ON_AND_OFF_PAIR, []); addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.API_PAIR_ERRORS, checkErrorResult, LogType.LOG_API, ErrorLevel.MIDDLE); } } for (const value of offEventCheckNames) { if (!onEventAllNames.has(value)) { - const checkErrorResult = 'The on and off event subscription methods do not appear in pair.'; + const checkErrorResult = createErrorInfo(ErrorValueInfo.ERROR_EVENT_ON_AND_OFF_PAIR, []); addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.API_PAIR_ERRORS, checkErrorResult, LogType.LOG_API, ErrorLevel.MIDDLE); } @@ -37,104 +37,118 @@ function checkOnAndOffAppearInPair(node, sourcefile, fileName, onEventAllNames, } function checkTheFirstParameter(node, sourcefile, fileName) { - // check the type of first parameter - if ((node.parameters[0].type.kind === ts.SyntaxKind.LiteralType && node.parameters[0].type.literal.kind === - ts.SyntaxKind.StringLiteral)) { - // if the first parameter is string - const parameterName = node.parameters[0].type.literal.text; - if (!checkSmallHump(parameterName)) { - const checkErrorResult = 'The event name [${parameterName}] should be named by small hump.'; + // check the version + if (!checkVersionNeedCheck(node)) { + return; + } + if (node.parameters && node.parameters.length > 0 && node.parameters[0].type) { + const firstParameterType = node.parameters[0].type; + // check the type of first parameter + if ((firstParameterType.kind === ts.SyntaxKind.LiteralType && firstParameterType.literal.kind === + ts.SyntaxKind.StringLiteral)) { + // if the first parameter is string + const parameterName = firstParameterType.literal.text; + if (!checkSmallHump(parameterName)) { + const checkErrorResult = createErrorInfo(ErrorValueInfo.ERROR_EVENT_NAME_SMALL_HUMP, [parameterName]); + addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.PARAMETER_ERRORS, checkErrorResult, LogType.LOG_API, + ErrorLevel.MIDDLE); + return; + } + } else if (firstParameterType.kind === ts.SyntaxKind.StringKeyword) { + // if the first parameter is 'string' + return; + } else { + let checkErrorResult = createErrorInfo(ErrorValueInfo.ERROR_EVENT_NAME_STRING, []); + if (firstParameterType.typeName && firstParameterType.typeName.escapedText === '') { + checkErrorResult = createErrorInfo(ErrorValueInfo.ERROR_EVENT_NAME_NULL, []); + } addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.PARAMETER_ERRORS, checkErrorResult, LogType.LOG_API, ErrorLevel.MIDDLE); - return; } - } else if (node.parameters[0].type.kind === ts.SyntaxKind.StringKeyword) { - // if the first parameter is 'string' - return; - } else { - const checkErrorResult = 'The event name should be string.'; - addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.PARAMETER_ERRORS, checkErrorResult, LogType.LOG_API, - ErrorLevel.MIDDLE); } } +function isBasicType(node) { + if (node.type !== undefined) { + const nodeKind = node.type.kind; + const basicTypes = new Set([ts.SyntaxKind.NumberKeyword, ts.SyntaxKind.StringKeyword, ts.SyntaxKind.BooleanKeyword, ts.SyntaxKind.UndefinedKeyword, + ts.SyntaxKind.LiteralType]); + if (basicTypes.has(nodeKind)) { + return true; + } + } + return false; +} + // check if the callback parameter of off function is optional function checkOffFunctions(nodes, sourcefile, fileName) { - let hasOffWithoutCallbackParameter = false; - let hasOffCallbackParameterNotOptional = false; + let isAllCallbackNotOptional = true; + let someoneMissingCallback = false; + let someoneHasCallback = false; for (let node of nodes) { - if (node.parameters.length > 1) { - const lastParameter = node.parameters[node.parameters.length - 1]; - if (lastParameter.name.escapedText !== 'callback' || lastParameter.name.escapedText !== 'observerCallback' || - lastParameter.name.escapedText !== 'listener') { - hasOffWithoutCallbackParameter = true; - } else if (lastParameter.questionToken === undefined) { - hasOffCallbackParameterNotOptional = true; - } + if (node.parameters.length === 0) { + continue; + } + const lastParameter = node.parameters[node.parameters.length - 1]; + if (isBasicType(lastParameter)) { + someoneMissingCallback = true; } else { - hasOffWithoutCallbackParameter = true; + someoneHasCallback = true; + if (lastParameter.questionToken !== undefined) { + isAllCallbackNotOptional = false; + } } } // has off fucntion with callback parameter which is not optional, and doesn't have off function without callback parameter - if (hasOffCallbackParameterNotOptional && !hasOffWithoutCallbackParameter) { - const checkErrorResult = 'The callback parameter of off function should be optional.'; + if (isAllCallbackNotOptional && !someoneMissingCallback) { + const checkErrorResult = createErrorInfo(ErrorValueInfo.ERROR_EVENT_CALLBACK_OPTIONAL, []); addAPICheckErrorLogs(nodes[0], sourcefile, fileName, ErrorType.PARAMETER_ERRORS, checkErrorResult, LogType.LOG_API, ErrorLevel.MIDDLE); } } +function extendEventNames(node, allNames, checkNames) { + const nodeType = node.parameters[0].type; + let eventName = '' + if (nodeType.kind === ts.SyntaxKind.LiteralType) { + eventName = nodeType.literal.text; + allNames.add(eventName); + } else if (nodeType.kind === ts.SyntaxKind.StringKeyword) { + eventName = 'string'; + allNames.add(eventName); + } + if (checkVersionNeedCheck(node) && eventName !== '') { + checkNames.add(eventName); + } + return eventName; +} + +function extendEventNodes(node, eventName, nodesSet) { +// store the off function node based on their names + if (!nodesSet.get(eventName)) { + nodesSet.set(eventName, [node]); + } else { + let curNodes = nodesSet.get(eventName); + curNodes.push(node); + nodesSet.set(eventName, curNodes); + } +} + // handle event subscription node function handleVariousEventSubscriptionAPI(childNode, childNodeName, sourcefile, fileName, onEventAllNames, onEventCheckNames, offEventAllNames, offEventCheckNames, offEventNodes) { - // judge the event subscription api type - if (childNodeName === 'on') { - let eventName = ''; - // store the event name - if (childNode.parameters[0].type.kind === ts.SyntaxKind.LiteralType) { - eventName = childNode.parameters[0].type.literal.text; - onEventAllNames.add(eventName); - } else if (childNode.parameters[0].type.kind === ts.SyntaxKind.StringKeyword) { - eventName = 'string'; - onEventAllNames.add(eventName); - } - // check the version - if (!checkVersionNeedCheck(childNode)) { - return; - } else if (eventName !== '') { - onEventCheckNames.add(eventName); - } - checkTheFirstParameter(childNode, sourcefile, fileName, childNodeName); - } else if (childNodeName === 'off') { - let eventName = ''; - // store the event name - if (childNode.parameters[0].type.kind === ts.SyntaxKind.LiteralType) { - eventName = childNode.parameters[0].type.literal.text; - offEventAllNames.add(eventName); - } else if (childNode.parameters[0].type.kind === ts.SyntaxKind.StringKeyword) { - eventName = 'string'; - offEventAllNames.add(eventName); - } - // store the off function node based on their names - if (!offEventNodes.get(eventName)) { - offEventNodes.set(eventName, [childNode]); - } else { - let curNodes = offEventNodes.get(eventName); - curNodes.push(childNode); - offEventNodes.set(eventName, curNodes); - } - // check the version - if (!checkVersionNeedCheck(childNode)) { - return; - } else if (eventName !== '') { - offEventCheckNames.add(eventName); - } - checkTheFirstParameter(childNode, sourcefile, fileName, childNodeName); - } else if (childNodeName === 'once' || childNodeName === 'emit') { - // check the version - if (!checkVersionNeedCheck(childNode)) { - return; + if (childNode.parameters && childNode.parameters.length > 0 && childNode.parameters[0].type) { + // judge the event subscription api type + if (childNodeName === 'on') { + extendEventNames(childNode, onEventAllNames, onEventCheckNames); + checkTheFirstParameter(childNode, sourcefile, fileName, childNodeName); + } else if (childNodeName === 'off') { + let eventName = extendEventNames(childNode, offEventAllNames, offEventCheckNames); + extendEventNodes(childNode, eventName, offEventNodes); + checkTheFirstParameter(childNode, sourcefile, fileName, childNodeName); + } else if (childNodeName === 'once' || childNodeName === 'emit') { + checkTheFirstParameter(childNode, sourcefile, fileName, childNodeName); } - checkTheFirstParameter(childNode, sourcefile, fileName, childNodeName); } } diff --git a/build-tools/api_check_plugin/src/utils.js b/build-tools/api_check_plugin/src/utils.js index e9ba7c2dd5..d4c2fbe549 100644 --- a/build-tools/api_check_plugin/src/utils.js +++ b/build-tools/api_check_plugin/src/utils.js @@ -321,6 +321,12 @@ const ErrorValueInfo = { ERROR_MORELABEL: 'JSDoc tag validity verification failed. The [$$] [$$] tag is redundant. Please check if the tag should be deleted.', ERROR_REPEATLABEL: 'the validity verification of the JSDoc tag failed. The [$$] tag is not allowed to be reused, please delete the extra tags', ERROR_USE_INTERFACE: 'the validity verification of the JSDoc tag failed. The [interface] tag and [typedef] tag are not allowed to be used simultaneously. Please confirm the interface class.', + ERROR_EVENT_NAME_STRING: 'The event name should be string.', + ERROR_EVENT_NAME_NULL: 'The event name cannot be Null value.', + ERROR_EVENT_NAME_SMALL_HUMP: 'The event name should be named by small hump. (Received [\'$$\'])', + ERROR_EVENT_CALLBACK_OPTIONAL: 'The callback parameter of off function should be optional.', + ERROR_EVENT_CALLBACK_MISSING: 'The off functions of one single event should have at least one callback parameter, and the callback parameter should be the last parameter.', + ERROR_EVENT_ON_AND_OFF_PAIR: 'The on and off event subscription methods do not appear in pair.', ILLEGAL_USE_ANY: 'Illegal [any] keyword used in the API' }; exports.ErrorValueInfo = ErrorValueInfo; -- Gitee