• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 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
16import * as arkts from '@koalaui/libarkts';
17import { getClassPropertyName, isPrivateClassProperty } from '../utils';
18import { UISyntaxRule, UISyntaxRuleContext } from './ui-syntax-rule';
19
20function addProperty(item: arkts.AstNode, structName: string, privateMap: Map<string, string[]>): void {
21  if (!arkts.isClassProperty(item) || !isPrivateClassProperty(item)) {
22    return;
23  }
24  // Check if structName already exists in privateMap
25  if (privateMap.has(structName)) {
26    // If it exists, retrieve the current string[] and append the new content
27    privateMap.get(structName)?.push(getClassPropertyName(item));
28  } else {
29    // If it doesn't exist, create a new string[] and add the content
30    privateMap.set(structName, [getClassPropertyName(item)]);
31  }
32}
33
34function checkPrivateVariables(
35  node: arkts.AstNode,
36  context: UISyntaxRuleContext,
37  privateMap: Map<string, string[]>
38): void {
39  // Check if the current node is the root node
40  if (arkts.nodeType(node) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE) {
41    node.getChildren().forEach((member) => {
42      if (!arkts.isStructDeclaration(member)) {
43        return;
44      }
45      const structName: string = member.definition.ident?.name ?? '';
46      member.definition?.body?.forEach((item) => {
47        addProperty(item, structName, privateMap);
48      });
49    });
50  }
51  if (!arkts.isCallExpression(node)) {
52    return;
53  }
54  const componentName = node.expression.dumpSrc();
55  // If the initialization is for a component with private properties
56  if (!privateMap.has(componentName)) {
57    return;
58  }
59  node.arguments?.forEach((member) => {
60    member.getChildren().forEach((property) => {
61      if (!arkts.isProperty(property)) {
62        return;
63      }
64      const propertyName: string = property.key?.dumpSrc() ?? '';
65      if (privateMap.get(componentName)!.includes(propertyName)) {
66        context.report({
67          node: property,
68          message: rule.messages.cannotInitializePrivateVariables,
69          data: {
70            propertyName: propertyName,
71          },
72        });
73      }
74    });
75  });
76}
77
78const rule: UISyntaxRule = {
79  name: 'check-construct-private-parameter',
80  messages: {
81    cannotInitializePrivateVariables: `Property '{{propertyName}}' is private and can not be initialized through the component constructor.`,
82  },
83  setup(context) {
84    let privateMap: Map<string, string[]> = new Map();
85    return {
86      parsed: (node): void => {
87        checkPrivateVariables(node, context, privateMap);
88      },
89    };
90  },
91};
92
93export default rule;