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