toon-formatter 2.0.1 → 2.2.0
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/CHANGELOG.md +39 -1
- package/README.md +211 -0
- package/bin/toon-formatter.js +3 -0
- package/package.json +17 -7
- package/src/cli.js +271 -0
- package/src/csv.js +19 -50
- package/src/csv_formatter/index.js +496 -0
- package/src/csv_formatter/validator.js +36 -0
- package/src/index.js +9 -1
- package/src/json.js +117 -67
- package/src/json_formatter/csv.js +145 -0
- package/src/json_formatter/index.js +525 -0
- package/src/json_formatter/validator.js +29 -0
- package/src/json_formatter/xml.js +206 -0
- package/src/json_formatter/yaml.js +81 -0
- package/src/utils.js +262 -64
- package/src/xml.js +24 -79
- package/src/xml_formatter/csv.js +122 -0
- package/src/xml_formatter/index.js +488 -0
- package/src/xml_formatter/validator.js +53 -0
- package/src/yaml_formatter/csv.js +101 -0
- package/src/yaml_formatter/index.js +542 -0
- package/src/yaml_formatter/validator.js +31 -0
- package/src/yaml_formatter/xml.js +116 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.1] - 2025-12-18
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **🔄 Unified Format Converters**
|
|
12
|
+
- New classes: `JsonConverter`, `YamlConverter`, `XmlConverter`, and `CsvConverter`
|
|
13
|
+
- Direct translation between formats (e.g., XML ↔ JSON, CSV ↔ YAML)
|
|
14
|
+
- Full encryption middleware support for all unified converters
|
|
15
|
+
- Static and Instance API parity across all converters
|
|
16
|
+
- **📝 Enhanced Mixed-Text Support**
|
|
17
|
+
- Standardized mixed-text extraction for JSON, XML, and CSV
|
|
18
|
+
- Preserves surrounding text while converting embedded data blocks
|
|
19
|
+
- **📦 Improved Packaging**
|
|
20
|
+
- Specific exports for all converters in `package.json`
|
|
21
|
+
- Fixed Node.js XML support by moving `xmldom` to production dependencies
|
|
22
|
+
- **📚 Documentation Hub**
|
|
23
|
+
- Comprehensive README updates with Unified Converter examples
|
|
24
|
+
- New `toon-formatter.json` documentation for the web platform
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- Standardized `returnJson` default to `false` (returns objects/arrays) for consistency
|
|
28
|
+
- Refined internal conversion logic to better handle edge cases in mixed-text scenarios
|
|
29
|
+
- Improved package keywords and description for better SEO
|
|
30
|
+
|
|
8
31
|
## [2.0.0] - 2025-12-08
|
|
9
32
|
|
|
10
33
|
### Added
|
|
@@ -65,6 +88,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
65
88
|
|
|
66
89
|
## Migration Guide
|
|
67
90
|
|
|
91
|
+
### From v2.0 to v2.1
|
|
92
|
+
|
|
93
|
+
**To use Unified Converters:**
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
import { JsonConverter, XmlConverter } from 'toon-formatter';
|
|
97
|
+
|
|
98
|
+
// Direct format-to-format
|
|
99
|
+
const xml = JsonConverter.toXml({ name: 'Alice' });
|
|
100
|
+
|
|
101
|
+
// With encryption
|
|
102
|
+
const converter = new JsonConverter(encryptor);
|
|
103
|
+
const encryptedXml = converter.toXml({ name: 'Alice' }, { conversionMode: 'export' });
|
|
104
|
+
```
|
|
105
|
+
|
|
68
106
|
### From v1.x to v2.0
|
|
69
107
|
|
|
70
108
|
**No changes required!** Version 2.0 is fully backward compatible.
|
|
@@ -73,7 +111,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
73
111
|
|
|
74
112
|
```javascript
|
|
75
113
|
// Old code (still works)
|
|
76
|
-
import
|
|
114
|
+
import ToonConverter from 'toon-formatter';
|
|
77
115
|
const toon = ToonConverter.fromJson(data);
|
|
78
116
|
|
|
79
117
|
// New code (with encryption)
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# 🚀 TOON Converter
|
|
2
2
|
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://nodejs.org/en/download)
|
|
5
|
+
[](https://toonformatter.net/)
|
|
6
|
+
|
|
3
7
|
A lightweight library to convert between **TOON** (Token-Oriented Object Notation) and popular data formats (JSON, YAML, XML, CSV).
|
|
4
8
|
|
|
5
9
|
**Reduce your LLM token costs by up to 40%** using the TOON format!
|
|
@@ -55,6 +59,64 @@ users[3]{id,name,active}:
|
|
|
55
59
|
|
|
56
60
|
---
|
|
57
61
|
|
|
62
|
+
## 💻 CLI Utility
|
|
63
|
+
|
|
64
|
+
**NEW in v2.1.0**: TOON Formatter now includes a powerful CLI utility for fast data conversion directly from your terminal!
|
|
65
|
+
|
|
66
|
+
### Global Installation
|
|
67
|
+
To use the `toon-formatter` command anywhere:
|
|
68
|
+
```bash
|
|
69
|
+
npm install -g toon-formatter
|
|
70
|
+
```
|
|
71
|
+
Or run it instantly without installation using `npx`:
|
|
72
|
+
```bash
|
|
73
|
+
npx toon-formatter --help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Basic Usage
|
|
77
|
+
Convert files or piped data easily:
|
|
78
|
+
```bash
|
|
79
|
+
# Convert JSON file to TOON
|
|
80
|
+
toon-formatter --from json --to toon -i data.json -o data.toon
|
|
81
|
+
|
|
82
|
+
# Piping data (JSON -> TOON)
|
|
83
|
+
echo '{"name": "Alice"}' | toon-formatter --from json --to toon
|
|
84
|
+
|
|
85
|
+
# Convert XML to JSON (prettified by default)
|
|
86
|
+
cat profile.xml | toon-formatter --from xml --to json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Advanced Features
|
|
90
|
+
The CLI supports all library features, including validation and encryption:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Validate a TOON string
|
|
94
|
+
cat data.toon | toon-formatter --validate toon
|
|
95
|
+
|
|
96
|
+
# Encrypt data during conversion (XOR)
|
|
97
|
+
echo '{"secret": "data"}' | toon-formatter --from json --to toon --mode export --key "mykey" --algo xor
|
|
98
|
+
|
|
99
|
+
# Decrypt data (AES-256-GCM)
|
|
100
|
+
cat encrypted.txt | toon-formatter --from toon --to json --mode ingestion --key "your-32-byte-key" --algo aes-256-gcm
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### CLI Options
|
|
104
|
+
| Flag | Short | Description |
|
|
105
|
+
|------|-------|-------------|
|
|
106
|
+
| `--from` | `-f` | Input format (json, yaml, xml, csv, toon) |
|
|
107
|
+
| `--to` | `-t` | Output format (json, yaml, xml, csv, toon) |
|
|
108
|
+
| `--input` | `-i` | Input file path (defaults to stdin) |
|
|
109
|
+
| `--output` | `-o` | Output file path (defaults to stdout) |
|
|
110
|
+
| `--validate` | `-v` | Validate the input format and exit |
|
|
111
|
+
| `--mode` | `-m` | Encryption mode (middleware, ingestion, export) |
|
|
112
|
+
| `--key` | `-k` | Encryption key |
|
|
113
|
+
| `--algo` | `-a` | Encryption algorithm (aes-256-gcm, xor, base64) |
|
|
114
|
+
| `--async` | | Use asynchronous conversion mode |
|
|
115
|
+
| `--no-parse` | | Skip parsing of objects (returns raw strings) |
|
|
116
|
+
| `--help` | `-h` | Show help information |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
58
120
|
## 🚀 Quick Start
|
|
59
121
|
|
|
60
122
|
### Basic Usage (Synchronous)
|
|
@@ -1086,6 +1148,152 @@ ToonConverter.toJsonAsync(toonString, returnJson?)
|
|
|
1086
1148
|
|
|
1087
1149
|
---
|
|
1088
1150
|
|
|
1151
|
+
### Unified Format Converters (v2.0.0+)
|
|
1152
|
+
|
|
1153
|
+
The library now includes specialized, unified converters for each major format. These are perfect when you need to convert between non-TOON formats (like XML to JSON or CSV to YAML) while still having access to TOON and encryption features.
|
|
1154
|
+
|
|
1155
|
+
#### Available Unified Converters:
|
|
1156
|
+
- `JsonConverter`: Specialized in JSON input/output
|
|
1157
|
+
- `YamlConverter`: Specialized in YAML input/output
|
|
1158
|
+
- `XmlConverter`: Specialized in XML input/output
|
|
1159
|
+
- `CsvConverter`: Specialized in CSV input/output
|
|
1160
|
+
|
|
1161
|
+
#### Example: Cross-Format Conversion
|
|
1162
|
+
```javascript
|
|
1163
|
+
import { XmlConverter, YamlConverter } from 'toon-formatter';
|
|
1164
|
+
|
|
1165
|
+
// Convert XML directly to YAML
|
|
1166
|
+
const xmlData = '<user><name>Alice</name></user>';
|
|
1167
|
+
const yamlData = XmlConverter.toYaml(xmlData);
|
|
1168
|
+
|
|
1169
|
+
// Convert YAML directly to CSV
|
|
1170
|
+
const csvData = YamlConverter.toCsv("name: Alice\nrole: admin");
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
---
|
|
1174
|
+
|
|
1175
|
+
### JsonConverter Class
|
|
1176
|
+
|
|
1177
|
+
Specialized for JSON-centric workflows. It can convert JSON to any format and any format back to JSON.
|
|
1178
|
+
|
|
1179
|
+
#### Instance Methods (with Encryption)
|
|
1180
|
+
```javascript
|
|
1181
|
+
import { JsonConverter, Encryptor } from 'toon-formatter';
|
|
1182
|
+
|
|
1183
|
+
const converter = new JsonConverter(new Encryptor(key, 'aes-256-gcm'));
|
|
1184
|
+
|
|
1185
|
+
// JSON -> TOON (Encrypted)
|
|
1186
|
+
const encryptedToon = converter.toToon(data, { conversionMode: 'export' });
|
|
1187
|
+
|
|
1188
|
+
// XML -> JSON (Decrypted)
|
|
1189
|
+
const jsonData = converter.fromXml(encryptedXml, { conversionMode: 'ingestion' });
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
#### Static Methods (No Encryption)
|
|
1193
|
+
```javascript
|
|
1194
|
+
// Convert TOON to JSON object
|
|
1195
|
+
const obj = JsonConverter.fromToon(toonString);
|
|
1196
|
+
|
|
1197
|
+
// Convert TOON to JSON string
|
|
1198
|
+
const json = JsonConverter.fromToon(toonString, { returnJson: true });
|
|
1199
|
+
|
|
1200
|
+
// Convert JSON to XML
|
|
1201
|
+
const xml = JsonConverter.toXml({ name: "Alice" });
|
|
1202
|
+
```
|
|
1203
|
+
|
|
1204
|
+
**Available Methods:**
|
|
1205
|
+
- `fromToon(toonString, options?)` / `fromToonAsync(toonString, options?)`
|
|
1206
|
+
- `toToon(data, options?)` / `toToonAsync(data, options?)`
|
|
1207
|
+
- `fromYaml(yamlString, options?)` / `fromYamlAsync(yamlString, options?)`
|
|
1208
|
+
- `toYaml(data, options?)` / `toYamlAsync(data, options?)`
|
|
1209
|
+
- `fromXml(xmlString, options?)` / `fromXmlAsync(xmlString, options?)`
|
|
1210
|
+
- `toXml(data, options?)` / `toXmlAsync(data, options?)`
|
|
1211
|
+
- `fromCsv(csvString, options?)` / `fromCsvAsync(csvString, options?)`
|
|
1212
|
+
- `toCsv(data, options?)` / `toCsvAsync(data, options?)`
|
|
1213
|
+
|
|
1214
|
+
---
|
|
1215
|
+
|
|
1216
|
+
### YamlConverter Class
|
|
1217
|
+
|
|
1218
|
+
Specialized for YAML workflows.
|
|
1219
|
+
|
|
1220
|
+
#### Usage Example
|
|
1221
|
+
```javascript
|
|
1222
|
+
import { YamlConverter } from 'toon-formatter';
|
|
1223
|
+
|
|
1224
|
+
// YAML to TOON
|
|
1225
|
+
const toon = YamlConverter.fromToon(testToon);
|
|
1226
|
+
|
|
1227
|
+
// YAML to JSON
|
|
1228
|
+
const json = YamlConverter.toJson(yamlString, { returnJson: true });
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
**Available Methods:**
|
|
1232
|
+
- `fromToon(toonString, options?)` / `fromToonAsync(toonString, options?)`
|
|
1233
|
+
- `toToon(yamlString, options?)` / `toToonAsync(yamlString, options?)`
|
|
1234
|
+
- `fromJson(jsonData, options?)` / `fromJsonAsync(jsonData, options?)`
|
|
1235
|
+
- `toJson(yamlString, options?)` / `toJsonAsync(yamlString, options?)`
|
|
1236
|
+
- `fromXml(xmlString, options?)` / `fromXmlAsync(xmlString, options?)`
|
|
1237
|
+
- `toXml(yamlString, options?)` / `toXmlAsync(yamlString, options?)`
|
|
1238
|
+
- `fromCsv(csvString, options?)` / `fromCsvAsync(csvString, options?)`
|
|
1239
|
+
- `toCsv(yamlString, options?)` / `toCsvAsync(yamlString, options?)`
|
|
1240
|
+
|
|
1241
|
+
---
|
|
1242
|
+
|
|
1243
|
+
### XmlConverter Class
|
|
1244
|
+
|
|
1245
|
+
Specialized for XML workflows. Supports mixed-text extraction automatically.
|
|
1246
|
+
|
|
1247
|
+
#### Usage Example
|
|
1248
|
+
```javascript
|
|
1249
|
+
import { XmlConverter } from 'toon-formatter';
|
|
1250
|
+
|
|
1251
|
+
// XML to TOON
|
|
1252
|
+
const toon = XmlConverter.fromToon(xmlString);
|
|
1253
|
+
|
|
1254
|
+
// JSON to XML
|
|
1255
|
+
const xml = XmlConverter.fromJson(jsonData);
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
**Available Methods:**
|
|
1259
|
+
- `fromToon(toonString, options?)` / `fromToonAsync(toonString, options?)`
|
|
1260
|
+
- `toToon(xmlString, options?)` / `toToonAsync(xmlString, options?)`
|
|
1261
|
+
- `fromJson(jsonData, options?)` / `fromJsonAsync(jsonData, options?)`
|
|
1262
|
+
- `toJson(xmlString, options?)` / `toJsonAsync(xmlString, options?)`
|
|
1263
|
+
- `fromYaml(yamlString, options?)` / `fromYamlAsync(yamlString, options?)`
|
|
1264
|
+
- `toYaml(xmlString, options?)` / `toYamlAsync(xmlString, options?)`
|
|
1265
|
+
- `fromCsv(csvString, options?)` / `fromCsvAsync(csvString, options?)`
|
|
1266
|
+
- `toCsv(xmlString, options?)` / `toCsvAsync(xmlString, options?)`
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1270
|
+
### CsvConverter Class
|
|
1271
|
+
|
|
1272
|
+
Specialized for CSV workflows.
|
|
1273
|
+
|
|
1274
|
+
#### Usage Example
|
|
1275
|
+
```javascript
|
|
1276
|
+
import { CsvConverter } from 'toon-formatter';
|
|
1277
|
+
|
|
1278
|
+
// CSV to TOON
|
|
1279
|
+
const toon = CsvConverter.fromToon(csvString);
|
|
1280
|
+
|
|
1281
|
+
// JSON to CSV
|
|
1282
|
+
const csv = CsvConverter.fromJson(jsonData);
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
**Available Methods:**
|
|
1286
|
+
- `fromToon(toonString, options?)` / `fromToonAsync(toonString, options?)`
|
|
1287
|
+
- `toToon(csvString, options?)` / `toToonAsync(csvString, options?)`
|
|
1288
|
+
- `fromJson(jsonData, options?)` / `fromJsonAsync(jsonData, options?)`
|
|
1289
|
+
- `toJson(csvString, options?)` / `toJsonAsync(csvString, options?)`
|
|
1290
|
+
- `fromYaml(yamlString, options?)` / `fromYamlAsync(yamlString, options?)`
|
|
1291
|
+
- `toYaml(csvString, options?)` / `toYamlAsync(csvString, options?)`
|
|
1292
|
+
- `fromXml(xmlString, options?)` / `fromXmlAsync(xmlString, options?)`
|
|
1293
|
+
- `toXml(csvString, options?)` / `toXmlAsync(csvString, options?)`
|
|
1294
|
+
|
|
1295
|
+
---
|
|
1296
|
+
|
|
1089
1297
|
## 🎨 TOON Format Guide
|
|
1090
1298
|
|
|
1091
1299
|
### Primitives
|
|
@@ -1234,7 +1442,10 @@ fs.writeFileSync('config.yaml', improvedYaml);
|
|
|
1234
1442
|
|
|
1235
1443
|
## 🧪 Testing
|
|
1236
1444
|
|
|
1445
|
+
The library includes a comprehensive test suite with 150+ unit and integration tests.
|
|
1446
|
+
|
|
1237
1447
|
```bash
|
|
1448
|
+
# Run all tests (Unit, Integration, and CLI)
|
|
1238
1449
|
npm test
|
|
1239
1450
|
```
|
|
1240
1451
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toon-formatter",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"funding": {
|
|
5
5
|
"type": "github",
|
|
6
6
|
"url": "https://github.com/sponsors/ankitpal181"
|
|
7
7
|
},
|
|
8
|
-
"description": "A
|
|
8
|
+
"description": "A powerful library to convert between TOON, JSON, YAML, XML, and CSV with end-to-end encryption. Includes Unified Converters for direct format-to-format translation and LLM token optimization.",
|
|
9
9
|
"main": "src/index.js",
|
|
10
10
|
"type": "module",
|
|
11
|
+
"bin": {
|
|
12
|
+
"toon-formatter": "./bin/toon-formatter.js"
|
|
13
|
+
},
|
|
11
14
|
"scripts": {
|
|
12
15
|
"test": "node --test test/*.test.js",
|
|
13
16
|
"test:watch": "node --test --watch test/*.test.js"
|
|
@@ -30,7 +33,11 @@
|
|
|
30
33
|
"security",
|
|
31
34
|
"crypto",
|
|
32
35
|
"secure-data",
|
|
33
|
-
"end-to-end-encryption"
|
|
36
|
+
"end-to-end-encryption",
|
|
37
|
+
"unified-converter",
|
|
38
|
+
"json-to-xml",
|
|
39
|
+
"csv-to-yaml",
|
|
40
|
+
"xml-to-json"
|
|
34
41
|
],
|
|
35
42
|
"author": "Ankit Pal",
|
|
36
43
|
"license": "MIT",
|
|
@@ -47,11 +54,10 @@
|
|
|
47
54
|
},
|
|
48
55
|
"dependencies": {
|
|
49
56
|
"js-yaml": "^4.1.0",
|
|
50
|
-
"papaparse": "^5.4.1"
|
|
51
|
-
},
|
|
52
|
-
"devDependencies": {
|
|
57
|
+
"papaparse": "^5.4.1",
|
|
53
58
|
"xmldom": "^0.6.0"
|
|
54
59
|
},
|
|
60
|
+
"devDependencies": {},
|
|
55
61
|
"exports": {
|
|
56
62
|
".": "./src/index.js",
|
|
57
63
|
"./json": "./src/json.js",
|
|
@@ -60,6 +66,10 @@
|
|
|
60
66
|
"./csv": "./src/csv.js",
|
|
61
67
|
"./validator": "./src/validator.js",
|
|
62
68
|
"./utils": "./src/utils.js",
|
|
63
|
-
"./encryptor": "./src/encryptor.js"
|
|
69
|
+
"./encryptor": "./src/encryptor.js",
|
|
70
|
+
"./json-converter": "./src/json_formatter/index.js",
|
|
71
|
+
"./yaml-converter": "./src/yaml_formatter/index.js",
|
|
72
|
+
"./xml-converter": "./src/xml_formatter/index.js",
|
|
73
|
+
"./csv-converter": "./src/csv_formatter/index.js"
|
|
64
74
|
}
|
|
65
75
|
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import {
|
|
6
|
+
ToonConverter,
|
|
7
|
+
JsonConverter,
|
|
8
|
+
YamlConverter,
|
|
9
|
+
XmlConverter,
|
|
10
|
+
CsvConverter,
|
|
11
|
+
Encryptor
|
|
12
|
+
} from './index.js';
|
|
13
|
+
|
|
14
|
+
// Polyfill DOMParser for Node.js environments (required for XML conversion)
|
|
15
|
+
if (typeof DOMParser === 'undefined') {
|
|
16
|
+
try {
|
|
17
|
+
const { DOMParser: NodeDOMParser } = await import('xmldom');
|
|
18
|
+
global.DOMParser = NodeDOMParser;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
// xmldom might not be available or other import error
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function readStdin() {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
let data = '';
|
|
27
|
+
process.stdin.setEncoding('utf8');
|
|
28
|
+
process.stdin.on('readable', () => {
|
|
29
|
+
let chunk;
|
|
30
|
+
while ((chunk = process.stdin.read()) !== null) {
|
|
31
|
+
data += chunk;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
process.stdin.on('end', () => resolve(data));
|
|
35
|
+
process.stdin.on('error', reject);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const showHelp = () => {
|
|
40
|
+
console.log(`
|
|
41
|
+
TOON Formatter CLI - Convert between TOON, JSON, YAML, XML, and CSV.
|
|
42
|
+
|
|
43
|
+
Usage:
|
|
44
|
+
toon-formatter --from <format> --to <format> [options]
|
|
45
|
+
toon-formatter --validate <format> [options]
|
|
46
|
+
|
|
47
|
+
Options:
|
|
48
|
+
--from <format> Source format (json, yaml, xml, csv, toon)
|
|
49
|
+
--to <format> Target format (json, yaml, xml, csv, toon)
|
|
50
|
+
-i, --input <file> Input file path (default: stdin)
|
|
51
|
+
-o, --output <file> Output file path (default: stdout)
|
|
52
|
+
--async Use asynchronous converters
|
|
53
|
+
-m, --mode <mode> Conversion mode (no_encryption, middleware, ingestion, export)
|
|
54
|
+
-k, --key <key> Encryption key
|
|
55
|
+
-a, --algo <algo> Encryption algorithm (aes-256-gcm, xor, base64)
|
|
56
|
+
--no-parse Return raw strings for applicable conversions
|
|
57
|
+
--validate <format> Validate the given format
|
|
58
|
+
-h, --help Show this help message
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
echo '{"name": "Alice"}' | toon-formatter --from json --to toon
|
|
62
|
+
toon-formatter --from xml --to json -i data.xml -o data.json
|
|
63
|
+
toon-formatter --validate toon -i data.toon
|
|
64
|
+
`);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
function parseArgs(args) {
|
|
68
|
+
const config = {
|
|
69
|
+
from: null,
|
|
70
|
+
to: null,
|
|
71
|
+
input: null,
|
|
72
|
+
output: null,
|
|
73
|
+
isAsync: false,
|
|
74
|
+
mode: 'no_encryption',
|
|
75
|
+
key: null,
|
|
76
|
+
algo: 'aes-256-gcm',
|
|
77
|
+
noParse: false,
|
|
78
|
+
validate: null
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < args.length; i++) {
|
|
82
|
+
const arg = args[i];
|
|
83
|
+
switch (arg) {
|
|
84
|
+
case '--from':
|
|
85
|
+
config.from = args[++i];
|
|
86
|
+
break;
|
|
87
|
+
case '--to':
|
|
88
|
+
config.to = args[++i];
|
|
89
|
+
break;
|
|
90
|
+
case '-i':
|
|
91
|
+
case '--input':
|
|
92
|
+
config.input = args[++i];
|
|
93
|
+
break;
|
|
94
|
+
case '-o':
|
|
95
|
+
case '--output':
|
|
96
|
+
config.output = args[++i];
|
|
97
|
+
break;
|
|
98
|
+
case '--async':
|
|
99
|
+
config.isAsync = true;
|
|
100
|
+
break;
|
|
101
|
+
case '-m':
|
|
102
|
+
case '--mode':
|
|
103
|
+
config.mode = args[++i];
|
|
104
|
+
break;
|
|
105
|
+
case '-k':
|
|
106
|
+
case '--key':
|
|
107
|
+
config.key = args[++i];
|
|
108
|
+
break;
|
|
109
|
+
case '-a':
|
|
110
|
+
case '--algo':
|
|
111
|
+
config.algo = args[++i];
|
|
112
|
+
break;
|
|
113
|
+
case '--no-parse':
|
|
114
|
+
config.noParse = true;
|
|
115
|
+
break;
|
|
116
|
+
case '--validate':
|
|
117
|
+
config.validate = args[++i];
|
|
118
|
+
break;
|
|
119
|
+
case '-h':
|
|
120
|
+
case '--help':
|
|
121
|
+
showHelp();
|
|
122
|
+
process.exit(0);
|
|
123
|
+
default:
|
|
124
|
+
if (arg.startsWith('-')) {
|
|
125
|
+
console.error(`Unknown option: ${arg}`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return config;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function run() {
|
|
135
|
+
const args = process.argv.slice(2);
|
|
136
|
+
if (args.length === 0) {
|
|
137
|
+
showHelp();
|
|
138
|
+
process.exit(0);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const config = parseArgs(args);
|
|
142
|
+
|
|
143
|
+
if (!config.validate && (!config.from || !config.to)) {
|
|
144
|
+
console.error("Error: --from and --to are required unless using --validate");
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let inputData = '';
|
|
149
|
+
if (config.input) {
|
|
150
|
+
try {
|
|
151
|
+
inputData = fs.readFileSync(path.resolve(config.input), 'utf8');
|
|
152
|
+
} catch (err) {
|
|
153
|
+
console.error(`Error reading input file: ${err.message}`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
inputData = await readStdin();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!inputData && !config.validate) {
|
|
161
|
+
console.error("Error: No input data provided");
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let encryptor = null;
|
|
166
|
+
if (config.key || config.algo === 'base64') {
|
|
167
|
+
try {
|
|
168
|
+
encryptor = new Encryptor(config.key, config.algo);
|
|
169
|
+
} catch (err) {
|
|
170
|
+
console.error(`Error initializing encryptor: ${err.message}`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
let result;
|
|
177
|
+
if (config.validate) {
|
|
178
|
+
result = ToonConverter.validate(inputData);
|
|
179
|
+
if (config.output) {
|
|
180
|
+
fs.writeFileSync(path.resolve(config.output), JSON.stringify(result, null, 2));
|
|
181
|
+
} else {
|
|
182
|
+
console.log(JSON.stringify(result, null, 2));
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const options = {
|
|
188
|
+
conversionMode: config.mode,
|
|
189
|
+
returnJson: !config.noParse
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
result = await handleConversion(config, inputData, encryptor);
|
|
193
|
+
|
|
194
|
+
if (typeof result === 'object' && result !== null) {
|
|
195
|
+
result = JSON.stringify(result, null, 2);
|
|
196
|
+
} else if (typeof result === 'string' && config.to === 'json' && !config.noParse) {
|
|
197
|
+
try {
|
|
198
|
+
const parsed = JSON.parse(result);
|
|
199
|
+
result = JSON.stringify(parsed, null, 2);
|
|
200
|
+
} catch (e) {
|
|
201
|
+
// Not a valid JSON string, leave as is
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (config.output) {
|
|
206
|
+
fs.writeFileSync(path.resolve(config.output), result);
|
|
207
|
+
} else {
|
|
208
|
+
process.stdout.write(result + '\n');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
} catch (err) {
|
|
212
|
+
console.error(`Conversion error: ${err.message}`);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function handleConversion(config, data, encryptor) {
|
|
218
|
+
const { from, to, isAsync, mode, noParse } = config;
|
|
219
|
+
|
|
220
|
+
// Use instance if encryption is involved
|
|
221
|
+
const toonConv = new ToonConverter(encryptor);
|
|
222
|
+
const jsonConv = new JsonConverter(encryptor);
|
|
223
|
+
const yamlConv = new YamlConverter(encryptor);
|
|
224
|
+
const xmlConv = new XmlConverter(encryptor);
|
|
225
|
+
const csvConv = new CsvConverter(encryptor);
|
|
226
|
+
|
|
227
|
+
const options = { conversionMode: mode, returnJson: !noParse };
|
|
228
|
+
|
|
229
|
+
if (from === 'toon') {
|
|
230
|
+
if (to === 'json') return isAsync ? toonConv.toJsonAsync(data, options) : toonConv.toJson(data, options);
|
|
231
|
+
if (to === 'yaml') return isAsync ? toonConv.toYamlAsync(data, options) : toonConv.toYaml(data, options);
|
|
232
|
+
if (to === 'xml') return isAsync ? toonConv.toXmlAsync(data, options) : toonConv.toXml(data, options);
|
|
233
|
+
if (to === 'csv') return isAsync ? toonConv.toCsvAsync(data, options) : toonConv.toCsv(data, options);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (to === 'toon') {
|
|
237
|
+
if (from === 'json') return isAsync ? toonConv.fromJsonAsync(data, options) : toonConv.fromJson(data, options);
|
|
238
|
+
if (from === 'yaml') return isAsync ? toonConv.fromYamlAsync(data, options) : toonConv.fromYaml(data, options);
|
|
239
|
+
if (from === 'xml') return isAsync ? toonConv.fromXmlAsync(data, options) : toonConv.fromXml(data, options);
|
|
240
|
+
if (from === 'csv') return isAsync ? toonConv.fromCsvAsync(data, options) : toonConv.fromCsv(data, options);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Unified Converters for direct translation
|
|
244
|
+
if (from === 'json') {
|
|
245
|
+
if (to === 'xml') return isAsync ? jsonConv.toXmlAsync(data, options) : jsonConv.toXml(data, options);
|
|
246
|
+
if (to === 'csv') return isAsync ? jsonConv.toCsvAsync(data, options) : jsonConv.toCsv(data, options);
|
|
247
|
+
if (to === 'yaml') return isAsync ? jsonConv.toYamlAsync(data, options) : jsonConv.toYaml(data, options);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (from === 'yaml') {
|
|
251
|
+
if (to === 'json') return isAsync ? yamlConv.toJsonAsync(data, options) : yamlConv.toJson(data, options);
|
|
252
|
+
if (to === 'xml') return isAsync ? yamlConv.toXmlAsync(data, options) : yamlConv.toXml(data, options);
|
|
253
|
+
if (to === 'csv') return isAsync ? yamlConv.toCsvAsync(data, options) : yamlConv.toCsv(data, options);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (from === 'xml') {
|
|
257
|
+
if (to === 'json') return isAsync ? xmlConv.toJsonAsync(data, options) : xmlConv.toJson(data, options);
|
|
258
|
+
if (to === 'csv') return isAsync ? xmlConv.toCsvAsync(data, options) : xmlConv.toCsv(data, options);
|
|
259
|
+
if (to === 'yaml') return isAsync ? xmlConv.toYamlAsync(data, options) : xmlConv.toYaml(data, options);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (from === 'csv') {
|
|
263
|
+
if (to === 'json') return isAsync ? csvConv.toJsonAsync(data, options) : csvConv.toJson(data, options);
|
|
264
|
+
if (to === 'xml') return isAsync ? csvConv.toXmlAsync(data, options) : csvConv.toXml(data, options);
|
|
265
|
+
if (to === 'yaml') return isAsync ? csvConv.toYamlAsync(data, options) : csvConv.toYaml(data, options);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
throw new Error(`Unsupported conversion from ${from} to ${to}`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
run();
|