• 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 { UISyntaxRule, UISyntaxRuleContext } from './ui-syntax-rule';
18import { PresetDecorators } from '../utils';
19
20function recordStructWithLinkDecorators(item: arkts.AstNode, structName: string, linkMap: Map<string, string>): void {
21  if (!arkts.isClassProperty(item)) {
22    return;
23  }
24  item.annotations?.forEach((annotation) => {
25    const annotationName: string = annotation.expr?.dumpSrc() ?? '';
26    if (annotationName === '') {
27      return;
28    }
29    // If the node has properties decorated with Link or ObjectLink, record this structure node
30    if (annotationName === PresetDecorators.LINK || annotationName === PresetDecorators.OBJECT_LINK) {
31      linkMap.set(structName, annotationName);
32    }
33  });
34}
35
36function initMap(node: arkts.AstNode, linkMap: Map<string, string>): void {
37  // Check if the current node is the root node
38  if (arkts.nodeType(node) !== arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE) {
39    return;
40  }
41  node.getChildren().forEach((member) => {
42    if (!arkts.isStructDeclaration(member)) {
43      return;
44    }
45    const structName: string = member.definition.ident?.name ?? '';
46    if (structName === '') {
47      return;
48    }
49    member.definition?.body?.forEach((item) => {
50      recordStructWithLinkDecorators(item, structName, linkMap);
51    });
52  });
53}
54
55function checkInitializeWithLiteral(node: arkts.AstNode, context: UISyntaxRuleContext,
56  linkMap: Map<string, string>
57): void {
58  if (!arkts.isCallExpression(node)) {
59    return;
60  }
61  const componentName = node.expression.dumpSrc();
62  // Only assignments to properties decorated with Link or ObjectLink trigger rule checks
63  if (!linkMap.has(componentName)) {
64    return;
65  }
66  node.arguments.forEach((member) => {
67    member.getChildren().forEach((property) => {
68      if (!arkts.isProperty(property)) {
69        return;
70      }
71      if (property.value === undefined) {
72        return;
73      }
74      const propertyType: arkts.Es2pandaAstNodeType = arkts.nodeType(property.value);
75      const key: string = property.key?.dumpSrc() ?? '';
76      if (key === '') {
77        return;
78      }
79      const value = property.value?.dumpSrc() ? property.value.dumpSrc() : '';
80      // If the assignment statement is not of type MemberExpression, throw an error
81      if (propertyType !== arkts.Es2pandaAstNodeType.AST_NODE_TYPE_MEMBER_EXPRESSION) {
82        context.report({
83          node: property,
84          message: rule.messages.cannotInitializeWithLiteral,
85          data: {
86            value: value,
87            annotationName: linkMap.get(componentName)!,
88            key: key,
89          },
90        });
91      }
92    });
93  });
94}
95
96const rule: UISyntaxRule = {
97  name: 'construct-parameter-literal',
98  messages: {
99    cannotInitializeWithLiteral: `Assigning the attribute'{{value}}' to the '@{{annotationName}}' decorated attribute '{{key}}' is not allowed.`,
100  },
101  setup(context) {
102    let linkMap: Map<string, string> = new Map();
103    return {
104      parsed: (node): void => {
105        initMap(node, linkMap);
106        checkInitializeWithLiteral(node, context, linkMap);
107      },
108    };
109  },
110};
111
112export default rule;