• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}