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 { hasAPINote, ApiCheckResult, requireTypescriptModule, commentNodeWhiteList, splitPath, 30 isWhiteListFile } = require('./utils'); 31const ts = requireTypescriptModule(); 32const result = require('../check_result.json'); 33const rules = require('../code_style_rule.json'); 34const { checkApiChanges } = require('./check_diff_changes'); 35const whiteLists = require('../config/jsdocCheckWhiteList.json'); 36 37function checkAPICodeStyle(url, isTestCase) { 38 if (fs.existsSync(url)) { 39 const mdApiFiles = getMdFiles(url, isTestCase); 40 tsTransform(mdApiFiles, checkAPICodeStyleCallback); 41 } 42} 43 44function getMdFiles(url, isTestCase) { 45 const mdFiles = []; 46 const content = fs.readFileSync(url, 'utf-8'); 47 const filePathArr = content.split(/[(\r\n)\r\n]+/); 48 filePathArr.forEach(filePath => { 49 const pathElements = new Set(); 50 splitPath(filePath, pathElements); 51 if (!pathElements.has('build-tools') || isTestCase) { 52 mdFiles.push(filePath); 53 } 54 }) 55 return mdFiles; 56} 57 58function tsTransform(uFiles, callback) { 59 uFiles.forEach((filePath, index) => { 60 console.log(`scaning file in no ${++index}!`); 61 if (/\.d\.ts/.test(filePath) && fs.existsSync(filePath)) { 62 const content = fs.readFileSync(filePath, 'utf-8'); 63 const fileName = path.basename(filePath).replace(/.d.ts/g, '.ts'); 64 ts.transpileModule(content, { 65 compilerOptions: { 66 target: ts.ScriptTarget.ES2017, 67 }, 68 fileName: fileName, 69 transformers: { before: [callback(filePath)] }, 70 }); 71 } 72 }); 73} 74 75function checkAPICodeStyleCallback(fileName) { 76 return (context) => { 77 return (node) => { 78 checkAPIFileName(node, fileName); 79 checkAllNode(node, node, fileName); 80 return node; 81 }; 82 }; 83} 84 85function checkAllNode(node, sourcefile, fileName) { 86 if (!ts.isImportDeclaration(node) && !ts.isSourceFile(node)) { 87 // check hump naming 88 checkAPINameOfHump(node, sourcefile, fileName); 89 } 90 if (hasAPINote(node)) { 91 // check decorator 92 checkAPIDecorators(node, sourcefile, fileName); 93 // check apiNote spelling 94 checkSpelling(node, sourcefile, fileName); 95 // check syscap 96 checkSyscap(node, sourcefile, fileName); 97 // check deprecated 98 checkDeprecated(node, sourcefile, fileName); 99 // check permission 100 checkPermission(node, sourcefile, fileName); 101 // check event subscription 102 checkEventSubscription(node, sourcefile, fileName); 103 104 const uesWhiteList = !isWhiteListFile(fileName, whiteLists.JSDocCheck); 105 if (commentNodeWhiteList.includes(node.kind) && uesWhiteList) { 106 checkJSDoc(node, sourcefile, fileName, true); 107 } 108 } 109 checkAnyInAPI(node, sourcefile, fileName); 110 if (ts.isIdentifier(node)) { 111 // check variable spelling 112 checkSpelling(node, sourcefile, fileName); 113 // check naming 114 if (node.parent.parent.kind !== ts.SyntaxKind.JSDoc) { 115 checkNaming(node, sourcefile, fileName); 116 } 117 } 118 node.getChildren().forEach((item) => checkAllNode(item, sourcefile, fileName)); 119} 120 121function scanEntry(url, prId, isTestCase) { 122 if (prId && prId !== 'NA') { 123 checkApiChanges(prId); 124 // scan entry 125 checkAPICodeStyle(url, isTestCase); 126 } 127 result.scanResult.push(`api_check: ${ApiCheckResult.formatCheckResult}`); 128 return result.scanResult; 129} 130exports.scanEntry = scanEntry; 131 132function reqGitApi(scanResult, prId) { 133 const administrators = new Set(); 134 const SUCCESS_CODE = 200; 135 rules.administrators.forEach((administrator) => { 136 administrators.add(administrator.user); 137 }); 138 if (ApiCheckResult.formatCheckResult || !prId || prId === 'NA') { 139 return scanResult; 140 } 141 const commentRequestPath = `https://gitee.com/api/v5/repos/openharmony/interface_sdk-js/pulls/${prId}/comments?page=1&per_page=100&direction=desc`; 142 const res = request('GET', commentRequestPath, { 143 headers: { 144 'Content-Type': 'application/json;charset=UFT-8', 145 }, 146 }); 147 if (res.statusCode !== SUCCESS_CODE) { 148 throw `The giteeAPI access failed, StatusCode:${res.statusCode}`; 149 } 150 const resBody = new TextDecoder('utf-8').decode(res.body); 151 const comments = JSON.parse(`{"resultBody": ${resBody}}`); 152 const resultBody = comments.resultBody; 153 if (!resultBody || resultBody.length === 0 || !(resultBody instanceof Array)) { 154 throw 'The format of data returned by giteeAPI is incorrect'; 155 } 156 for (let i = 0; i < resultBody.length; i++) { 157 const comment = resultBody[i]; 158 if (!(comment && comment.user && comment.user.id && comment.body)) { 159 continue; 160 } 161 const userId = String(comment.user.id); 162 if (userId === rules.ciId && /^代码有更新,重置PR验证状态$/.test(comment.body)) { 163 break; 164 } 165 if (administrators.has(userId) && /^approve api check$/.test(comment.body)) { 166 ApiCheckResult.formatCheckResult = true; 167 scanResult = ['api_check: true']; 168 break; 169 } 170 } 171 return scanResult; 172} 173exports.reqGitApi = reqGitApi; 174