• 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}
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