• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023-2023 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
16namespace ts {
17export namespace ArkTSLinter_1_0 {
18
19import DiagnosticChecker = DiagnosticCheckerNamespace.DiagnosticChecker
20// Current approach relates on error code and error message matching and it is quite fragile,
21// so this place should be checked thoroughly in the case of typescript upgrade
22export namespace LibraryTypeCallDiagnosticCheckerNamespace {
23export const TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE = 2322;
24export const TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type '(.*)\bunknown\b(.*)' is not assignable to type '.*'\.$/;
25export const TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'null' is not assignable to type '.*'\.$/;
26export const TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'undefined' is not assignable to type '.*'\.$/;
27
28export const ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE = 2345;
29export const ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'null' is not assignable to parameter of type '.*'\.$/;
30export const ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'undefined' is not assignable to parameter of type '.*'\.$/;
31
32export const NO_OVERLOAD_MATCHES_THIS_CALL_ERROR_CODE = 2769;
33
34export class LibraryTypeCallDiagnosticChecker implements DiagnosticChecker {
35  inLibCall: boolean = false;
36  diagnosticMessages: Array<ts.DiagnosticMessageChain> | undefined;
37  filteredDiagnosticMessages: DiagnosticMessageChain[] = [];
38
39  constructor(filteredDiagnosticMessages: DiagnosticMessageChain[]) {
40    this.filteredDiagnosticMessages = filteredDiagnosticMessages;
41  }
42
43  configure(inLibCall: boolean, diagnosticMessages: Array<ts.DiagnosticMessageChain>) {
44    this.inLibCall = inLibCall;
45    this.diagnosticMessages = diagnosticMessages;
46  }
47
48  checkMessageText(msg: string): boolean {
49    if (this.inLibCall) {
50      const match = msg.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE) ||
51        msg.match(ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE) ||
52        msg.match(TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE) ||
53        msg.match(TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE);
54      return !match;
55    }
56    return true;
57  }
58
59  checkMessageChain(chain: ts.DiagnosticMessageChain): boolean {
60    if (chain.code == TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE) {
61      if (chain.messageText.match(TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) {
62        return false;
63      }
64      if (this.inLibCall && chain.messageText.match(TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) {
65        return false;
66      }
67      if (this.inLibCall && chain.messageText.match(TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) {
68        return false;
69      }
70    }
71    if (chain.code == ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE) {
72      if (this.inLibCall && chain.messageText.match(ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE)) {
73        return false;
74      }
75      if (this.inLibCall && chain.messageText.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE)) {
76        return false;
77      }
78    }
79    return chain.next == undefined ? true : this.checkMessageChain(chain.next[0]);
80  };
81
82  checkFilteredDiagnosticMessages(msgText: ts.DiagnosticMessageChain | string) {
83    if (this.filteredDiagnosticMessages.length == 0) {
84      return true;
85    }
86
87    if (typeof msgText !== 'string' && this.filteredDiagnosticMessages.includes(msgText)) {
88      return false;
89    }
90
91    for (const msgChain of this.filteredDiagnosticMessages) {
92      if (typeof msgText == 'string') {
93        if (msgText == msgChain.messageText) {
94          return false;
95        }
96        continue;
97      }
98
99      let curMsg: ts.DiagnosticMessageChain | undefined = msgText;
100      let curFilteredMsg: ts.DiagnosticMessageChain | undefined = msgChain;
101      while (curMsg) {
102        if (!curFilteredMsg) {
103          return true;
104        }
105
106        if (curMsg.code != curFilteredMsg.code) {
107          return true;
108        }
109
110        if (curMsg.messageText != curFilteredMsg.messageText) {
111          return true;
112        }
113
114        curMsg = curMsg.next ? curMsg.next[0]: undefined;
115        curFilteredMsg = curFilteredMsg.next ? curFilteredMsg.next[0]: undefined;
116      }
117
118      return false;
119    }
120    return true;
121  }
122
123  checkDiagnosticMessage(msgText: string | ts.DiagnosticMessageChain): boolean {
124    if (!this.diagnosticMessages) {
125      return false;
126    }
127
128    if (this.inLibCall && !this.checkFilteredDiagnosticMessages(msgText)) {
129      return false;
130    }
131
132    if (typeof msgText == 'string') {
133      return this.checkMessageText(msgText);
134    }
135
136    if (!this.checkMessageChain(msgText)) {
137      this.diagnosticMessages.push(msgText);
138      return false;
139    }
140    return true;
141  }
142}
143}
144}
145}
146