1/* 2 * Copyright (c) 2024 - 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 { ts } from 'arkanalyzer'; 17import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; 18 19const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'Json5parser'); 20 21export class Json5parser { 22 /** 23 * 获取JSON5文件的根对象字面量表达式 24 * @param file - JSON5文件的源文件对象 25 * @returns 如果找到根对象字面量表达式,则返回该表达式;否则返回undefined 26 */ 27 public static getRootObjectLiteral(file: ts.JsonSourceFile): ts.ObjectLiteralExpression | undefined { 28 // 检查文件语句是否为空 29 if (!file.statements || !file.statements.length) { 30 logger.error('The JSON5 file format is incorrect, the root node statements is empty.'); 31 return undefined; 32 } 33 const expressionStatement = file.statements[0]; 34 if (expressionStatement.kind !== ts.SyntaxKind.ExpressionStatement) { 35 logger.error(`The JSON5 file format is incorrect, the first child node is not ExpressionStatement. kind: ${expressionStatement.kind}`); 36 return undefined; 37 } 38 // JSON5顶层对象仅识别一个 39 const rootObjectLiteralExpression = (expressionStatement as ts.ExpressionStatement).expression; 40 if (!rootObjectLiteralExpression) { 41 logger.error('The JSON5 file format is incorrect, the first child node expression is empty.'); 42 return undefined; 43 } 44 // 检查表达式是否为对象字面量表达式 45 if (rootObjectLiteralExpression.kind === ts.SyntaxKind.ObjectLiteralExpression) { 46 return rootObjectLiteralExpression as ts.ObjectLiteralExpression; 47 } 48 // 检查表达式是否为数组字面量表达式 49 if (rootObjectLiteralExpression.kind === ts.SyntaxKind.ArrayLiteralExpression) { 50 const elements = (rootObjectLiteralExpression as ts.ArrayLiteralExpression).elements; 51 // 检查数组是否为空或第一个元素是否为对象字面量表达式 52 if (elements && elements.length && elements[0].kind === ts.SyntaxKind.ObjectLiteralExpression) { 53 return elements[0] as ts.ObjectLiteralExpression; 54 } 55 logger.error('The JSON5 file format is incorrect, the node ArrayLiteralExpression first element is not ObjectLiteralExpression.'); 56 } 57 logger.error('The JSON5 file format is incorrect.'); 58 return undefined; 59 } 60 61 /** 62 * 解析对象字面量表达式 63 * @param objectLiteralExpression - 对象字面量表达式 64 * @param file - JSON源文件 65 * @returns 解析后的对象字面量表达式 66 */ 67 private static parseObjectLiteralExpression(objectLiteralExpression: ts.ObjectLiteralExpression, file: ts.JsonSourceFile): { [k: string]: unknown } { 68 const res: { [k: string]: unknown } = {}; 69 objectLiteralExpression.properties.forEach(node => { 70 const propNode = node as ts.PropertyAssignment; 71 const key = (propNode.name as ts.Identifier).text; 72 const value = this.parsePropertyInitializer(propNode.initializer, file); 73 res[key] = value; 74 }); 75 return res; 76 } 77 78 /** 79 * 解析语法树中的表达式节点 80 * @param node - 表达式节点 81 * @param file - JSON源文件 82 * @returns 解析后的值 83 */ 84 private static parsePropertyInitializer(node: ts.Expression, file: ts.JsonSourceFile): unknown { 85 if (node.kind === ts.SyntaxKind.StringLiteral) { 86 return (node as ts.StringLiteral).text; 87 } else if (node.kind === ts.SyntaxKind.NumericLiteral) { 88 return parseInt((node as ts.NumericLiteral).text); 89 } else if (node.kind === ts.SyntaxKind.PrefixUnaryExpression) { 90 return Number((node as ts.PrefixUnaryExpression).getText(file)); 91 } else if (node.kind === ts.SyntaxKind.ArrayLiteralExpression) { 92 return this.parseArrayLiteral(node, file); 93 } else if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) { 94 return this.parseObjectLiteralExpression(node as ts.ObjectLiteralExpression, file); 95 } else if (node.kind === ts.SyntaxKind.TrueKeyword) { 96 return true; 97 } else if (node.kind === ts.SyntaxKind.FalseKeyword) { 98 return false; 99 } 100 return undefined; 101 } 102 103 /** 104 * 解析数组字面量表达式 105 * @param node - 要解析的表达式节点 106 * @param file - 所属的 JSON 源文件 107 * @returns 解析后的数组 108 */ 109 private static parseArrayLiteral(node: ts.Expression, file: ts.JsonSourceFile): unknown[] { 110 const res: unknown[] = []; 111 (node as ts.ArrayLiteralExpression).elements.forEach(n => { 112 res.push(this.parsePropertyInitializer(n, file)); 113 }); 114 return res; 115 } 116 117 /** 118 * 解析JSON文本 119 * @param text - 要解析的JSON文本 120 * @returns 解析后的对象 121 */ 122 public static parseJsonText(text: string): { [k: string]: unknown } { 123 const file = ts.parseJsonText('', text); 124 const rootObjectLiteralExpression = this.getRootObjectLiteral(file); 125 if (!rootObjectLiteralExpression) { 126 return {}; 127 } 128 return this.parseObjectLiteralExpression(rootObjectLiteralExpression, file); 129 } 130}