• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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