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 { getAnnotationUsage, PresetDecorators } from '../utils'; 18import { UISyntaxRule } from './ui-syntax-rule'; 19 20const rule: UISyntaxRule = { 21 name: 'struct-missing-decorator', 22 messages: { 23 missingComponentDecorator: `struct '{{structName}}' is missing '@Component' or '@CustomDialog' decorators`, 24 misusedPreview: `struct '{{structName}}' misused '@Preview' decorator. it should be decorated by '@Component' or '@CustomDialog'`, 25 misusedObserved: `struct '{{structName}}' misused '@Observed' decorator. it should be decorated by '@Component' or '@CustomDialog'`, 26 }, 27 setup(context) { 28 function hasDecorator(node: arkts.StructDeclaration, decorator: string): boolean { 29 return !!getAnnotationUsage(node, decorator); 30 } 31 32 return { 33 parsed: (node): void => { 34 if (!arkts.isStructDeclaration(node)) { 35 return; 36 } 37 // Check for the presence of specific decorators on the struct 38 const structName = node.definition.ident?.name ?? ''; 39 const structNode = node.definition.ident; 40 const hasComponent = hasDecorator(node, PresetDecorators.COMPONENT_V1); 41 const hasComponentV2 = hasDecorator(node, PresetDecorators.COMPONENT_V2); 42 const hasCustomDialog = hasDecorator(node, PresetDecorators.CUSTOM_DIALOG); 43 const hasPreview = getAnnotationUsage(node, PresetDecorators.PREVIEW); 44 const hasObserved = getAnnotationUsage(node, PresetDecorators.OBSERVED_V1); 45 // If no valid component decorators (@Component or @CustomDialog) are found 46 if (!hasComponent && !hasComponentV2 && !hasCustomDialog && structNode) { 47 context.report({ 48 node: structNode, 49 message: rule.messages.missingComponentDecorator, 50 data: { structName }, 51 }); 52 } 53 // If the @Preview decorator is used but the struct is not decorated with @Component or @CustomDialog 54 if (hasPreview && !hasComponent && !hasComponentV2 && !hasCustomDialog && structNode) { 55 context.report({ 56 node: structNode, 57 message: rule.messages.misusedPreview, 58 data: { structName }, 59 }); 60 } 61 // If the @Observed decorator is used but the struct is not decorated with @Component or @CustomDialog 62 if (hasObserved && !hasComponent && !hasComponentV2 && !hasCustomDialog && structNode) { 63 context.report({ 64 node: structNode, 65 message: rule.messages.misusedObserved, 66 data: { structName }, 67 }); 68 } 69 }, 70 }; 71 }, 72}; 73 74export default rule; 75