toon-formatter 1.1.1 → 2.0.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.
package/src/json.js CHANGED
@@ -120,10 +120,11 @@ export async function jsonToToon(data) {
120
120
  /**
121
121
  * Converts TOON to JSON format (Synchronous)
122
122
  * @param {string} toonString - TOON formatted string
123
- * @returns {Object} JSON object
123
+ * @param {boolean} [returnJson=false] - If true, returns JSON string; if false, returns object
124
+ * @returns {Object|string} JSON object or JSON string
124
125
  * @throws {Error} If TOON string is invalid
125
126
  */
126
- export function toonToJsonSync(toonString) {
127
+ export function toonToJsonSync(toonString, returnJson = false) {
127
128
  // Validate TOON string before conversion
128
129
  const validationStatus = validateToonStringSync(toonString);
129
130
  if (!validationStatus.isValid) {
@@ -136,7 +137,7 @@ export function toonToJsonSync(toonString) {
136
137
 
137
138
  // Pre-process: Check for Root Array or Root Primitive
138
139
  const firstLine = lines.find(l => l.trim() !== '');
139
- if (!firstLine) return {}; // Empty document
140
+ if (!firstLine) return returnJson ? '{}' : {}; // Empty document
140
141
 
141
142
  // Root Array detection: [N]... at start of line
142
143
  if (firstLine.trim().startsWith('[')) {
@@ -324,14 +325,15 @@ export function toonToJsonSync(toonString) {
324
325
  }
325
326
  }
326
327
 
327
- return root;
328
+ return returnJson ? JSON.stringify(root) : root;
328
329
  }
329
330
 
330
331
  /**
331
332
  * Converts TOON to JSON format (Async)
332
333
  * @param {string} toonString - TOON formatted string
333
- * @returns {Promise<Object>} Parsed JSON data
334
+ * @param {boolean} [returnJson=false] - If true, returns JSON string; if false, returns object
335
+ * @returns {Promise<Object|string>} Parsed JSON data (object or string)
334
336
  */
335
- export async function toonToJson(toonString) {
336
- return toonToJsonSync(toonString);
337
+ export async function toonToJson(toonString, returnJson = false) {
338
+ return toonToJsonSync(toonString, returnJson);
337
339
  }
@@ -1,15 +0,0 @@
1
- # These are supported funding model platforms
2
-
3
- github: [ankitpal181] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
- # patreon: # Replace with a single Patreon username
5
- # open_collective: # Replace with a single Open Collective username
6
- # ko_fi: # Replace with a single Ko-fi username
7
- # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
- # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
- # liberapay: # Replace with a single Liberapay username
10
- # issuehunt: # Replace with a single IssueHunt username
11
- # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12
- # polar: # Replace with a single Polar username
13
- # buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14
- # thanks_dev: # Replace with a single thanks.dev username
15
- # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
package/ENHANCEMENTS.md DELETED
@@ -1,124 +0,0 @@
1
- # TOON Converter Library - Enhancement Summary
2
-
3
- ## Overview
4
- Updated the `toon-converter-lib` package with improved validators, mixed text extraction capabilities, validation checks on reverse conversions, and loop-based conversion for embedded formats.
5
-
6
- ---
7
-
8
- ## ✨ New Features Added
9
-
10
- ### 1. **Enhanced Validator** (`src/validator.js`)
11
- - **Empty Block Detection**: Validates that arrays with size > 0 have actual items
12
- - **Tabular Array Support**: Properly handles tabular arrays with `{field1,field2}` syntax
13
- - **List Item Context Checking**: Ensures `-` items only appear in array contexts
14
- - **Better Error Messages**: Line numbers and specific error descriptions
15
-
16
- **Example Error**:
17
- ```
18
- L5: Array declared with size 3 but has no items (expected indented block).
19
- ```
20
-
21
- ---
22
-
23
- ### 2. **Format Extraction Functions** (`src/utils.js`)
24
- Added utilities to extract specific formats from mixed text:
25
-
26
- - `extractJsonFromString(text)` - Finds and extracts JSON objects/arrays
27
- - `extractYamlFromString(text)` - Extracts YAML blocks
28
- - `extractXmlFromString(text)` - Extracts XML elements with balance checking
29
- - `extractCsvFromString(text)` - Identifies CSV data
30
-
31
- **Use Case**: Allows conversion of mixed content (e.g., JSON embedded in markdown).
32
-
33
- ---
34
-
35
- ### 3. **Integrated Mixed Text Conversion**
36
- The conversion functions now automatically detect and handle mixed text input using an extraction loop. This logic covers both embedded data and full data strings.
37
-
38
- **Synchronous API (Main Logic)**:
39
- - `jsonToToonSync(input)`
40
- - `xmlToToonSync(input)`
41
- - `csvToToonSync(input)`
42
- - `yamlToToonSync(input)`
43
-
44
- **Asynchronous API (Wrappers)**:
45
- - `jsonToToon(input)`
46
- - `xmlToToon(input)`
47
- - `csvToToon(input)`
48
- - `yamlToToon(input)`
49
-
50
- **Behavior**:
51
- 1. Checks if input is a string.
52
- 2. Uses extraction logic (`extract*FromString`) in a loop to find and convert all data blocks.
53
- 3. If no blocks are found (and input is not valid data), it returns the original text (or throws if strict parsing fails inside the loop).
54
-
55
- **Note**: `*TextToToon` functions have been removed in favor of this integrated approach.
56
-
57
- ---
58
-
59
- ---
60
-
61
- ### 4. **Validation on Reverse Conversions**
62
- All `toonTo*` functions now validate TOON input before conversion:
63
-
64
- - `toonToJson()` - Validates before parsing
65
- - `toonToYaml()` - Validates before conversion
66
- - `toonToXml()` - Validates before conversion
67
- - `toonToCsv()` - Validates before conversion
68
-
69
- **Benefits**:
70
- - Early error detection
71
- - Clear error messages
72
- - Prevents invalid conversions
73
-
74
- ---
75
-
76
- ### 6. **API Consistency (Sync & Async)**
77
- All converters now support both Synchronous and Asynchronous operations for consistency.
78
-
79
- | Format | Sync Method | Async Method |
80
- |--------|-------------|--------------|
81
- | **JSON** | `jsonToToon` | `jsonToToonAsync` |
82
- | **YAML** | `yamlToToon` | `yamlToToonAsync` |
83
- | **XML** | `xmlToToonSync`* | `xmlToToon` |
84
- | **CSV** | `csvToToonSync` | `csvToToon` |
85
-
86
- *\*Note: `xmlToToonSync` in Node.js requires a global `DOMParser` polyfill (e.g., via `jsdom`).*
87
-
88
- ### 7. **Unified Class API** (`ToonConverter`)
89
- The `ToonConverter` class now exposes all variations:
90
-
91
- ```javascript
92
- // Async
93
- await ToonConverter.fromJsonAsync(data);
94
- await ToonConverter.fromXmlAsync(xml);
95
- await ToonConverter.fromCsvAsync(csv);
96
-
97
- // Sync
98
- ToonConverter.fromJson(data);
99
- ToonConverter.fromXmlSync(xml);
100
- ToonConverter.fromCsvSync(csv);
101
-
102
- // Mixed Text
103
- ToonConverter.fromJsonText(text);
104
- await ToonConverter.fromXmlText(text);
105
- ```
106
-
107
- ---
108
-
109
- ## 🚀 Benefits
110
-
111
- - **Robustness**: Validation prevents invalid conversions
112
- - **Flexibility**: Handle mixed content seamlessly
113
- - **Consistency**: Unified API for all formats
114
- - **Developer Experience**: Clear errors, easy debugging
115
- - **Reliability**: Comprehensive validation at every step
116
- - **Reusability**: Extraction functions available for custom use
117
-
118
- ---
119
-
120
- **Note**: History feature was intentionally NOT added to the package as requested.
121
-
122
- ---
123
-
124
- Made with ❤️ for the TOON Formatter project
@@ -1,139 +0,0 @@
1
- /**
2
- * Basic tests for TOON Converter
3
- * Run with: node --test test/basic.test.js
4
- */
5
-
6
- import { test } from 'node:test';
7
- import assert from 'node:assert';
8
- import { jsonToToonSync, toonToJsonSync } from '../src/json.js';
9
- import { validateToonStringSync } from '../src/validator.js';
10
-
11
- test('JSON to TOON - Simple Object', () => {
12
- const input = { name: "Alice", age: 30, active: true };
13
- const result = jsonToToonSync(input);
14
-
15
- assert.ok(result.includes('name: "Alice"'));
16
- assert.ok(result.includes('age: 30'));
17
- assert.ok(result.includes('active: true'));
18
- });
19
-
20
- test('JSON to TOON - Array of Primitives', () => {
21
- const input = { numbers: [1, 2, 3, 4, 5] };
22
- const result = jsonToToonSync(input);
23
-
24
- assert.ok(result.includes('numbers[5]: 1, 2, 3, 4, 5'));
25
- });
26
-
27
- test('JSON to TOON - Tabular Array', () => {
28
- const input = {
29
- users: [
30
- { id: 1, name: "Alice", active: true },
31
- { id: 2, name: "Bob", active: false }
32
- ]
33
- };
34
- const result = jsonToToonSync(input);
35
-
36
- assert.ok(result.includes('users[2]{id,name,active}:'));
37
- assert.ok(result.includes('1,"Alice",true'));
38
- assert.ok(result.includes('2,"Bob",false'));
39
- });
40
-
41
- test('TOON to JSON - Simple Object', () => {
42
- const input = `name: "Alice"\nage: 30\nactive: true`;
43
- const result = toonToJsonSync(input);
44
-
45
- assert.strictEqual(result.name, "Alice");
46
- assert.strictEqual(result.age, 30);
47
- assert.strictEqual(result.active, true);
48
- });
49
-
50
- test('TOON to JSON - Array of Primitives', () => {
51
- const input = `numbers[5]: 1, 2, 3, 4, 5`;
52
- const result = toonToJsonSync(input);
53
-
54
- assert.ok(Array.isArray(result.numbers));
55
- assert.strictEqual(result.numbers.length, 5);
56
- assert.deepStrictEqual(result.numbers, [1, 2, 3, 4, 5]);
57
- });
58
-
59
- test('TOON to JSON - Tabular Array', () => {
60
- const input = `users[2]{id,name,active}:\n 1,"Alice",true\n 2,"Bob",false`;
61
- const result = toonToJsonSync(input);
62
-
63
- assert.ok(Array.isArray(result.users));
64
- assert.strictEqual(result.users.length, 2);
65
- assert.strictEqual(result.users[0].id, 1);
66
- assert.strictEqual(result.users[0].name, "Alice");
67
- assert.strictEqual(result.users[0].active, true);
68
- assert.strictEqual(result.users[1].id, 2);
69
- assert.strictEqual(result.users[1].name, "Bob");
70
- assert.strictEqual(result.users[1].active, false);
71
- });
72
-
73
- test('Round-trip Conversion - Object', () => {
74
- const original = {
75
- company: "TechCorp",
76
- employees: [
77
- { name: "Alice", role: "Engineer" },
78
- { name: "Bob", role: "Designer" }
79
- ]
80
- };
81
-
82
- const toon = jsonToToonSync(original);
83
- const result = toonToJsonSync(toon);
84
-
85
- assert.deepStrictEqual(result, original);
86
- });
87
-
88
- test('Validator - Valid TOON', () => {
89
- const input = `name: "Alice"\nage: 30`;
90
- const result = validateToonStringSync(input);
91
-
92
- assert.strictEqual(result.isValid, true);
93
- assert.strictEqual(result.error, null);
94
- });
95
-
96
- test('Validator - Invalid TOON (Array Size Mismatch)', () => {
97
- const input = `items[3]: 1, 2`; // Declared 3, but only 2 items
98
- const result = validateToonStringSync(input);
99
-
100
- assert.strictEqual(result.isValid, false);
101
- assert.ok(result.error.includes('Array size mismatch'));
102
- });
103
-
104
- test('Validator - Valid Tabular Array', () => {
105
- const input = `users[2]{id,name}:\n 1,"Alice"\n 2,"Bob"`;
106
- const result = validateToonStringSync(input);
107
-
108
- assert.strictEqual(result.isValid, true);
109
- assert.strictEqual(result.error, null);
110
- });
111
-
112
- test('Edge Case - Empty Object', () => {
113
- const input = {};
114
- const result = jsonToToonSync(input);
115
-
116
- assert.strictEqual(result.trim(), '');
117
- });
118
-
119
- test('Edge Case - Null Value', () => {
120
- const input = { value: null };
121
- const result = jsonToToonSync(input);
122
-
123
- assert.ok(result.includes('value: null'));
124
- });
125
-
126
- test('Edge Case - Nested Objects', () => {
127
- const input = {
128
- level1: {
129
- level2: {
130
- level3: "deep"
131
- }
132
- }
133
- };
134
-
135
- const toon = jsonToToonSync(input);
136
- const result = toonToJsonSync(toon);
137
-
138
- assert.deepStrictEqual(result, input);
139
- });
@@ -1,135 +0,0 @@
1
- /**
2
- * Tests for YAML, XML, and CSV Converters
3
- * Run with: node --test test/converters.test.js
4
- */
5
-
6
- import { test } from 'node:test';
7
- import assert from 'node:assert';
8
- import { yamlToToonSync, toonToYamlSync } from '../src/yaml.js';
9
- import { xmlToToon, toonToXmlSync } from '../src/xml.js';
10
- import { csvToToon, csvToToonSync, toonToCsvSync } from '../src/csv.js';
11
-
12
- // --- YAML Tests ---
13
-
14
- test('YAML to TOON - Simple Object', () => {
15
- const yaml = `
16
- name: Alice
17
- age: 30
18
- `;
19
- const toon = yamlToToonSync(yaml);
20
- assert.ok(toon.includes('name: "Alice"'));
21
- assert.ok(toon.includes('age: 30'));
22
- });
23
-
24
- test('TOON to YAML - Simple Object', () => {
25
- const toon = `name: "Alice"\nage: 30`;
26
- const yaml = toonToYamlSync(toon);
27
- assert.ok(yaml.includes('name: Alice'));
28
- assert.ok(yaml.includes('age: 30'));
29
- });
30
-
31
- test('YAML to TOON - Nested Structure', () => {
32
- const yaml = `
33
- user:
34
- name: Alice
35
- roles:
36
- - admin
37
- - editor
38
- `;
39
- const toon = yamlToToonSync(yaml);
40
- assert.ok(toon.includes('user:'));
41
- assert.ok(toon.includes('name: "Alice"'));
42
- assert.ok(toon.includes('roles[2]:'));
43
- });
44
-
45
- // --- XML Tests ---
46
-
47
- test('XML to TOON - Simple Element', async () => {
48
- const xml = `<user><name>Alice</name><age>30</age></user>`;
49
- const toon = await xmlToToon(xml);
50
-
51
- // Note: XML conversion wraps based on root element
52
- assert.ok(toon.includes('user:'));
53
- assert.ok(toon.includes('name: "Alice"'));
54
- assert.ok(toon.includes('age: "30"')); // XML text content is usually string
55
- });
56
-
57
- test('TOON to XML - Simple Element', () => {
58
- const toon = `user:\n name: "Alice"\n age: 30`;
59
- const xml = toonToXmlSync(toon);
60
-
61
- assert.ok(xml.includes('<user>'));
62
- assert.ok(xml.includes('<name>Alice</name>'));
63
- assert.ok(xml.includes('<age>30</age>'));
64
- assert.ok(xml.includes('</user>'));
65
- });
66
-
67
- test('XML to TOON - Attributes', async () => {
68
- const xml = `<item id="123" type="widget">Content</item>`;
69
- const toon = await xmlToToon(xml);
70
-
71
- assert.ok(toon.includes('item:'));
72
- assert.ok(toon.includes('@attributes:'));
73
- assert.ok(toon.includes('id: "123"'));
74
- assert.ok(toon.includes('type: "widget"'));
75
- assert.ok(toon.includes('#text: "Content"'));
76
- });
77
-
78
- // --- CSV Tests ---
79
-
80
- test('CSV to TOON - Basic (Async)', async () => {
81
- const csv = `name,age,active
82
- Alice,30,true
83
- Bob,25,false`;
84
-
85
- const toon = await csvToToon(csv);
86
-
87
- // Should detect as tabular array or array of objects
88
- // Since root is array, it might be [2]{name,age,active}: ...
89
-
90
- assert.ok(toon.includes('[2]{name,age,active}:'));
91
- assert.ok(toon.includes('Alice'));
92
- assert.ok(toon.includes('30'));
93
- assert.ok(toon.includes('true'));
94
- });
95
-
96
- test('CSV to TOON - Basic (Sync)', () => {
97
- const csv = `id,product
98
- 1,Apple
99
- 2,Banana`;
100
-
101
- const toon = csvToToonSync(csv);
102
-
103
- assert.ok(toon.includes('[2]{id,product}:'));
104
- assert.ok(toon.includes('1,"Apple"'));
105
- assert.ok(toon.includes('2,"Banana"'));
106
- });
107
-
108
- test('TOON to CSV - Basic', () => {
109
- const toon = `
110
- [2]{name,role}:
111
- "Alice","Admin"
112
- "Bob","User"
113
- `;
114
- const csv = toonToCsvSync(toon);
115
-
116
- assert.ok(csv.includes('name,role'));
117
- assert.ok(csv.includes('Alice,Admin'));
118
- assert.ok(csv.includes('Bob,User'));
119
- });
120
-
121
- test('CSV Round Trip', async () => {
122
- const originalCsv = `name,score
123
- Alice,100
124
- Bob,95`;
125
-
126
- const toon = await csvToToon(originalCsv);
127
- const finalCsv = toonToCsvSync(toon);
128
-
129
- // Note: PapaParse might add/remove quotes or change spacing, so exact match isn't always guaranteed
130
- // But content should be same
131
- assert.ok(finalCsv.includes('name'));
132
- assert.ok(finalCsv.includes('score'));
133
- assert.ok(finalCsv.includes('Alice'));
134
- assert.ok(finalCsv.includes('100'));
135
- });