toon-formatter 2.0.0 → 2.1.1

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.
@@ -0,0 +1,122 @@
1
+ /**
2
+ * CSV <-> XML Converter (for XmlConverter)
3
+ */
4
+
5
+ import { extractCsvFromString, extractJsonFromString, extractXmlFromString } from '../utils.js';
6
+ import { csvToJsonSync, jsonToCsvSync } from '../json_formatter/csv.js';
7
+ import { jsonToXmlSync, xmlToJsonSync } from '../json_formatter/xml.js';
8
+
9
+ /**
10
+ * Convert CSV string to XML string (Sync)
11
+ * Supports mixed text CSV.
12
+ * @param {string} csvString
13
+ * @returns {string} XML string
14
+ */
15
+ export function csvToXmlSync(csvString) {
16
+ if (!csvString || typeof csvString !== 'string') {
17
+ throw new Error('Input must be a non-empty string');
18
+ }
19
+
20
+ let convertedText = csvString;
21
+ let iterationCount = 0;
22
+ const maxIterations = 100;
23
+ let wasModified = false;
24
+
25
+ // Check pure CSV
26
+ const firstExtract = extractCsvFromString(csvString);
27
+ if (firstExtract === csvString.trim()) {
28
+ const json = csvToJsonSync(csvString);
29
+ return jsonToXmlSync(json);
30
+ }
31
+
32
+ // Mixed Loop
33
+ while (iterationCount < maxIterations) {
34
+ const csvBlock = extractCsvFromString(convertedText);
35
+ if (!csvBlock) break;
36
+
37
+ try {
38
+ const jsonObject = csvToJsonSync(csvBlock);
39
+ const xmlOutput = jsonToXmlSync(jsonObject);
40
+ convertedText = convertedText.replace(csvBlock, xmlOutput);
41
+ wasModified = true;
42
+ iterationCount++;
43
+ } catch (e) {
44
+ break;
45
+ }
46
+ }
47
+
48
+ if (wasModified) return convertedText;
49
+
50
+ try {
51
+ const json = csvToJsonSync(csvString);
52
+ return jsonToXmlSync(json);
53
+ } catch (e) {
54
+ return csvString;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Convert CSV string to XML string (Async)
60
+ * @param {string} csvString
61
+ * @returns {Promise<string>} XML string
62
+ */
63
+ export async function csvToXml(csvString) {
64
+ return csvToXmlSync(csvString);
65
+ }
66
+
67
+ /**
68
+ * Convert XML string to CSV string (Sync)
69
+ * Supports mixed text XML.
70
+ * @param {string} xmlString
71
+ * @returns {string} CSV string
72
+ */
73
+ export function xmlToCsvSync(xmlString) {
74
+ if (!xmlString || typeof xmlString !== 'string') {
75
+ throw new Error('Input must be a non-empty string');
76
+ }
77
+
78
+ let convertedText = xmlString;
79
+ let iterationCount = 0;
80
+ const maxIterations = 100;
81
+ let wasModified = false;
82
+
83
+ // Check pure XML
84
+ const firstExtract = extractXmlFromString(xmlString);
85
+ if (firstExtract === xmlString.trim()) {
86
+ const json = xmlToJsonSync(xmlString);
87
+ return jsonToCsvSync(json);
88
+ }
89
+
90
+ while (iterationCount < maxIterations) {
91
+ const xmlBlock = extractXmlFromString(convertedText);
92
+ if (!xmlBlock) break;
93
+
94
+ try {
95
+ const jsonObject = xmlToJsonSync(xmlBlock);
96
+ const csvOutput = jsonToCsvSync(jsonObject);
97
+ convertedText = convertedText.replace(xmlBlock, csvOutput);
98
+ wasModified = true;
99
+ iterationCount++;
100
+ } catch (e) {
101
+ break;
102
+ }
103
+ }
104
+
105
+ if (wasModified) return convertedText;
106
+
107
+ try {
108
+ const json = xmlToJsonSync(xmlString);
109
+ return jsonToCsvSync(json);
110
+ } catch (e) {
111
+ return xmlString;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Convert XML string to CSV string (Async)
117
+ * @param {string} xmlString
118
+ * @returns {Promise<string>} CSV string
119
+ */
120
+ export async function xmlToCsv(xmlString) {
121
+ return xmlToCsvSync(xmlString);
122
+ }
@@ -0,0 +1,488 @@
1
+ /**
2
+ * XmlConverter Class
3
+ */
4
+
5
+ import { toonToXml, toonToXmlSync, xmlToToon, xmlToToonSync } from '../xml.js';
6
+ import { jsonToXml, jsonToXmlSync, xmlToJson, xmlToJsonSync } from '../json_formatter/xml.js';
7
+ import { yamlToXml, yamlToXmlSync, xmlToYaml, xmlToYamlSync } from '../yaml_formatter/xml.js';
8
+ import { csvToXml, csvToXmlSync, xmlToCsv, xmlToCsvSync } from './csv.js';
9
+ import { validateXmlString, validateXmlStringSync } from './validator.js';
10
+
11
+ export class XmlConverter {
12
+ /**
13
+ * Creates an XmlConverter instance
14
+ * @param {Object} [encryptor=null] - Optional Encryptor instance for encryption support
15
+ */
16
+ constructor(encryptor = null) {
17
+ this.encryptor = encryptor;
18
+ }
19
+
20
+ // --- Helper Methods for Encryption ---
21
+
22
+ /**
23
+ * Applies encryption logic based on conversion mode (synchronous)
24
+ * @private
25
+ * @param {Function} fn - The converter function to call
26
+ * @param {*} data - Data to convert
27
+ * @param {string} mode - Conversion mode: 'no_encryption', 'middleware', 'ingestion', 'export'
28
+ * @returns {*} Converted (and possibly encrypted) data
29
+ */
30
+ _convertWithEncryption(fn, data, mode) {
31
+ if (!this.encryptor || mode === 'no_encryption') {
32
+ return fn(data);
33
+ }
34
+
35
+ switch (mode) {
36
+ case 'middleware':
37
+ const decrypted = this.encryptor.decrypt(data);
38
+ const result = fn(decrypted);
39
+ return this.encryptor.encrypt(result);
40
+ case 'ingestion':
41
+ const dec = this.encryptor.decrypt(data);
42
+ return fn(dec);
43
+ case 'export':
44
+ const res = fn(data);
45
+ return this.encryptor.encrypt(res);
46
+ default:
47
+ return fn(data);
48
+ }
49
+ }
50
+
51
+ async _convertWithEncryptionAsync(fn, data, mode) {
52
+ if (!this.encryptor || mode === 'no_encryption') {
53
+ return await fn(data);
54
+ }
55
+
56
+ switch (mode) {
57
+ case 'middleware':
58
+ const decrypted = this.encryptor.decrypt(data);
59
+ const result = await fn(decrypted);
60
+ return this.encryptor.encrypt(result);
61
+ case 'ingestion':
62
+ const dec = this.encryptor.decrypt(data);
63
+ return await fn(dec);
64
+ case 'export':
65
+ const res = await fn(data);
66
+ return this.encryptor.encrypt(res);
67
+ default:
68
+ return await fn(data);
69
+ }
70
+ }
71
+
72
+ // --- TOON Conversions ---
73
+
74
+ /**
75
+ * Convert TOON string to XML (Sync)
76
+ * @param {string} toonString - TOON formatted string
77
+ * @param {Object} [options={}] - Conversion options
78
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
79
+ * @returns {string} XML formatted string
80
+ */
81
+ fromToon(toonString, options = {}) {
82
+ const { conversionMode = 'no_encryption' } = options;
83
+ return this._convertWithEncryption(
84
+ (data) => toonToXmlSync(data),
85
+ toonString,
86
+ conversionMode
87
+ );
88
+ }
89
+
90
+ /**
91
+ * Convert TOON string to XML (Async)
92
+ * @param {string} toonString - TOON formatted string
93
+ * @param {Object} [options={}] - Conversion options
94
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
95
+ * @returns {Promise<string>} XML formatted string
96
+ */
97
+ async fromToonAsync(toonString, options = {}) {
98
+ const { conversionMode = 'no_encryption' } = options;
99
+ return this._convertWithEncryptionAsync(
100
+ async (data) => toonToXml(data),
101
+ toonString,
102
+ conversionMode
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Convert XML to TOON string (Sync)
108
+ * @param {string} xmlString - XML formatted string (supports mixed text)
109
+ * @param {Object} [options={}] - Conversion options
110
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
111
+ * @returns {string} TOON formatted string
112
+ */
113
+ toToon(xmlString, options = {}) {
114
+ const { conversionMode = 'no_encryption' } = options;
115
+ return this._convertWithEncryption(
116
+ (data) => xmlToToonSync(data),
117
+ xmlString,
118
+ conversionMode
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Convert XML to TOON string (Async)
124
+ * @param {string} xmlString - XML formatted string (supports mixed text)
125
+ * @param {Object} [options={}] - Conversion options
126
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
127
+ * @returns {Promise<string>} TOON formatted string
128
+ */
129
+ async toToonAsync(xmlString, options = {}) {
130
+ const { conversionMode = 'no_encryption' } = options;
131
+ return this._convertWithEncryptionAsync(
132
+ async (data) => xmlToToon(data),
133
+ xmlString,
134
+ conversionMode
135
+ );
136
+ }
137
+
138
+ // --- JSON Conversions ---
139
+
140
+ /**
141
+ * Convert JSON to XML (Sync)
142
+ * @param {Object|string} jsonData - JSON data or string with embedded JSON
143
+ * @param {Object} [options={}] - Conversion options
144
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
145
+ * @returns {string} XML formatted string
146
+ */
147
+ fromJson(jsonData, options = {}) {
148
+ const { conversionMode = 'no_encryption' } = options;
149
+ return this._convertWithEncryption(
150
+ (data) => jsonToXmlSync(data),
151
+ jsonData,
152
+ conversionMode
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Convert JSON to XML (Async)
158
+ * @param {Object|string} jsonData - JSON data or string with embedded JSON
159
+ * @param {Object} [options={}] - Conversion options
160
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
161
+ * @returns {Promise<string>} XML formatted string
162
+ */
163
+ async fromJsonAsync(jsonData, options = {}) {
164
+ const { conversionMode = 'no_encryption' } = options;
165
+ return this._convertWithEncryptionAsync(
166
+ async (data) => jsonToXml(data),
167
+ jsonData,
168
+ conversionMode
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Convert XML to JSON (Sync)
174
+ * @param {string} xmlString - XML formatted string (supports mixed text)
175
+ * @param {Object} [options={}] - Conversion options
176
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
177
+ * @returns {Object|string} JSON result
178
+ */
179
+ toJson(xmlString, options = {}) {
180
+ const { conversionMode = 'no_encryption' } = options;
181
+ return this._convertWithEncryption(
182
+ (data) => xmlToJsonSync(data),
183
+ xmlString,
184
+ conversionMode
185
+ );
186
+ }
187
+
188
+ /**
189
+ * Convert XML to JSON (Async)
190
+ * @param {string} xmlString - XML formatted string (supports mixed text)
191
+ * @param {Object} [options={}] - Conversion options
192
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
193
+ * @returns {Promise<Object|string>} JSON result
194
+ */
195
+ async toJsonAsync(xmlString, options = {}) {
196
+ const { conversionMode = 'no_encryption' } = options;
197
+ return this._convertWithEncryptionAsync(
198
+ async (data) => xmlToJson(data),
199
+ xmlString,
200
+ conversionMode
201
+ );
202
+ }
203
+
204
+ // --- YAML Conversions ---
205
+
206
+ /**
207
+ * Convert YAML to XML (Sync)
208
+ * @param {string} yamlString - YAML formatted string
209
+ * @param {Object} [options={}] - Conversion options
210
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
211
+ * @returns {string} XML formatted string
212
+ */
213
+ fromYaml(yamlString, options = {}) {
214
+ const { conversionMode = 'no_encryption' } = options;
215
+ return this._convertWithEncryption(
216
+ (data) => yamlToXmlSync(data),
217
+ yamlString,
218
+ conversionMode
219
+ );
220
+ }
221
+
222
+ async fromYamlAsync(yamlString, options = {}) {
223
+ const { conversionMode = 'no_encryption' } = options;
224
+ return this._convertWithEncryptionAsync(
225
+ async (data) => yamlToXml(data),
226
+ yamlString,
227
+ conversionMode
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Convert XML to YAML (Sync)
233
+ * @param {string} xmlString - XML formatted string (supports mixed text)
234
+ * @param {Object} [options={}] - Conversion options
235
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
236
+ * @returns {string} YAML formatted string
237
+ */
238
+ toYaml(xmlString, options = {}) {
239
+ const { conversionMode = 'no_encryption' } = options;
240
+ return this._convertWithEncryption(
241
+ (data) => xmlToYamlSync(data),
242
+ xmlString,
243
+ conversionMode
244
+ );
245
+ }
246
+
247
+ async toYamlAsync(xmlString, options = {}) {
248
+ const { conversionMode = 'no_encryption' } = options;
249
+ return this._convertWithEncryptionAsync(
250
+ async (data) => xmlToYaml(data),
251
+ xmlString,
252
+ conversionMode
253
+ );
254
+ }
255
+
256
+ // --- CSV Conversions ---
257
+
258
+ /**
259
+ * Convert CSV to XML (Sync)
260
+ * @param {string} csvString - CSV formatted string (supports mixed text)
261
+ * @param {Object} [options={}] - Conversion options
262
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
263
+ * @returns {string} XML formatted string
264
+ */
265
+ fromCsv(csvString, options = {}) {
266
+ const { conversionMode = 'no_encryption' } = options;
267
+ return this._convertWithEncryption(
268
+ (data) => csvToXmlSync(data),
269
+ csvString,
270
+ conversionMode
271
+ );
272
+ }
273
+
274
+ async fromCsvAsync(csvString, options = {}) {
275
+ const { conversionMode = 'no_encryption' } = options;
276
+ return this._convertWithEncryptionAsync(
277
+ async (data) => csvToXml(data),
278
+ csvString,
279
+ conversionMode
280
+ );
281
+ }
282
+
283
+ /**
284
+ * Convert XML to CSV (Sync)
285
+ * @param {string} xmlString - XML formatted string (supports mixed text)
286
+ * @param {Object} [options={}] - Conversion options
287
+ * @param {string} [options.conversionMode='no_encryption'] - Encryption mode
288
+ * @returns {string} CSV formatted string
289
+ */
290
+ toCsv(xmlString, options = {}) {
291
+ const { conversionMode = 'no_encryption' } = options;
292
+ return this._convertWithEncryption(
293
+ (data) => xmlToCsvSync(data),
294
+ xmlString,
295
+ conversionMode
296
+ );
297
+ }
298
+
299
+ async toCsvAsync(xmlString, options = {}) {
300
+ const { conversionMode = 'no_encryption' } = options;
301
+ return this._convertWithEncryptionAsync(
302
+ async (data) => xmlToCsv(data),
303
+ xmlString,
304
+ conversionMode
305
+ );
306
+ }
307
+
308
+ // --- Validation ---
309
+
310
+ /**
311
+ * Validate XML string (Sync)
312
+ * @param {string} xmlString - XML string to validate
313
+ * @returns {boolean} True if valid
314
+ */
315
+ validate(xmlString) {
316
+ return validateXmlStringSync(xmlString);
317
+ }
318
+
319
+ async validateAsync(xmlString) {
320
+ return validateXmlString(xmlString);
321
+ }
322
+
323
+ // ========================================
324
+ // Static Methods (Backward Compatibility)
325
+ // ========================================
326
+
327
+ /**
328
+ * Convert TOON string to XML (Sync)
329
+ * @param {string} toonString - TOON formatted string
330
+ * @returns {string} XML formatted string
331
+ */
332
+ static fromToon(toonString) {
333
+ return toonToXmlSync(toonString);
334
+ }
335
+
336
+ /**
337
+ * Convert TOON string to XML (Async)
338
+ * @param {string} toonString - TOON formatted string
339
+ * @returns {Promise<string>} XML formatted string
340
+ */
341
+ static async fromToonAsync(toonString) {
342
+ return toonToXml(toonString);
343
+ }
344
+
345
+ /**
346
+ * Convert XML to TOON string (Sync)
347
+ * @param {string} xmlString - XML formatted string
348
+ * @returns {string} TOON formatted string
349
+ */
350
+ static toToon(xmlString) {
351
+ return xmlToToonSync(xmlString);
352
+ }
353
+
354
+ /**
355
+ * Convert XML to TOON string (Async)
356
+ * @param {string} xmlString - XML formatted string
357
+ * @returns {Promise<string>} TOON formatted string
358
+ */
359
+ static async toToonAsync(xmlString) {
360
+ return xmlToToon(xmlString);
361
+ }
362
+
363
+ /**
364
+ * Convert JSON to XML string (Sync)
365
+ * @param {Object|string} jsonData - JSON data or string with embedded JSON
366
+ * @returns {string} XML formatted string
367
+ */
368
+ static fromJson(jsonData) {
369
+ return jsonToXmlSync(jsonData);
370
+ }
371
+
372
+ /**
373
+ * Convert JSON to XML string (Async)
374
+ * @param {Object|string} jsonData - JSON data or string with embedded JSON
375
+ * @returns {Promise<string>} XML formatted string
376
+ */
377
+ static async fromJsonAsync(jsonData) {
378
+ return jsonToXml(jsonData);
379
+ }
380
+
381
+ /**
382
+ * Convert XML to JSON (Sync)
383
+ * @param {string} xmlString - XML formatted string
384
+ * @returns {Object|string} JSON result
385
+ */
386
+ static toJson(xmlString) {
387
+ return xmlToJsonSync(xmlString);
388
+ }
389
+
390
+ /**
391
+ * Convert XML to JSON (Async)
392
+ * @param {string} xmlString - XML formatted string
393
+ * @returns {Promise<Object|string>} JSON result
394
+ */
395
+ static async toJsonAsync(xmlString) {
396
+ return xmlToJson(xmlString);
397
+ }
398
+
399
+ /**
400
+ * Convert YAML to XML string (Sync)
401
+ * @param {string} yamlString - YAML formatted string
402
+ * @returns {string} XML formatted string
403
+ */
404
+ static fromYaml(yamlString) {
405
+ return yamlToXmlSync(yamlString);
406
+ }
407
+
408
+ /**
409
+ * Convert YAML to XML string (Async)
410
+ * @param {string} yamlString - YAML formatted string
411
+ * @returns {Promise<string>} XML formatted string
412
+ */
413
+ static async fromYamlAsync(yamlString) {
414
+ return yamlToXml(yamlString);
415
+ }
416
+
417
+ /**
418
+ * Convert XML to YAML string (Sync)
419
+ * @param {string} xmlString - XML formatted string
420
+ * @returns {string} YAML formatted string
421
+ */
422
+ static toYaml(xmlString) {
423
+ return xmlToYamlSync(xmlString);
424
+ }
425
+
426
+ /**
427
+ * Convert XML to YAML string (Async)
428
+ * @param {string} xmlString - XML formatted string
429
+ * @returns {Promise<string>} YAML formatted string
430
+ */
431
+ static async toYamlAsync(xmlString) {
432
+ return xmlToYaml(xmlString);
433
+ }
434
+
435
+ /**
436
+ * Convert CSV to XML string (Sync)
437
+ * @param {string} csvString - CSV formatted string
438
+ * @returns {string} XML formatted string
439
+ */
440
+ static fromCsv(csvString) {
441
+ return csvToXmlSync(csvString);
442
+ }
443
+
444
+ /**
445
+ * Convert CSV to XML string (Async)
446
+ * @param {string} csvString - CSV formatted string
447
+ * @returns {Promise<string>} XML formatted string
448
+ */
449
+ static async fromCsvAsync(csvString) {
450
+ return csvToXml(csvString);
451
+ }
452
+
453
+ /**
454
+ * Convert XML to CSV string (Sync)
455
+ * @param {string} xmlString - XML formatted string
456
+ * @returns {string} CSV formatted string
457
+ */
458
+ static toCsv(xmlString) {
459
+ return xmlToCsvSync(xmlString);
460
+ }
461
+
462
+ /**
463
+ * Convert XML to CSV string (Async)
464
+ * @param {string} xmlString - XML formatted string
465
+ * @returns {Promise<string>} CSV formatted string
466
+ */
467
+ static async toCsvAsync(xmlString) {
468
+ return xmlToCsv(xmlString);
469
+ }
470
+
471
+ /**
472
+ * Validate XML string
473
+ * @param {string} xmlString - XML string to validate
474
+ * @returns {boolean} True if valid
475
+ */
476
+ static validate(xmlString) {
477
+ return validateXmlStringSync(xmlString);
478
+ }
479
+
480
+ /**
481
+ * Validate XML string (Async)
482
+ * @param {string} xmlString - XML string to validate
483
+ * @returns {Promise<boolean>} True if valid
484
+ */
485
+ static async validateAsync(xmlString) {
486
+ return validateXmlString(xmlString);
487
+ }
488
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * XML Validator (for XmlConverter)
3
+ */
4
+
5
+ import { encodeXmlReservedChars } from '../utils.js';
6
+
7
+ /**
8
+ * Validate XML string (Sync)
9
+ * @param {string} xmlString
10
+ * @returns {boolean} True if valid, throws error if invalid
11
+ */
12
+ export function validateXmlStringSync(xmlString) {
13
+ if (typeof xmlString !== 'string') {
14
+ throw new Error("Input must be a string.");
15
+ }
16
+
17
+ let Parser;
18
+ if (typeof DOMParser !== 'undefined') {
19
+ Parser = DOMParser;
20
+ } else {
21
+ throw new Error('DOMParser is not available for validation.');
22
+ }
23
+
24
+ const parser = new Parser();
25
+ const xmlDoc = parser.parseFromString(
26
+ encodeXmlReservedChars(xmlString),
27
+ 'application/xml'
28
+ );
29
+
30
+ const parserError = xmlDoc.querySelector ? xmlDoc.querySelector('parsererror') :
31
+ (xmlDoc.documentElement && xmlDoc.documentElement.nodeName === 'parsererror' ? xmlDoc.documentElement : null);
32
+
33
+ if (parserError) {
34
+ throw new Error(`Invalid XML: ${parserError.textContent}`);
35
+ }
36
+
37
+ return true;
38
+ }
39
+
40
+ /**
41
+ * Validate XML string (Async)
42
+ * @param {string} xmlString
43
+ * @returns {Promise<boolean>} True if valid
44
+ */
45
+ export async function validateXmlString(xmlString) {
46
+ if (typeof DOMParser === 'undefined') {
47
+ try {
48
+ const { DOMParser: NodeDOMParser } = await import('xmldom');
49
+ global.DOMParser = NodeDOMParser;
50
+ } catch (e) { }
51
+ }
52
+ return validateXmlStringSync(xmlString);
53
+ }