@sap-ux/odata-service-inquirer 0.5.28 → 0.5.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/error-handler/error-handler.d.ts +2 -2
- package/dist/error-handler/error-handler.js +4 -4
- package/dist/index.d.ts +2 -12
- package/dist/index.js +3 -20
- package/dist/prompts/connectionValidator.d.ts +121 -27
- package/dist/prompts/connectionValidator.js +231 -36
- package/dist/prompts/datasources/sap-system/abap-on-btp/cf-helper.d.ts +9 -0
- package/dist/prompts/datasources/sap-system/abap-on-btp/cf-helper.js +55 -0
- package/dist/prompts/datasources/sap-system/abap-on-btp/questions.d.ts +34 -0
- package/dist/prompts/datasources/sap-system/abap-on-btp/questions.js +213 -0
- package/dist/prompts/datasources/sap-system/abap-on-prem/questions.d.ts +7 -16
- package/dist/prompts/datasources/sap-system/abap-on-prem/questions.js +16 -164
- package/dist/prompts/datasources/sap-system/new-system/questions.d.ts +36 -5
- package/dist/prompts/datasources/sap-system/new-system/questions.js +229 -37
- package/dist/prompts/datasources/sap-system/{abap-on-prem → new-system}/service-helper.d.ts +11 -1
- package/dist/prompts/datasources/sap-system/{abap-on-prem → new-system}/service-helper.js +30 -1
- package/dist/prompts/datasources/sap-system/new-system/types.d.ts +16 -0
- package/dist/prompts/datasources/sap-system/new-system/types.js +9 -0
- package/dist/prompts/datasources/sap-system/prompt-helpers.d.ts +3 -3
- package/dist/prompts/datasources/sap-system/prompt-helpers.js +4 -4
- package/dist/prompts/datasources/sap-system/validators.d.ts +10 -1
- package/dist/prompts/datasources/sap-system/validators.js +27 -2
- package/dist/prompts/datasources/service-url/questions.js +20 -8
- package/dist/prompts/datasources/service-url/validators.d.ts +4 -4
- package/dist/prompts/datasources/service-url/validators.js +4 -6
- package/dist/prompts/prompts.js +6 -9
- package/dist/translations/odata-service-inquirer.i18n.json +24 -4
- package/dist/types.d.ts +13 -3
- package/dist/types.js +5 -1
- package/dist/utils/index.d.ts +17 -0
- package/dist/utils/index.js +29 -1
- package/package.json +2 -1
|
@@ -4,14 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.validateService = void 0;
|
|
7
|
-
const axios_extension_1 = require("@sap-ux/axios-extension");
|
|
8
7
|
const error_handler_1 = require("../../../error-handler/error-handler");
|
|
9
8
|
const i18n_1 = require("../../../i18n");
|
|
10
9
|
const types_1 = require("../../../types");
|
|
11
10
|
const utils_1 = require("../../../utils");
|
|
11
|
+
const connectionValidator_1 = require("../../connectionValidator");
|
|
12
12
|
const logger_helper_1 = __importDefault(require("../../logger-helper"));
|
|
13
13
|
const prompt_helpers_1 = require("../../prompt-helpers");
|
|
14
|
-
const connectionValidator_1 = require("../../connectionValidator");
|
|
15
14
|
/**
|
|
16
15
|
* Validates that a service specified by the service url is accessible, has the required version and returns valid metadata.
|
|
17
16
|
* Retrieves annotations (from Abap backends) if available and stores them in the PromptState.
|
|
@@ -19,12 +18,12 @@ const connectionValidator_1 = require("../../connectionValidator");
|
|
|
19
18
|
* @param url the full odata service url including query parameters
|
|
20
19
|
* @param connectionConfig the connection configuration to use for the validation, a subset of the ConnectionValidator properties
|
|
21
20
|
* @param connectionConfig.odataService the odata service instance used to retrieve the metadata (as used by ConnectionValidator)
|
|
22
|
-
* @param connectionConfig.
|
|
21
|
+
* @param connectionConfig.abapServiceProvider the abap service provider instance used to retrieve annotations (as used by ConnectionValidator)
|
|
23
22
|
* @param requiredVersion if specified and the service odata version does not match this version, an error is returned
|
|
24
23
|
* @param ignoreCertError if true some certificate errors are ignored
|
|
25
24
|
* @returns true if a valid odata service was returned, false or an error message string otherwise
|
|
26
25
|
*/
|
|
27
|
-
async function validateService(url, { odataService,
|
|
26
|
+
async function validateService(url, { odataService, abapServiceProvider }, requiredVersion = undefined, ignoreCertError = false) {
|
|
28
27
|
try {
|
|
29
28
|
if (ignoreCertError === true) {
|
|
30
29
|
connectionValidator_1.ConnectionValidator.setGlobalRejectUnauthorized(!ignoreCertError);
|
|
@@ -50,8 +49,7 @@ async function validateService(url, { odataService, axiosConfig }, requiredVersi
|
|
|
50
49
|
// Best effort attempt to get annotations but dont throw an error if it fails as this may not even be an Abap system
|
|
51
50
|
try {
|
|
52
51
|
// Create an abap provider instance to get the annotations using the same request config
|
|
53
|
-
const
|
|
54
|
-
const catalogService = abapProvider.catalog(serviceOdataVersion);
|
|
52
|
+
const catalogService = abapServiceProvider.catalog(serviceOdataVersion);
|
|
55
53
|
logger_helper_1.default.attachAxiosLogger(catalogService.interceptors);
|
|
56
54
|
logger_helper_1.default.logger.debug('Getting annotations for service');
|
|
57
55
|
const annotations = await catalogService.getAnnotations({ path: fullUrl.pathname });
|
package/dist/prompts/prompts.js
CHANGED
|
@@ -10,9 +10,8 @@ const i18n_1 = require("../i18n");
|
|
|
10
10
|
const types_1 = require("../types");
|
|
11
11
|
const questions_1 = require("./datasources/cap-project/questions");
|
|
12
12
|
const metadata_file_1 = require("./datasources/metadata-file");
|
|
13
|
-
const questions_2 = require("./datasources/sap-system/
|
|
14
|
-
const questions_3 = require("./datasources/
|
|
15
|
-
const questions_4 = require("./datasources/service-url/questions");
|
|
13
|
+
const questions_2 = require("./datasources/sap-system/new-system/questions");
|
|
14
|
+
const questions_3 = require("./datasources/service-url/questions");
|
|
16
15
|
const logger_helper_1 = __importDefault(require("./logger-helper"));
|
|
17
16
|
const prompt_helpers_1 = require("./prompt-helpers");
|
|
18
17
|
/**
|
|
@@ -61,7 +60,7 @@ function getDatasourceTypeQuestion(options) {
|
|
|
61
60
|
if (source === types_1.DatasourceType.businessHub) {
|
|
62
61
|
return {
|
|
63
62
|
message: (0, i18n_1.t)('prompts.nonUIServiceTypeWarningMessage', {
|
|
64
|
-
|
|
63
|
+
serviceType: (0, i18n_1.t)('prompts.datasourceType.businessHubName')
|
|
65
64
|
}),
|
|
66
65
|
severity: yeoman_ui_types_1.Severity.warning
|
|
67
66
|
};
|
|
@@ -79,11 +78,9 @@ async function getDatasourceTypeConditionalQuestions(promptOptions) {
|
|
|
79
78
|
const conditionalQuestions = [];
|
|
80
79
|
conditionalQuestions.push(...(0, inquirer_common_1.withCondition)([(0, metadata_file_1.getMetadataFileQuestion)(promptOptions?.metadataFilePath)], (answers) => answers.datasourceType === types_1.DatasourceType.metadataFile));
|
|
81
80
|
conditionalQuestions.push(...(0, inquirer_common_1.withCondition)((0, questions_1.getLocalCapProjectPrompts)(promptOptions), (answers) => answers.datasourceType === types_1.DatasourceType.capProject));
|
|
82
|
-
conditionalQuestions.push(...(0, inquirer_common_1.withCondition)((0,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
answers.system === questions_3.newSystemChoiceValue &&
|
|
86
|
-
answers.newSystemType === 'abapOnPrem'));
|
|
81
|
+
conditionalQuestions.push(...(0, inquirer_common_1.withCondition)((0, questions_3.getServiceUrlQuestions)(promptOptions), (answers) => answers.datasourceType === types_1.DatasourceType.odataServiceUrl));
|
|
82
|
+
conditionalQuestions.push(...(0, inquirer_common_1.withCondition)((0, questions_2.getNewSystemQuestions)(promptOptions), (answers) => answers.datasourceType === types_1.DatasourceType.sapSystem &&
|
|
83
|
+
answers.system === questions_2.newSystemChoiceValue));
|
|
87
84
|
//...further data sources to be added here
|
|
88
85
|
return conditionalQuestions;
|
|
89
86
|
}
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"breadcrumb": "Service",
|
|
86
86
|
"noServicesWarning": "No services available for the selected system, see logs for further details."
|
|
87
87
|
},
|
|
88
|
-
"
|
|
88
|
+
"newSystemType": {
|
|
89
89
|
"choiceAbapOnPrem": "ABAP On Premise",
|
|
90
90
|
"choiceAbapOnBtp": "ABAP Environment on SAP Business Technology Platform",
|
|
91
91
|
"message": "System type",
|
|
@@ -100,6 +100,22 @@
|
|
|
100
100
|
},
|
|
101
101
|
"systemSelection": {
|
|
102
102
|
"newSystemChoiceLabel": "New system"
|
|
103
|
+
},
|
|
104
|
+
"abapOnBTPType": {
|
|
105
|
+
"message": "ABAP environment definition source",
|
|
106
|
+
"choiceReentranceTicket": "Use Reentrance Ticket",
|
|
107
|
+
"choiceServiceKey": "Upload a Service Key File",
|
|
108
|
+
"choiceCloudFoundry": "Discover a Cloud Foundry Service"
|
|
109
|
+
},
|
|
110
|
+
"serviceKey": {
|
|
111
|
+
"message": "Service key file path",
|
|
112
|
+
"hint": "Select a local file that defines the service connection for an ABAP Environment on SAP Business Technology Platform",
|
|
113
|
+
"incompleteServiceKeyInfo": "Service keys file does not contain the required information",
|
|
114
|
+
"unparseableServiceKey": "Service keys file contents are not a valid JSON format"
|
|
115
|
+
},
|
|
116
|
+
"cloudFoundryAbapSystem": {
|
|
117
|
+
"message": "ABAP environment",
|
|
118
|
+
"hint": "Enter the name of the Cloud Foundry service that contains the ABAP Environment instance"
|
|
103
119
|
}
|
|
104
120
|
},
|
|
105
121
|
"errors": {
|
|
@@ -129,14 +145,17 @@
|
|
|
129
145
|
"noSuchHostError": "No such host is known",
|
|
130
146
|
"odataServiceVersionMismatch": "The template you have chosen supports V{{requiredVersion}} OData services only. The provided version is V{{serviceVersion}}.",
|
|
131
147
|
"destinationAuthError": "The selected system is returning an authentication error. Please verify the destination configuration",
|
|
132
|
-
"
|
|
148
|
+
"systemOrServiceUrlNotFound": "Please verify the url: {{- url}}, target system configuration and network connectivity",
|
|
133
149
|
"urlRedirect": "The service URL is redirecting",
|
|
134
150
|
"certValidationRequired": "Certificate validation is required to continue.",
|
|
135
151
|
"exitingGeneration": "Exiting generation. {{exitReason}}",
|
|
136
152
|
"serviceMetadataError": "An error occurred reading service metadata for service: {{- servicePath}}",
|
|
137
153
|
"serviceMetadataErrorUI": "$t(errors.serviceMetadataError, {\"servicePath\": \"{{- servicePath}}\" }). $t(texts.seeLogForDetails)",
|
|
138
154
|
"serviceMetadataErrorLog": "$t(errors.serviceMetadataError, {\"servicePath\": \"{{- servicePath}}\" }). {{error}}",
|
|
139
|
-
"serviceTypeRequestError": "Error retrieving service type: {{- error}}"
|
|
155
|
+
"serviceTypeRequestError": "Error retrieving service type: {{- error}}",
|
|
156
|
+
"noAbapEnvsInCFSpace": "No ABAP environments in CF space found.",
|
|
157
|
+
"abapEnvsCFDiscoveryFailed": "Discovering ABAP Environments failed. Please ensure you are logged into Cloud Foundry (see https://docs.cloudfoundry.org/cf-cli/getting-started.html#login).",
|
|
158
|
+
"abapServiceAuthenticationFailed": "ABAP environment authentication using UAA failed."
|
|
140
159
|
},
|
|
141
160
|
"texts": {
|
|
142
161
|
"anExpiredCert": "an expired",
|
|
@@ -144,7 +163,8 @@
|
|
|
144
163
|
"anUnknownOrInvalidCert": "an unknown or invalid",
|
|
145
164
|
"anUntrustedRootCert": "an untrusted root",
|
|
146
165
|
"suggestedSystemNameClient": ", client {{client}}",
|
|
147
|
-
"seeLogForDetails": "See log for more details."
|
|
166
|
+
"seeLogForDetails": "See log for more details.",
|
|
167
|
+
"forUserName": "(for user [{{username}}])"
|
|
148
168
|
},
|
|
149
169
|
"guidedAnswers": {
|
|
150
170
|
"validationErrorHelpText": "Need help with this error?"
|
package/dist/types.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { CommonPromptOptions, YUIQuestion } from '@sap-ux/inquirer-common';
|
|
|
4
4
|
import type { OdataVersion } from '@sap-ux/odata-service-writer';
|
|
5
5
|
import type { CdsVersionInfo } from '@sap-ux/project-access';
|
|
6
6
|
import type { ListChoiceOptions } from 'inquirer';
|
|
7
|
-
import type { BackendSystem } from '
|
|
7
|
+
import type { BackendSystem } from '@sap-ux/store';
|
|
8
8
|
/**
|
|
9
9
|
* This file contains types that are exported by the module and are needed for consumers using the APIs `prompt` and `getPrompts`.
|
|
10
10
|
*/
|
|
@@ -17,7 +17,11 @@ export declare enum DatasourceType {
|
|
|
17
17
|
metadataFile = "metadataFile",
|
|
18
18
|
projectSpecificDestination = "projectSpecificDestination"
|
|
19
19
|
}
|
|
20
|
-
export
|
|
20
|
+
export declare const SapSystemTypes: {
|
|
21
|
+
readonly abapOnPrem: "abapOnPrem";
|
|
22
|
+
readonly abapOnBtp: "abapOnBtp";
|
|
23
|
+
};
|
|
24
|
+
export type SapSystemType = keyof typeof SapSystemTypes;
|
|
21
25
|
/**
|
|
22
26
|
* Answers returned by the OdataServiceInquirer prompt API.
|
|
23
27
|
* These values may be used to write an OData service and may be derived from the user's input rather than direct answers.
|
|
@@ -175,6 +179,12 @@ export type DatasourceTypePromptOptions = {
|
|
|
175
179
|
* Include the `projectSpecificDestination` option in the datasource type prompt
|
|
176
180
|
*/
|
|
177
181
|
includeProjectSpecificDest?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Limit the offered datasource types to the specified types. Note that if `default` is also provided and not included in the choices, the default will be ignored.
|
|
184
|
+
* If `includeNone` is set to true, the `none` option will always be included.
|
|
185
|
+
*
|
|
186
|
+
*/
|
|
187
|
+
choices?: DatasourceType[];
|
|
178
188
|
};
|
|
179
189
|
export type MetadataPromptOptions = {
|
|
180
190
|
/**
|
|
@@ -198,7 +208,7 @@ export type SystemNamePromptOptions = {
|
|
|
198
208
|
* This option allows the prompt to be excluded where later storage of the system with the provided name is not required.
|
|
199
209
|
* If this propmt is not included then a BackendSystem will not be returned for the connected system.
|
|
200
210
|
*/
|
|
201
|
-
|
|
211
|
+
hide?: boolean;
|
|
202
212
|
};
|
|
203
213
|
export type OdataServiceUrlPromptOptions = {
|
|
204
214
|
/**
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SAP_CLIENT_KEY = exports.hostEnvironment = exports.ValidationLink = exports.promptNames = exports.DatasourceType = void 0;
|
|
3
|
+
exports.SAP_CLIENT_KEY = exports.hostEnvironment = exports.ValidationLink = exports.promptNames = exports.SapSystemTypes = exports.DatasourceType = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* This file contains types that are exported by the module and are needed for consumers using the APIs `prompt` and `getPrompts`.
|
|
6
6
|
*/
|
|
@@ -14,6 +14,10 @@ var DatasourceType;
|
|
|
14
14
|
DatasourceType["metadataFile"] = "metadataFile";
|
|
15
15
|
DatasourceType["projectSpecificDestination"] = "projectSpecificDestination";
|
|
16
16
|
})(DatasourceType || (exports.DatasourceType = DatasourceType = {}));
|
|
17
|
+
exports.SapSystemTypes = {
|
|
18
|
+
abapOnPrem: 'abapOnPrem',
|
|
19
|
+
abapOnBtp: 'abapOnBtp'
|
|
20
|
+
};
|
|
17
21
|
/**
|
|
18
22
|
* Enumeration of prompt names used by OdataServiceInquirerPromptOptions
|
|
19
23
|
*/
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { TelemetryProperties, ToolsSuiteTelemetryClient } from '@sap-ux/telemetry';
|
|
2
2
|
import { PromptState } from './prompt-state';
|
|
3
3
|
import { OdataVersion } from '@sap-ux/odata-service-writer';
|
|
4
|
+
import { ODataVersion } from '@sap-ux/axios-extension';
|
|
5
|
+
import type { ListChoiceOptions } from 'inquirer';
|
|
4
6
|
/**
|
|
5
7
|
* Determine if the current prompting environment is cli or a hosted extension (app studio or vscode).
|
|
6
8
|
*
|
|
@@ -39,5 +41,20 @@ export declare function parseOdataVersion(metadata: string): OdataVersion;
|
|
|
39
41
|
* @returns the metadata string with URIs replaced with relative paths
|
|
40
42
|
*/
|
|
41
43
|
export declare function originToRelative(metadata: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Convert the odata version type from the prompt (odata-service-writer) type to the axios-extension type.
|
|
46
|
+
*
|
|
47
|
+
* @param odataVersion The odata version to convert
|
|
48
|
+
* @returns The converted odata version
|
|
49
|
+
*/
|
|
50
|
+
export declare function convertODataVersionType(odataVersion?: OdataVersion): ODataVersion | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Gets the default index for a list of items, used to default list prompts to the first item if only one item is available.
|
|
53
|
+
* If list is undefined or has more than one, returns undefined which will default to the 'please select' message.
|
|
54
|
+
*
|
|
55
|
+
* @param list the list of choices
|
|
56
|
+
* @returns the default index if only one item is available, otherwise undefined
|
|
57
|
+
*/
|
|
58
|
+
export declare function getDefaultChoiceIndex(list: ListChoiceOptions[]): number | undefined;
|
|
42
59
|
export { PromptState };
|
|
43
60
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/utils/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.PromptState = exports.originToRelative = exports.parseOdataVersion = exports.sendTelemetryEvent = exports.setTelemetryClient = exports.getHostEnvironment = void 0;
|
|
6
|
+
exports.PromptState = exports.getDefaultChoiceIndex = exports.convertODataVersionType = exports.originToRelative = exports.parseOdataVersion = exports.sendTelemetryEvent = exports.setTelemetryClient = exports.getHostEnvironment = void 0;
|
|
7
7
|
const btp_utils_1 = require("@sap-ux/btp-utils");
|
|
8
8
|
const telemetry_1 = require("@sap-ux/telemetry");
|
|
9
9
|
const os_name_1 = __importDefault(require("os-name"));
|
|
@@ -14,6 +14,7 @@ const fast_xml_parser_1 = require("fast-xml-parser");
|
|
|
14
14
|
const odata_service_writer_1 = require("@sap-ux/odata-service-writer");
|
|
15
15
|
const logger_helper_1 = __importDefault(require("../prompts/logger-helper"));
|
|
16
16
|
const i18n_1 = require("../i18n");
|
|
17
|
+
const axios_extension_1 = require("@sap-ux/axios-extension");
|
|
17
18
|
const osVersionName = (0, os_name_1.default)();
|
|
18
19
|
/**
|
|
19
20
|
* Determine if the current prompting environment is cli or a hosted extension (app studio or vscode).
|
|
@@ -117,4 +118,31 @@ function originToRelative(metadata) {
|
|
|
117
118
|
(match, ...patterns) => `${patterns[0]}./${patterns[4]}`);
|
|
118
119
|
}
|
|
119
120
|
exports.originToRelative = originToRelative;
|
|
121
|
+
/**
|
|
122
|
+
* Convert the odata version type from the prompt (odata-service-writer) type to the axios-extension type.
|
|
123
|
+
*
|
|
124
|
+
* @param odataVersion The odata version to convert
|
|
125
|
+
* @returns The converted odata version
|
|
126
|
+
*/
|
|
127
|
+
function convertODataVersionType(odataVersion) {
|
|
128
|
+
if (!odataVersion) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
return odataVersion === odata_service_writer_1.OdataVersion.v2 ? axios_extension_1.ODataVersion.v2 : axios_extension_1.ODataVersion.v4;
|
|
132
|
+
}
|
|
133
|
+
exports.convertODataVersionType = convertODataVersionType;
|
|
134
|
+
/**
|
|
135
|
+
* Gets the default index for a list of items, used to default list prompts to the first item if only one item is available.
|
|
136
|
+
* If list is undefined or has more than one, returns undefined which will default to the 'please select' message.
|
|
137
|
+
*
|
|
138
|
+
* @param list the list of choices
|
|
139
|
+
* @returns the default index if only one item is available, otherwise undefined
|
|
140
|
+
*/
|
|
141
|
+
function getDefaultChoiceIndex(list) {
|
|
142
|
+
if (list?.length === 1) {
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
exports.getDefaultChoiceIndex = getDefaultChoiceIndex;
|
|
120
148
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap-ux/odata-service-inquirer",
|
|
3
3
|
"description": "Prompts module that can prompt users for inputs required for odata service writing",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.30",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/SAP/open-ux-tools.git",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"!dist/**/*.map"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"@sap/cf-tools": "3.2.0",
|
|
22
23
|
"axios": "1.7.4",
|
|
23
24
|
"axios-logger": "2.8.0",
|
|
24
25
|
"fast-xml-parser": "4.4.1",
|