• 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 { PresetDecorators, getAnnotationUsage } from '../utils';
18import { UISyntaxRule, UISyntaxRuleContext } from './ui-syntax-rule';
19
20function findPropertyDecorator(
21  node: arkts.ClassProperty,
22  decoratorName: string
23): arkts.AnnotationUsage | undefined {
24  const annotation = node.annotations?.find(annotation =>
25    annotation.expr &&
26    annotation.expr.dumpSrc() === decoratorName
27  );
28  return annotation;
29}
30
31function paramDecoratorError(
32  context: UISyntaxRuleContext,
33  hasParamDecorator: arkts.AnnotationUsage,
34  hasComponentDecorator: arkts.AnnotationUsage
35): void {
36  context.report({
37    node: hasParamDecorator,
38    message: rule.messages.paramDecoratorError,
39    fix: () => {
40      const startPosition = arkts.getStartPosition(hasComponentDecorator);
41      const endPosition = arkts.getEndPosition(hasComponentDecorator);
42      return {
43        range: [startPosition, endPosition],
44        code: `@${PresetDecorators.COMPONENT_V2}`,
45      };
46    },
47  });
48}
49
50function stateDecoratorError(
51  context: UISyntaxRuleContext,
52  hasStateDecorator: arkts.AnnotationUsage,
53  hasComponentV2Decorator: arkts.AnnotationUsage
54): void {
55  context.report({
56    node: hasStateDecorator,
57    message: rule.messages.stateDecoratorError,
58    fix: () => {
59      const startPosition = arkts.getStartPosition(hasComponentV2Decorator);
60      const endPosition = arkts.getEndPosition(hasComponentV2Decorator);
61      return {
62        range: [startPosition, endPosition],
63        code: `@${PresetDecorators.COMPONENT_V1}`,
64      };
65    },
66  });
67}
68
69function findDecoratorError(
70  node: arkts.StructDeclaration,
71  context: UISyntaxRuleContext
72): void {
73  const hasComponentV2Decorator = getAnnotationUsage(node, PresetDecorators.COMPONENT_V2);
74  const hasComponentDecorator = getAnnotationUsage(node, PresetDecorators.COMPONENT_V1);
75  // Check where @Param and @State are used
76  node.definition.body.forEach((property) => {
77    if (arkts.isClassProperty(property)) {
78      const hasParamDecorator = findPropertyDecorator(property, PresetDecorators.PARAM);
79      const hasStateDecorator = findPropertyDecorator(property, PresetDecorators.STATE);
80      // Check that @Param is in the correct location
81      if (hasParamDecorator && !hasComponentV2Decorator && hasComponentDecorator) {
82        paramDecoratorError(context, hasParamDecorator, hasComponentDecorator);
83      }
84      // Check that @State is in the correct location
85      if (hasStateDecorator && !hasComponentDecorator && hasComponentV2Decorator) {
86        stateDecoratorError(context, hasStateDecorator, hasComponentV2Decorator);
87      }
88    }
89  });
90}
91
92
93const rule: UISyntaxRule = {
94  name: 'old-new-decorator-mix-use-check',
95  messages: {
96    paramDecoratorError: `The '@Param' decorator can only be used in a 'struct' decorated with '@ComponentV2'.`,
97    stateDecoratorError: `The '@State' decorator can only be used in a 'struct' decorated with '@Component'.`,
98  },
99  setup(context) {
100    return {
101      parsed: (node): void => {
102        if (!arkts.isStructDeclaration(node)) {
103          return;
104        }
105        findDecoratorError(node, context);
106      },
107    };
108  },
109};
110
111export default rule;
112