• 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 { getIdentifierName } from '../utils';
18import { UISyntaxRule, UISyntaxRuleContext } from './ui-syntax-rule';
19
20const NOT_PARAM_LENGTH: number = 0;
21const BUILD_NAME: string = 'build';
22const BUILD_FUNCTION_COUNT_INI: number = 0;
23const BUILD_FUNCTION_COUNT: number = 1;
24const NOT_STATEMENT_LENGTH: number = 0;
25
26// rule1: Check if the build function contains arguments and report an error
27function validateBuildFunctionParameters(buildFunction: arkts.MethodDefinition, context: UISyntaxRuleContext): void {
28  const paramsNodes = buildFunction.scriptFunction.params;
29  if (paramsNodes.length > NOT_PARAM_LENGTH) {
30    paramsNodes.forEach((param) => {
31      if (arkts.isEtsParameterExpression(param)) {
32        reportBuildParamNotAllowed(param, context);
33      }
34    });
35  }
36}
37
38// Report an error with an unallowed parameter in the build function
39function reportBuildParamNotAllowed(
40  param: arkts.ETSParameterExpression,
41  context: UISyntaxRuleContext
42): void {
43  context.report({
44    node: param,
45    message: rule.messages.invalidComponet,
46    fix: (param) => {
47      const startPosition = arkts.getStartPosition(param);
48      const endPosition = arkts.getEndPosition(param);
49      return {
50        range: [startPosition, endPosition],
51        code: ''
52      };
53    }
54  });
55}
56
57function validateConstructorForBuildFunction(
58  node: arkts.StructDeclaration,
59  member: arkts.MethodDefinition,
60  buildFunctionCount: number,
61  context: UISyntaxRuleContext
62): void {
63  const blockStatement = member.scriptFunction.body;
64  if (!blockStatement || !arkts.isBlockStatement(blockStatement)) {
65    return;
66  }
67  const statements = blockStatement.statements;
68  const structName = node.definition.ident;
69  if (buildFunctionCount !== BUILD_FUNCTION_COUNT &&
70    statements.length === NOT_STATEMENT_LENGTH) {
71    reportMissingBuildInStruct(structName, blockStatement, context);
72  }
73}
74
75function reportMissingBuildInStruct(
76  structName: arkts.Identifier | undefined,
77  blockStatement: arkts.BlockStatement,
78  context: UISyntaxRuleContext
79): void {
80  if (!structName) {
81    return;
82  }
83  context.report({
84    node: structName,
85    message: rule.messages.invalidBuild,
86    fix: (structName) => {
87      const startPosition = arkts.getStartPosition(blockStatement);
88      const endPosition = startPosition;
89      return {
90        range: [startPosition, endPosition],
91        code: '{\nbuild {\n}'
92      };
93    }
94  });
95}
96
97function validateBuild(
98  node: arkts.StructDeclaration,
99  buildFunctionCount: number,
100  context: UISyntaxRuleContext,
101): void {
102  node.definition.body.forEach((member) => {
103    // Check if the member is defined for the method and the method name is 'build'
104    if (arkts.isMethodDefinition(member) && getIdentifierName(member.name) === BUILD_NAME) {
105      buildFunctionCount++;
106      validateBuildFunctionParameters(member, context);
107    }
108    // rule2: This rule validates the use of the 'build' function
109    if (arkts.isMethodDefinition(member) &&
110      arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR === member.kind) {
111      validateConstructorForBuildFunction(node, member, buildFunctionCount, context);
112    }
113  });
114}
115
116const rule: UISyntaxRule = {
117  name: 'validate-build-in-struct',
118  messages: {
119    invalidComponet: `A custom component can have only one 'build' function, which does not require parameters.`,
120    invalidBuild: `This rule validates the use of the 'build' function`,
121  },
122  setup(context) {
123    return {
124      parsed: (node: arkts.AstNode): void => {
125        if (!arkts.isStructDeclaration(node)) {
126          return;
127        }
128        let buildFunctionCount: number = BUILD_FUNCTION_COUNT_INI;
129        validateBuild(node, buildFunctionCount, context);
130      },
131    };
132  },
133};
134
135export default rule;