1/* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16const path = require('path'); 17const fs = require('fs'); 18const request = require('sync-request'); 19const { checkSpelling } = require('./check_spelling'); 20const { checkAPIDecorators } = require('./check_decorator'); 21const { checkPermission } = require('./check_permission'); 22const { checkSyscap } = require('./check_syscap'); 23const { checkDeprecated } = require('./check_deprecated'); 24const { checkAPINameOfHump, checkAPIFileName } = require('./check_hump'); 25const { checkJSDoc } = require('./check_legality'); 26const { checkNaming } = require('./check_naming'); 27const { checkEventSubscription } = require('./check_event_subscription'); 28const { checkAnyInAPI } = require('./check_any'); 29const { checkFileTagOrder } = require('./check_file_tag_order'); 30const { hasAPINote, ApiCheckResult, requireTypescriptModule, commentNodeWhiteList, splitPath, 31 isWhiteListFile } = require('./utils'); 32const ts = requireTypescriptModule(); 33const result = require('../check_result.json'); 34const rules = require('../code_style_rule.json'); 35const { checkApiChanges } = require('./check_diff_changes'); 36const whiteLists = require('../config/jsdocCheckWhiteList.json'); 37 38function checkAPICodeStyle(url, isTestCase) { 39 if (fs.existsSync(url)) { 40 const mdApiFiles = getMdFiles(url, isTestCase); 41 tsTransform(mdApiFiles, checkAPICodeStyleCallback); 42 } 43} 44 45function getMdFiles(url, isTestCase) { 46 const mdFiles = []; 47 const content = fs.readFileSync(url, 'utf-8'); 48 const filePathArr = content.split(/[(\r\n)\r\n]+/); 49 filePathArr.forEach(filePath => { 50 const pathElements = new Set(); 51 splitPath(filePath, pathElements); 52 if (!pathElements.has('build-tools') || isTestCase) { 53 mdFiles.push(filePath); 54 } 55 }); 56 return mdFiles; 57} 58 59function tsTransform(uFiles, callback) { 60 uFiles.forEach((filePath, index) => { 61 console.log(`scaning file in no ${++index}!`); 62 if (/\.d\.ts/.test(filePath) && fs.existsSync(filePath)) { 63 const content = fs.readFileSync(filePath, 'utf-8'); 64 const fileName = path.basename(filePath).replace(/.d.ts/g, '.ts'); 65 ts.transpileModule(content, { 66 compilerOptions: { 67 target: ts.ScriptTarget.ES2017, 68 }, 69 fileName: fileName, 70 transformers: { before: [callback(filePath)] }, 71 }); 72 } 73 }); 74} 75 76function checkAPICodeStyleCallback(fileName) { 77 return (context) => { 78 return (node) => { 79 checkAPIFileName(node, fileName); 80 checkAllNode(node, node, fileName); 81 return node; 82 }; 83 }; 84} 85 86function checkAllNode(node, sourcefile, fileName) { 87 if (!ts.isImportDeclaration(node) && !ts.isSourceFile(node)) { 88 // check hump naming 89 checkAPINameOfHump(node, sourcefile, fileName); 90 } 91 if (hasAPINote(node)) { 92 // check decorator 93 checkAPIDecorators(node, sourcefile, fileName); 94 // check apiNote spelling 95 checkSpelling(node, sourcefile, fileName); 96 // check syscap 97 checkSyscap(node, sourcefile, fileName); 98 // check deprecated 99 checkDeprecated(node, sourcefile, fileName); 100 // check permission 101 checkPermission(node, sourcefile, fileName); 102 // check event subscription 103 checkEventSubscription(node, sourcefile, fileName); 104 // check file tag order 105 if (ts.isSourceFile(node)) { 106 checkFileTagOrder(node, sourcefile, fileName); 107 } 108 109 const uesWhiteList = !isWhiteListFile(fileName, whiteLists.JSDocCheck); 110 if (commentNodeWhiteList.includes(node.kind) && uesWhiteList) { 111 checkJSDoc(node, sourcefile, fileName, true); 112 } 113 } 114 checkAnyInAPI(node, sourcefile, fileName); 115 if (ts.isIdentifier(node)) { 116 // check variable spelling 117 checkSpelling(node, sourcefile, fileName); 118 // check naming 119 if (node.parent.parent.kind !== ts.SyntaxKind.JSDoc) { 120 checkNaming(node, sourcefile, fileName); 121 } 122 } 123 node.getChildren().forEach((item) => checkAllNode(item, sourcefile, fileName)); 124} 125 126function scanEntry(url, prId, isTestCase) { 127 if (prId && prId !== 'NA') { 128 checkApiChanges(prId); 129 // scan entry 130 checkAPICodeStyle(url, isTestCase); 131 } 132 result.scanResult.push(`api_check: ${ApiCheckResult.formatCheckResult}`); 133 return result.scanResult; 134} 135exports.scanEntry = scanEntry; 136 137function reqGitApi(scanResult, prId) { 138 const administrators = new Set(); 139 const SUCCESS_CODE = 200; 140 rules.administrators.forEach((administrator) => { 141 administrators.add(administrator.user); 142 }); 143 if (ApiCheckResult.formatCheckResult || !prId || prId === 'NA') { 144 return scanResult; 145 } 146 const commentRequestPath = `https://gitee.com/api/v5/repos/openharmony/interface_sdk-js/pulls/${prId}/comments?page=1&per_page=100&direction=desc`; 147 const res = request('GET', commentRequestPath, { 148 headers: { 149 'Content-Type': 'application/json;charset=UFT-8', 150 }, 151 }); 152 if (res.statusCode !== SUCCESS_CODE) { 153 throw `The giteeAPI access failed, StatusCode:${res.statusCode}`; 154 } 155 const resBody = new TextDecoder('utf-8').decode(res.body); 156 const comments = JSON.parse(`{"resultBody": ${resBody}}`); 157 const resultBody = comments.resultBody; 158 if (!resultBody || resultBody.length === 0 || !(resultBody instanceof Array)) { 159 throw 'The format of data returned by giteeAPI is incorrect'; 160 } 161 for (let i = 0; i < resultBody.length; i++) { 162 const comment = resultBody[i]; 163 if (!(comment && comment.user && comment.user.id && comment.body)) { 164 continue; 165 } 166 const userId = String(comment.user.id); 167 if (userId === rules.ciId && /^代码有更新,重置PR验证状态$/.test(comment.body)) { 168 break; 169 } 170 if (administrators.has(userId) && /^approve api check$/.test(comment.body)) { 171 ApiCheckResult.formatCheckResult = true; 172 scanResult = ['api_check: true']; 173 break; 174 } 175 } 176 return scanResult; 177} 178exports.reqGitApi = reqGitApi; 179