• 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 * as ts from 'ohos-typescript';
17import * as fs from 'fs';
18import Logger, { LOG_MODULE_TYPE } from './logger';
19
20const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'json5parser');
21
22export function fetchDependenciesFromFile(filePath: string): {
23    [k: string]: unknown;
24} {
25    if (!fs.existsSync(filePath)) {
26        return {};
27    }
28    let configurationsText: string;
29    try {
30        configurationsText = fs.readFileSync(filePath, 'utf-8');
31    } catch (error) {
32        logger.error(`Error reading file: ${error}`);
33        return {};
34    }
35    const file = parseJsonText(configurationsText);
36    return file;
37}
38
39export function parseJsonText(text: string): { [k: string]: unknown } {
40    let file;
41    try {
42        file = ts.parseJsonText('', text);
43    } catch (error) {
44        logger.error(`Error parsing file: ${error}`);
45        return {};
46    }
47    const rootObjectLiteralExpression = getRootObjectLiteral(file);
48    if (!rootObjectLiteralExpression) {
49        logger.error('The JSON5 file format is incorrect, rootObjectLiteralExpression is null.');
50        return {};
51    }
52    return parseObjectLiteralExpression(rootObjectLiteralExpression, file);
53}
54
55function getRootObjectLiteral(file: ts.JsonSourceFile): ts.ObjectLiteralExpression | undefined {
56    if (!file || !file.statements || !file.statements.length) {
57        logger.error('The JSON5 file format is incorrect, the root node statements is empty.');
58        return undefined;
59    }
60    const expressionStatement = file.statements[0];
61    if (expressionStatement.kind !== ts.SyntaxKind.ExpressionStatement) {
62        logger.error(`The JSON5 file format is incorrect, the first child node is not ExpressionStatement. kind: ${expressionStatement.kind}`);
63        return undefined;
64    }
65    const rootObjectLiteralExpression = (expressionStatement as ts.ExpressionStatement).expression;
66    if (!rootObjectLiteralExpression) {
67        logger.error('The JSON5 file format is incorrect, the first child node is empty.');
68        return undefined;
69    }
70
71    if (rootObjectLiteralExpression.kind === ts.SyntaxKind.ObjectLiteralExpression) {
72        return rootObjectLiteralExpression as ts.ObjectLiteralExpression;
73    }
74
75    if (rootObjectLiteralExpression.kind === ts.SyntaxKind.ArrayLiteralExpression) {
76        const elements = (rootObjectLiteralExpression as ts.ArrayLiteralExpression).elements;
77        if (elements && elements.length && elements[0].kind === ts.SyntaxKind.ObjectLiteralExpression) {
78            return elements[0] as ts.ObjectLiteralExpression;
79        }
80        logger.error('The JSON5 file format is incorrect, the node ArrayLiteralExpression first element is not ObjectLiteralExpression.');
81    }
82    logger.error('The JSON5 file format is incorrect.');
83    return undefined;
84}
85
86function parsePropertyInitializer(node: ts.Expression, file: ts.JsonSourceFile): unknown {
87    if (node.kind === ts.SyntaxKind.StringLiteral) {
88        return (node as ts.StringLiteral).text;
89    } else if (node.kind === ts.SyntaxKind.NumericLiteral) {
90        return (node as ts.NumericLiteral).text;
91    } else if (node.kind === ts.SyntaxKind.PrefixUnaryExpression) {
92        return (node as ts.PrefixUnaryExpression).getText(file);
93    } else if (node.kind === ts.SyntaxKind.ArrayLiteralExpression) {
94        return parseArrayLiteral(node, file);
95    } else if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) {
96        return parseObjectLiteralExpression(node as ts.ObjectLiteralExpression, file);
97    } else if (node.kind === ts.SyntaxKind.TrueKeyword) {
98        return true;
99    } else if (node.kind === ts.SyntaxKind.FalseKeyword) {
100        return false;
101    }
102    return undefined;
103}
104
105function parseArrayLiteral(node: ts.Expression, file: ts.JsonSourceFile): unknown[] {
106    const res: unknown[] = [];
107    (node as ts.ArrayLiteralExpression).elements.forEach(n => {
108        res.push(parsePropertyInitializer(n, file));
109    });
110    return res;
111}
112
113function parseObjectLiteralExpression(ObjectLiteralExpression: ts.ObjectLiteralExpression, file: ts.JsonSourceFile): { [k: string]: unknown } {
114    const res: { [k: string]: unknown } = {};
115    ObjectLiteralExpression.properties.forEach(node => {
116        const propNode = node as ts.PropertyAssignment;
117        const key = (propNode.name as ts.Identifier).text;
118        const value = parsePropertyInitializer(propNode.initializer, file);
119        res[key] = value;
120    });
121    return res;
122}
123