1/*
2 * Copyright (c) 2022 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
16interface ReceiveObject {
17  obj: Object;
18  spaces?: string | number;
19}
20
21interface NativeConvertXml {
22  new(): NativeConvertXml;
23  convert(strXml: string, options?: Object): ReceiveObject;
24  convertToJSObject(strXml: string, options?: Object): ReceiveObject;
25  fastConvertToJSObject(strXml: string, options?: Object): NativeConvertXml;
26}
27interface ConvertXML {
28  ConvertXml: NativeConvertXml;
29}
30declare function requireInternal(s: string): ConvertXML;
31const convertXml = requireInternal('convertxml');
32
33const LESS_SIGN_INDEX = 3;
34const TypeErrorCode = 401;
35class BusinessError extends Error {
36  code: number;
37  constructor(msg: string) {
38    super(msg);
39    this.name = 'BusinessError';
40    this.code = TypeErrorCode;
41  }
42}
43
44class ConvertXML {
45  convertxmlclass: NativeConvertXml;
46  constructor() {
47    this.convertxmlclass = new convertXml.ConvertXml();
48  }
49  convert(strXml: string, options?: Object): ReceiveObject {
50    strXml = dealXml(strXml);
51    let converted: ReceiveObject = this.convertxmlclass.convert(strXml, options);
52    let strEnd: string = '';
53    if (Object.prototype.hasOwnProperty.call(converted, 'spaces')) {
54      let space: string | number | undefined = converted.spaces;
55      delete converted.spaces;
56    }
57    return converted;
58  }
59
60  convertToJSObject(strXml: string, options?: Object): ReceiveObject {
61    if (typeof strXml !== 'string') {
62      throw new BusinessError(`Parameter error.The type of ${strXml} must be string`);
63    }
64    if (options && !(typeof options === 'undefined' || options === null) && typeof options !== 'object') {
65      throw new BusinessError(`Parameter error.The type of ${options} must be object`);
66    }
67    strXml = dealXml(strXml);
68    let converted: ReceiveObject;
69    if (arguments.length === 1) {
70      converted = this.convertxmlclass.convert(strXml);
71    } else {
72      converted = this.convertxmlclass.convert(strXml, options);
73    }
74    if (Object.prototype.hasOwnProperty.call(converted, 'spaces')) {
75      let space: string | number | undefined = converted.spaces;
76      delete converted.spaces;
77    }
78    return converted;
79  }
80
81  fastConvertToJSObject(strXml: string, options?: Object): NativeConvertXml {
82    if (typeof strXml !== 'string') {
83      throw new BusinessError(`Parameter error.The type of ${strXml} must be string`);
84    }
85    if (options && typeof options !== 'object') {
86      throw new BusinessError(`Parameter error.The type of ${options} must be object`);
87    }
88    if (arguments.length === 1) {
89      return this.convertxmlclass.fastConvertToJSObject(strXml);
90    }
91    return this.convertxmlclass.fastConvertToJSObject(strXml, options);
92  }
93}
94
95function dealXml(strXml: string): string {
96  strXml = strXml.replace(/(<!\[CDATA\[[\s\S]*?\]\]>)|(>\s+<)/g, function(match, group) {
97    if (group) {
98      return group;
99    } else {
100      return '><';
101    }
102  }).trim();
103  if ((strXml.indexOf('[CDATA')) !== -1) {
104    return dealXmlInner(strXml);
105  }
106  return strXml;
107}
108
109function dealXmlInner(strXml: string): string {
110  strXml = strXml.replace(/\]\]><!\[CDATA/g, ']]> <![CDATA');
111  return strXml.replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, function (match) {
112    return match.replace(/\\/g, '\\\\').replace(/[\r\n\t\v]/g, function (suit) {
113      switch (suit) {
114        case '\n': return '\\n';
115        case '\r': return '\\r';
116        case '\t': return '\\t';
117        case '\v': return '\\v';
118        default: return suit;
119      }
120    });
121  });
122}
123
124export default {
125  ConvertXML: ConvertXML
126};
127