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;