1/*
2 * Copyright (c) 2023 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 convertXml from '@ohos.convertxml';
17import type { Features, Language, Feature, Changelog, Icon } from '@ohos/common/src/main/ets/const/update_const';
18import { LogUtils } from '@ohos/common/src/main/ets/util/LogUtils';
19
20let conv = new convertXml.ConvertXML();
21
22let options: convertXml.ConvertOptions = {
23  trim: false,
24  declarationKey: '_declaration',
25  instructionKey: '_instruction',
26  attributesKey: '_attributes',
27  textKey: '_text',
28  cdataKey: '_cdata',
29  doctypeKey: '_doctype',
30  commentKey: '_comment',
31  parentKey: '_parent',
32  typeKey: '_type',
33  nameKey: '_name',
34  elementsKey: '_elements',
35};
36
37let changelog: Changelog;
38
39/**
40 * Changelog解析工具
41 *
42 * @since 2022-06-06
43 */
44namespace ChangelogParseUtils {
45  /**
46   * Changelog解析
47   *
48   * @param res 待解析的string
49   * @param callback 解析结果回调
50   */
51  export function parseXml(res: string, callback: (data: Changelog) => void): void {
52    logInfo('read file parse start');
53    changelog = { language: new Map() };
54    if (!res) {
55      logError('res is null!');
56      callback(null);
57      return;
58    }
59    let xmlResult: Object = conv.convert(res, options);
60    if (!xmlResult || !xmlResult['_elements'] || xmlResult['_elements'].length <= 0) {
61      logError('xmlResult is null! ' + JSON.stringify(xmlResult));
62      callback(null);
63      return;
64    }
65    let root = xmlResult['_elements'][0];
66    if (!root || !root['_elements'] || root['_elements'].length <= 0) {
67      logError('root is null! ' + JSON.stringify(root));
68      callback(null);
69      return;
70    }
71    parseRoot(root);
72    logInfo('read file parse end');
73    callback(changelog);
74  }
75
76  function parseRoot(root: any): void {
77    // 倒序解析,先解析Icon
78    let icons = {};
79    logInfo('root length ' + root['_elements'].length);
80    for (let index = root['_elements'].length; index > 0; index--) {
81      let element = root['_elements'][index - 1];
82      if (!element) {
83        logError('element is null! ' + JSON.stringify(element));
84        continue;
85      }
86      if (element['_type'] === 'element' && element['_name'] === 'default-language') {
87        let attribute = element['_attributes']['name'];
88        logInfo('default-language :' + attribute);
89        changelog.defLanguage = attribute;
90      }
91      if (element['_type'] === 'element' && element['_name'] === 'displayType') {
92        let attribute = element['_elements']?.[0]?.['_text'];
93        logInfo('displayType :' + attribute);
94        changelog.displayType = attribute;
95      }
96      if (element['_type'] === 'element' && element['_name'] === 'icons') {
97        let iconsElement = element['_elements'];
98        parseIcons(iconsElement, icons);
99      }
100      parseLanguage(element, icons);
101    }
102  }
103
104  function parseLanguage(element: any, icons: Object): void {
105    let language: Language = { featuresArray: [] };
106    if (element['_type'] === 'element' && element['_name'] === 'language') {
107      let attribute: string;
108      if (!element['_attributes']) {
109        logError('language is null :' + JSON.stringify(element['_attributes']));
110        return;
111      }
112      attribute = element['_attributes']['name'];
113      let languageElement = element['_elements'];
114      language.language = attribute;
115      changelog.language.set(language.language, language);
116
117      if (!languageElement || languageElement.length <= 0) {
118        logError('features is null' + JSON.stringify(languageElement));
119        return;
120      }
121      parseFeatures(languageElement, language, icons);
122    }
123  }
124
125  function parseIcons(iconsElement: any, icons: Object): void {
126    let icon: Icon;
127    for (let index = 0; index < iconsElement.length; index++) {
128      let iconElement = iconsElement[index];
129      if (!iconElement) {
130        logError('iconElement is null :' + JSON.stringify(iconElement));
131        continue;
132      }
133      if (iconElement['_type'] === 'element' && iconElement['_name'] === 'icon') {
134        icon = {
135          id: iconElement['_attributes']['id'],
136          pkg: iconElement['_attributes']['pkg'],
137          res: iconElement['_attributes']['res'],
138        };
139        icons[icon.id] = icon;
140      }
141    }
142  }
143
144  function parseFeatures(languageElement: any, language: Language, icons: Object): void {
145    let features: Features;
146    for (let index = 0; index < languageElement.length; index++) {
147      let featuresElement = languageElement[index];
148      if (!featuresElement) {
149        logInfo('featuresElement is null' + JSON.stringify(featuresElement));
150        continue;
151      }
152
153      if (featuresElement['_type'] === 'element' && featuresElement['_name'] === 'features') {
154        let moduleString = featuresElement['_attributes']['module'];
155        let typeString = featuresElement['_attributes']['type'];
156        let id = featuresElement['_attributes']['id'];
157        let featureElement = featuresElement['_elements'];
158        let featureList: Feature[] = [];
159        features = {
160          title: moduleString,
161          id: id,
162          featureModuleType: typeString,
163          featureList: featureList,
164          icon: icons[id],
165        };
166        language.featuresArray.push(features);
167
168        if (!featureElement || featureElement.length <= 0) {
169          logError('featureElement is null: ' + JSON.stringify(featureElement));
170          continue;
171        }
172        parseFeature(featureElement, featureList);
173      }
174    }
175  }
176
177  function parseFeature(featureElement: any, featureList: Array<Feature>): void {
178    let feature: Feature;
179    for (let index = 0; index < featureElement.length; index++) {
180      let featureItem = featureElement[index];
181      if (featureItem['_type'] !== 'element' || featureItem['_name'] !== 'feature') {
182        continue;
183      }
184      if (!featureItem) {
185        logError('featureItem is null: ' + JSON.stringify(featureItem));
186        continue;
187      }
188
189      let title: string;
190      if (featureItem['_attributes']) {
191        title = featureItem['_attributes']['title'];
192      }
193      let content: string;
194      if (featureItem['_elements']) {
195        content = featureItem['_elements'][0]['_text'];
196      }
197      if (title) {
198        feature = { subTitle: title, contents: [] };
199        featureList.push(feature);
200      } else {
201        if (!feature) {
202          feature = { subTitle: title, contents: [] };
203          featureList.push(feature);
204        }
205        if (content) {
206          feature.contents.push(content);
207        }
208      }
209    }
210  }
211
212  function logInfo(message: string): void {
213    LogUtils.info('ChangelogParseUtils', message);
214  }
215
216  function logError(message: string): void {
217    LogUtils.error('ChangelogParseUtils', message);
218  }
219}
220
221export default ChangelogParseUtils;