toon-parser 2.1.1 → 2.2.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/README.md CHANGED
@@ -14,7 +14,13 @@ Safe JSON ⇆ TOON encoder/decoder with strict validation and prototype-pollutio
14
14
  npm install toon-parser
15
15
  ```
16
16
 
17
- Note: this package supports both ESM and CommonJS consumers (CJS builds are available as `dist/index.cjs`). The package requires Node >= 18 per `engines` in `package.json`.
17
+ Note: this package supports both ESM and CommonJS consumers (CJS builds are available as `dist/index.cjs`). The package requires Node >= 20 per `engines` in `package.json`.
18
+
19
+ ## New in 2.2.0
20
+ - **Security**: Fixed 8 dependency vulnerabilities (1 critical `fast-xml-parser` with 6 CVEs, 5 high, 2 moderate).
21
+ - **Dependencies**: Updated all dependencies to latest versions (vitest 4, TypeScript 5.9, fast-xml-parser 5.5.9).
22
+ - **Node.js**: Minimum version bumped to Node 20 (Node 18 reached EOL April 2025).
23
+ - **Build**: `esbuild` is now an explicit dependency; test files excluded from published tarball.
18
24
 
19
25
  ## New in 2.1.0
20
26
  - **HTML/CSV/Log/URL Support**: Dedicated parsers for common formats to leverage Toon's structure.
@@ -204,4 +210,4 @@ try {
204
210
 
205
211
  ## Project status
206
212
 
207
- This library targets TOON spec v2.1 core behaviors commonly needed for JSON round-trips. It prioritizes correctness and safety over permissiveness; loosen validation via `strict: false` only when you fully trust the input source.***
213
+ This library targets TOON spec v2.1 core behaviors commonly needed for JSON round-trips. It prioritizes correctness and safety over permissiveness; loosen validation via `strict: false` only when you fully trust the input source.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toon-parser",
3
- "version": "2.1.1",
3
+ "version": "2.2.1",
4
4
  "description": "Safe JSON <-> TOON encoder/decoder with strict validation.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -14,7 +14,8 @@
14
14
  }
15
15
  },
16
16
  "files": [
17
- "dist"
17
+ "dist",
18
+ "!dist/**/*.test.*"
18
19
  ],
19
20
  "scripts": {
20
21
  "typecheck": "tsc -p tsconfig.json --noEmit",
@@ -41,7 +42,7 @@
41
42
  "author": "Branislav Lang",
42
43
  "repository": {
43
44
  "type": "git",
44
- "url": "https://github.com/BranLang/toon-parser"
45
+ "url": "git+https://github.com/BranLang/toon-parser.git"
45
46
  },
46
47
  "bugs": {
47
48
  "url": "https://github.com/BranLang/toon-parser/issues"
@@ -50,17 +51,18 @@
50
51
  "license": "MIT",
51
52
  "sideEffects": false,
52
53
  "devDependencies": {
53
- "fast-check": "^4.3.0",
54
- "rimraf": "^6.0.0",
55
- "eslint": "^9.0.0",
56
- "@typescript-eslint/parser": "^8.49.0",
57
- "@typescript-eslint/eslint-plugin": "^8.48.1"
54
+ "esbuild": "^0.27.4",
55
+ "fast-check": "^4.6.0",
56
+ "rimraf": "^6.1.3",
57
+ "eslint": "^9.39.4",
58
+ "@typescript-eslint/parser": "^8.58.0",
59
+ "@typescript-eslint/eslint-plugin": "^8.58.0"
58
60
  },
59
61
  "engines": {
60
- "node": ">=18"
62
+ "node": ">=20"
61
63
  },
62
64
  "dependencies": {
63
- "fast-xml-parser": "^5.3.2",
64
- "node-html-parser": "^7.0.1"
65
+ "fast-xml-parser": "^5.5.9",
66
+ "node-html-parser": "^7.1.0"
65
67
  }
66
68
  }
package/dist/cjs.test.cjs DELETED
@@ -1,46 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") {
10
- for (let key of __getOwnPropNames(from))
11
- if (!__hasOwnProp.call(to, key) && key !== except)
12
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
- }
14
- return to;
15
- };
16
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
- // If the importer is in node compatibility mode or this is not an ESM
18
- // file that has been converted to a CommonJS file using a Babel-
19
- // compatible transform (i.e. "__esModule" has not been set), then set
20
- // "default" to the CommonJS "module.exports" for node compatibility.
21
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
- mod
23
- ));
24
- var import_vitest = require("vitest");
25
- var esmModule = __toESM(require("./index"), 1);
26
- var import_fs = __toESM(require("fs"), 1);
27
- var import_path = __toESM(require("path"), 1);
28
- const distPath = import_path.default.join(__dirname, "..", "dist", "index.cjs");
29
- (0, import_vitest.describe)("CJS built package", () => {
30
- (0, import_vitest.it)("exposes same API as ESM source (if built)", () => {
31
- if (!import_fs.default.existsSync(distPath)) {
32
- (0, import_vitest.expect)(true).toBeTruthy();
33
- return;
34
- }
35
- const cjs = require(distPath);
36
- (0, import_vitest.expect)(typeof cjs.jsonToToon).toBe("function");
37
- (0, import_vitest.expect)(typeof cjs.toonToJson).toBe("function");
38
- const sample = { a: 1, b: "x" };
39
- const e = esmModule.jsonToToon(sample);
40
- const d = cjs.jsonToToon(sample);
41
- (0, import_vitest.expect)(e).toBeDefined();
42
- (0, import_vitest.expect)(d).toBeDefined();
43
- (0, import_vitest.expect)(esmModule.toonToJson(e)).toEqual(sample);
44
- (0, import_vitest.expect)(cjs.toonToJson(d)).toEqual(sample);
45
- });
46
- });
@@ -1,35 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("Complex Scenarios", () => {
5
- (0, import_vitest.describe)("CSV Complex Escaping", () => {
6
- (0, import_vitest.it)("handles newlines and escaped quotes inside quoted fields", () => {
7
- const csv = `"note","data"
8
- "line1
9
- line2","has ""quotes"" inside"`;
10
- const toon = (0, import_index.csvToToon)(csv);
11
- (0, import_vitest.expect)(toon).toContain('"line1\\nline2"');
12
- (0, import_vitest.expect)(toon).toContain('"has \\"quotes\\" inside"');
13
- });
14
- });
15
- (0, import_vitest.describe)("HTML Deep Nesting & Attributes", () => {
16
- (0, import_vitest.it)("preserves attributes in deeply nested lists", () => {
17
- const html = `<ul>
18
- <li class="item" data-id="1">Item 1</li>
19
- <li class="item" data-id="2">Item 2</li>
20
- </ul>`;
21
- const toon = (0, import_index.htmlToToon)(html);
22
- (0, import_vitest.expect)(toon).toContain("ul:");
23
- (0, import_vitest.expect)(toon).toContain("li:");
24
- (0, import_vitest.expect)(toon).toContain('"@_class": item');
25
- (0, import_vitest.expect)(toon).toContain('"@_data-id": "1"');
26
- });
27
- });
28
- (0, import_vitest.describe)("URL Array Syntax", () => {
29
- (0, import_vitest.it)("expands bracket notation deeply", () => {
30
- const url = "sort[order]=asc&sort[fields][]=name&sort[fields][]=date";
31
- const toon = (0, import_index.urlToToon)(url);
32
- (0, import_vitest.expect)(toon).toContain("order: asc");
33
- });
34
- });
35
- });
@@ -1,49 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("Coverage & Edge Case Gaps", () => {
5
- (0, import_vitest.describe)("decodeKey Invalid Inputs", () => {
6
- (0, import_vitest.it)("throws on unquoted key starting with invalid character", () => {
7
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)('123key: "val"')).toThrow(/Invalid key token/);
8
- });
9
- (0, import_vitest.it)("throws on unquoted key with special characters", () => {
10
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)('key+val: "val"')).toThrow(/Invalid key token/);
11
- });
12
- (0, import_vitest.it)("throws on unquoted key containing delimiter (fails regex anyway)", () => {
13
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)('key,val: "val"')).toThrow(/Invalid key token/);
14
- });
15
- });
16
- (0, import_vitest.describe)("Tabular Fallback", () => {
17
- (0, import_vitest.it)("falls back to list format if object values are non-primitive", () => {
18
- const data = [
19
- { id: 1, info: { meta: "not-primitive" } },
20
- { id: 2, info: { meta: "x" } }
21
- ];
22
- const encoded = (0, import_index.jsonToToon)(data);
23
- (0, import_vitest.expect)(encoded).not.toContain("]{id,info}");
24
- (0, import_vitest.expect)(encoded).toContain("-");
25
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
26
- });
27
- (0, import_vitest.it)("falls back to list format if objects have different keys", () => {
28
- const data = [
29
- { id: 1, a: 1 },
30
- { id: 2, b: 2 }
31
- ];
32
- const encoded = (0, import_index.jsonToToon)(data);
33
- (0, import_vitest.expect)(encoded).not.toContain("]{id,a}");
34
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
35
- });
36
- });
37
- (0, import_vitest.describe)("Circular References", () => {
38
- (0, import_vitest.it)("throws error on circular reference", () => {
39
- const a = { name: "a" };
40
- a.self = a;
41
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)(a)).toThrow(/Maximum depth \d+ exceeded/);
42
- });
43
- });
44
- (0, import_vitest.describe)("Tabular Header Pollution", () => {
45
- (0, import_vitest.it)("throws if tabular header contains disallowed keys when row is parsed", () => {
46
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)("[1]{__proto__}:\n 1")).toThrow(/Disallowed key "__proto__"/);
47
- });
48
- });
49
- });
@@ -1,20 +0,0 @@
1
- "use strict";
2
- var import_csv = require("../src/csv");
3
- var import_vitest = require("vitest");
4
- (0, import_vitest.test)("malformed CSV throws error", () => {
5
- const malformed = "a,b\n1,2,3";
6
- (0, import_vitest.expect)(() => (0, import_csv.csvToJson)(malformed)).toThrow();
7
- });
8
- (0, import_vitest.test)("empty CSV returns empty array", () => {
9
- const empty = "";
10
- const result = (0, import_csv.csvToJson)(empty);
11
- (0, import_vitest.expect)(result).toEqual([]);
12
- });
13
- (0, import_vitest.test)("multi-character delimiter is rejected", () => {
14
- const data = "a|b\n1|2";
15
- (0, import_vitest.expect)(() => (0, import_csv.csvToJson)(data, { delimiter: "||" })).toThrow();
16
- });
17
- (0, import_vitest.test)("row length mismatch throws in csvToToon", () => {
18
- const malformed = "a,b\n1,2,3";
19
- (0, import_vitest.expect)(() => (0, import_csv.csvToToon)(malformed)).toThrow();
20
- });
package/dist/csv.test.cjs DELETED
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_csv = require("./csv");
4
- (0, import_vitest.describe)("csvToToon", () => {
5
- (0, import_vitest.it)("converts simple CSV with header to table", () => {
6
- const csv = `id,name,role
7
- 1,Alice,Admin
8
- 2,Bob,User`;
9
- const toon = (0, import_csv.csvToToon)(csv);
10
- (0, import_vitest.expect)(toon).toContain("[2]{id,name,role}:");
11
- (0, import_vitest.expect)(toon).toContain("1,Alice,Admin");
12
- (0, import_vitest.expect)(toon).toContain("2,Bob,User");
13
- });
14
- (0, import_vitest.it)("handles quoted values", () => {
15
- const csv = `id,desc
16
- 1,"Hello, World"`;
17
- const toon = (0, import_csv.csvToToon)(csv);
18
- (0, import_vitest.expect)(toon).toContain('"Hello, World"');
19
- });
20
- (0, import_vitest.it)("handles headerless csv", () => {
21
- const csv = `1,2
22
- 3,4`;
23
- const toon = (0, import_csv.csvToToon)(csv, { hasHeader: false });
24
- (0, import_vitest.expect)(toon).toContain("- [2]: 1,2");
25
- (0, import_vitest.expect)(toon).toContain("- [2]: 3,4");
26
- });
27
- });
@@ -1,23 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("Edge case tests", () => {
5
- (0, import_vitest.it)("round-trips arrays with empty objects", () => {
6
- const data = { arr: [{}, { id: 1 }] };
7
- const t = (0, import_index.jsonToToon)(data);
8
- const back = (0, import_index.toonToJson)(t);
9
- (0, import_vitest.expect)(back).toEqual(data);
10
- });
11
- (0, import_vitest.it)("round-trips keys with punctuation (quoted)", () => {
12
- const data = { "a b": 1, "!ok": 2 };
13
- const t = (0, import_index.jsonToToon)(data);
14
- const back = (0, import_index.toonToJson)(t);
15
- (0, import_vitest.expect)(back).toEqual(data);
16
- });
17
- (0, import_vitest.it)("handles strings with delimiter and colon characters by quoting", () => {
18
- const data = { val: "1,2:3|x" };
19
- const t = (0, import_index.jsonToToon)(data, { delimiter: "," });
20
- const back = (0, import_index.toonToJson)(t);
21
- (0, import_vitest.expect)(back).toEqual(data);
22
- });
23
- });
@@ -1,19 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("Toon parser strict vs non-strict and diagnostics", () => {
5
- (0, import_vitest.it)("allows inline length mismatch when strict false", () => {
6
- const result = (0, import_index.toonToJson)("vals[2]: 1", { strict: false });
7
- (0, import_vitest.expect)(result).toEqual({ vals: [1] });
8
- });
9
- (0, import_vitest.it)("includes line numbers in errors", () => {
10
- try {
11
- (0, import_index.toonToJson)("vals[2]: 1", { strict: true });
12
- throw new Error("Should have thrown");
13
- } catch (err) {
14
- (0, import_vitest.expect)(err).toBeInstanceOf(Error);
15
- (0, import_vitest.expect)(String(err)).toMatch(/Line 1/);
16
- (0, import_vitest.expect)(String(err)).toMatch(/length mismatch/);
17
- }
18
- });
19
- });
@@ -1,16 +0,0 @@
1
- "use strict";
2
- var import_html = require("../src/html");
3
- var import_vitest = require("vitest");
4
- (0, import_vitest.test)("nested HTML tags are parsed correctly", () => {
5
- const html = "<div><span>Text</span></div>";
6
- const result = (0, import_html.htmlToJson)(html);
7
- (0, import_vitest.expect)(result).toMatchObject({ children: [{ tag: "div", children: [{ tag: "span", text: "Text" }] }] });
8
- });
9
- (0, import_vitest.test)("malformed HTML throws error", () => {
10
- const badHtml = "<div><span>Missing closing tags";
11
- (0, import_vitest.expect)(() => (0, import_html.htmlToJson)(badHtml)).toThrow();
12
- });
13
- (0, import_vitest.test)("hostile input does not hang (no ReDoS)", () => {
14
- const hostile = "<0".repeat(5e3);
15
- (0, import_vitest.expect)(() => (0, import_html.htmlToJson)(hostile)).not.toThrow();
16
- });
@@ -1,28 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_html = require("./html");
4
- (0, import_vitest.describe)("htmlToToon", () => {
5
- (0, import_vitest.it)("converts simple html", () => {
6
- const html = '<div class="foo">Hello</div>';
7
- const toon = (0, import_html.htmlToToon)(html);
8
- (0, import_vitest.expect)(toon).toContain("div:");
9
- (0, import_vitest.expect)(toon).toContain('"@_class": foo');
10
- (0, import_vitest.expect)(toon).toContain('"#text": Hello');
11
- });
12
- (0, import_vitest.it)("converts nested structure", () => {
13
- const html = "<ul><li>A</li><li>B</li></ul>";
14
- const toon = (0, import_html.htmlToToon)(html);
15
- (0, import_vitest.expect)(toon).toContain("ul:");
16
- (0, import_vitest.expect)(toon).toContain("li");
17
- (0, import_vitest.expect)(toon).toContain("A");
18
- (0, import_vitest.expect)(toon).toContain("B");
19
- });
20
- (0, import_vitest.it)("converts mixed content", () => {
21
- const html = "<p>Hello <b>World</b></p>";
22
- const toon = (0, import_html.htmlToToon)(html);
23
- (0, import_vitest.expect)(toon).toContain("p:");
24
- (0, import_vitest.expect)(toon).toContain('"#children"[2]:');
25
- (0, import_vitest.expect)(toon).toContain("- Hello");
26
- (0, import_vitest.expect)(toon).toContain("b: World");
27
- });
28
- });
@@ -1,59 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("json-toon parser", () => {
5
- (0, import_vitest.it)("round-trips objects with tabular arrays", () => {
6
- const payload = {
7
- context: { task: "hike planning", year: 2025 },
8
- friends: ["ana", "luis", "sam"],
9
- hikes: [
10
- { id: 1, name: "Blue Lake", distanceKm: 7.5, wasSunny: true },
11
- { id: 2, name: "Ridge Overlook", distanceKm: 9.2, wasSunny: false }
12
- ]
13
- };
14
- const toon = (0, import_index.jsonToToon)(payload);
15
- (0, import_vitest.expect)(toon).toContain("hikes[2]{id,name,distanceKm,wasSunny}");
16
- const decoded = (0, import_index.toonToJson)(toon);
17
- (0, import_vitest.expect)(decoded).toEqual(payload);
18
- });
19
- (0, import_vitest.it)("quotes strings that could be misread as primitives", () => {
20
- const payload = {
21
- literalTrue: "true",
22
- spaced: " leading",
23
- dash: "-value",
24
- colon: "a:b"
25
- };
26
- const toon = (0, import_index.jsonToToon)(payload);
27
- (0, import_vitest.expect)(toon).toContain('"true"');
28
- (0, import_vitest.expect)(toon).toContain('" leading"');
29
- (0, import_vitest.expect)(toon).toContain('"-value"');
30
- const decoded = (0, import_index.toonToJson)(toon);
31
- (0, import_vitest.expect)(decoded).toEqual(payload);
32
- });
33
- (0, import_vitest.it)("rejects prototype-polluting keys when encoding and decoding", () => {
34
- const polluted = /* @__PURE__ */ Object.create(null);
35
- polluted["__proto__"] = 1;
36
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)(polluted)).toThrow(/Disallowed key/);
37
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)("__proto__: 1")).toThrow(/Disallowed key/);
38
- });
39
- (0, import_vitest.it)("enforces declared array lengths in strict mode", () => {
40
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)("nums[2]: 1")).toThrow(/length mismatch/);
41
- });
42
- (0, import_vitest.it)("rejects numbers with leading zeros", () => {
43
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)("value: 007")).toThrow(/leading zeros/);
44
- });
45
- (0, import_vitest.it)('treats a numeric-like but non-numeric token as a quoted string (e.g., "00;")', () => {
46
- (0, import_vitest.expect)((0, import_index.toonToJson)('value: "00;"')).toEqual({ value: "00;" });
47
- });
48
- (0, import_vitest.it)("round-trips nested array items that contain objects", () => {
49
- const payload = [
50
- [
51
- { id: 1, label: "alpha" },
52
- { id: 2, label: "beta" }
53
- ]
54
- ];
55
- const toon = (0, import_index.jsonToToon)(payload);
56
- const decoded = (0, import_index.toonToJson)(toon);
57
- (0, import_vitest.expect)(decoded).toEqual(payload);
58
- });
59
- });
@@ -1,21 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("security enforcement and limits", () => {
5
- (0, import_vitest.it)("throws when maxDepth exceeded", () => {
6
- let nested = { a: 1 };
7
- for (let i = 0; i < 70; i++) {
8
- nested = [nested];
9
- }
10
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)(nested)).toThrow(/Maximum depth/);
11
- });
12
- (0, import_vitest.it)("throws when maxArrayLength is exceeded", () => {
13
- const arr = new Array(50001).fill(0);
14
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ arr })).toThrow(/Array length/);
15
- });
16
- (0, import_vitest.it)("throws when maxTotalNodes exceeded", () => {
17
- const bigObj = {};
18
- for (let i = 0; i < 1e3; i++) bigObj["k" + i] = i;
19
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)(bigObj, { maxTotalNodes: 100 })).toThrow(/Node count/);
20
- });
21
- });
@@ -1,15 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_log = require("./log");
4
- (0, import_vitest.describe)("logToToon CLF ReDoS mitigation", () => {
5
- (0, import_vitest.it)("parses malicious CLF line without hanging", () => {
6
- const maliciousRequest = "GET " + "a".repeat(5e3) + " HTTP/1.1";
7
- const line = `127.0.0.1 - - [01/Jan/2020:00:00:00 +0000] "${maliciousRequest}" 200 1234`;
8
- const logData = line + "\n";
9
- const start = Date.now();
10
- const result = (0, import_log.logToToon)(logData);
11
- const duration = Date.now() - start;
12
- (0, import_vitest.expect)(result).toContain("GET");
13
- (0, import_vitest.expect)(duration).toBeLessThan(100);
14
- });
15
- });
package/dist/log.test.cjs DELETED
@@ -1,20 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_log = require("./log");
4
- (0, import_vitest.describe)("logToToon", () => {
5
- (0, import_vitest.it)("converts json logs", () => {
6
- const logs = `{"id":1}
7
- {"id":2}`;
8
- const toon = (0, import_log.logToToon)(logs, { format: "json" });
9
- (0, import_vitest.expect)(toon).toContain("[2]{id}:");
10
- (0, import_vitest.expect)(toon).toContain("1");
11
- (0, import_vitest.expect)(toon).toContain("2");
12
- });
13
- (0, import_vitest.it)("converts CLF logs", () => {
14
- const log = `127.0.0.1 - - [10/Oct:13:55:36] "GET /index.html" 200 1024`;
15
- const toon = (0, import_log.logToToon)(log, { format: "clf" });
16
- (0, import_vitest.expect)(toon).toContain("[1]{host,date,request,status,size}:");
17
- (0, import_vitest.expect)(toon).toContain("127.0.0.1");
18
- (0, import_vitest.expect)(toon).toContain("GET /index.html");
19
- });
20
- });
@@ -1,60 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") {
10
- for (let key of __getOwnPropNames(from))
11
- if (!__hasOwnProp.call(to, key) && key !== except)
12
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
- }
14
- return to;
15
- };
16
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
- // If the importer is in node compatibility mode or this is not an ESM
18
- // file that has been converted to a CommonJS file using a Babel-
19
- // compatible transform (i.e. "__esModule" has not been set), then set
20
- // "default" to the CommonJS "module.exports" for node compatibility.
21
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
- mod
23
- ));
24
- var import_vitest = require("vitest");
25
- var fc = __toESM(require("fast-check"), 1);
26
- var import_index = require("./index");
27
- const arbJson = fc.letrec((tie) => {
28
- const primitiveArb = fc.oneof(
29
- // allow strings with punctuation and whitespace - they will be quoted by serializer
30
- fc.string({ minLength: 0, maxLength: 6 }).filter((s) => s.length <= 6),
31
- fc.integer(),
32
- fc.boolean(),
33
- fc.constant(null)
34
- );
35
- const innerObjArb = fc.dictionary(fc.string({ minLength: 1, maxLength: 6 }), fc.oneof(fc.string(), fc.integer(), fc.boolean()), { maxKeys: 3 });
36
- const arrArb = fc.array(fc.oneof(primitiveArb, fc.array(primitiveArb, { maxLength: 2 }), innerObjArb), { maxLength: 3 });
37
- const dictArb = fc.dictionary(
38
- fc.string({ minLength: 1, maxLength: 6 }).filter((k) => /^[A-Za-z_][A-Za-z0-9_.]*$/.test(k)),
39
- tie("json"),
40
- { maxKeys: 3 }
41
- ).filter((o) => Object.keys(o).length > 0);
42
- return {
43
- json: fc.oneof(fc.string(), fc.integer(), fc.boolean(), fc.constant(null), arrArb, dictArb)
44
- };
45
- }).json;
46
- const safeKey = fc.string({ minLength: 1, maxLength: 8 });
47
- const arbTopObject = fc.dictionary(safeKey, arbJson, { maxKeys: 4 }).filter((o) => Object.keys(o).length > 0);
48
- (0, import_vitest.describe)("property-based round-trip", () => {
49
- (0, import_vitest.it)("round trips random JSON values", () => {
50
- fc.assert(
51
- fc.property(arbTopObject, (val) => {
52
- const t = (0, import_index.jsonToToon)(val);
53
- const back = (0, import_index.toonToJson)(t);
54
- (0, import_vitest.expect)(back).toEqual(val);
55
- return true;
56
- }),
57
- { numRuns: 100 }
58
- );
59
- });
60
- });
@@ -1,132 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("Smoke Tests: Unexpected Inputs & Edge Cases", () => {
5
- (0, import_vitest.describe)("Unsupported Types", () => {
6
- (0, import_vitest.it)("throws on RegExp", () => {
7
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ regex: /abc/ })).toThrow(/Unsupported value type/);
8
- });
9
- (0, import_vitest.it)("throws on Map", () => {
10
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ map: /* @__PURE__ */ new Map() })).toThrow(/Unsupported value type/);
11
- });
12
- (0, import_vitest.it)("throws on Set", () => {
13
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ set: /* @__PURE__ */ new Set() })).toThrow(/Unsupported value type/);
14
- });
15
- (0, import_vitest.it)("throws on Function", () => {
16
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ fn: () => {
17
- } })).toThrow(/Unsupported value type/);
18
- });
19
- (0, import_vitest.it)("throws on Symbol", () => {
20
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ sym: Symbol("sym") })).toThrow(/Unsupported value type/);
21
- });
22
- (0, import_vitest.it)("throws on undefined values (unlike JSON.stringify which omits them)", () => {
23
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ val: void 0 })).toThrow(/Unsupported value type: undefined/);
24
- });
25
- });
26
- (0, import_vitest.describe)("Numeric Edge Cases", () => {
27
- (0, import_vitest.it)("handles NaN (converts to string or throws?) - current impl expects finite numbers", () => {
28
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ val: NaN })).toThrow(/Numeric values must be finite/);
29
- });
30
- (0, import_vitest.it)("handles Infinity", () => {
31
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ val: Infinity })).toThrow(/Numeric values must be finite/);
32
- });
33
- (0, import_vitest.it)("handles -Infinity", () => {
34
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)({ val: -Infinity })).toThrow(/Numeric values must be finite/);
35
- });
36
- (0, import_vitest.it)("handles negative zero", () => {
37
- const result = (0, import_index.jsonToToon)({ val: -0 });
38
- (0, import_vitest.expect)(result).toContain("-0");
39
- const decoded = (0, import_index.toonToJson)(result);
40
- (0, import_vitest.expect)(decoded).toEqual({ val: -0 });
41
- });
42
- });
43
- (0, import_vitest.describe)("String Quoting & Special Characters", () => {
44
- (0, import_vitest.it)("quotes strings that look like boolean/null", () => {
45
- const data = { a: "true", b: "false", c: "null" };
46
- const encoded = (0, import_index.jsonToToon)(data);
47
- (0, import_vitest.expect)(encoded).toContain('"true"');
48
- (0, import_vitest.expect)(encoded).toContain('"false"');
49
- (0, import_vitest.expect)(encoded).toContain('"null"');
50
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
51
- });
52
- (0, import_vitest.it)("quotes strings that look like numbers", () => {
53
- const data = { a: "123", b: "-45.67" };
54
- const encoded = (0, import_index.jsonToToon)(data);
55
- (0, import_vitest.expect)(encoded).toContain('"123"');
56
- (0, import_vitest.expect)(encoded).toContain('"-45.67"');
57
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
58
- });
59
- (0, import_vitest.it)("quotes strings with leading zeros", () => {
60
- const data = { code: "007" };
61
- const encoded = (0, import_index.jsonToToon)(data);
62
- (0, import_vitest.expect)(encoded).toContain('"007"');
63
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
64
- });
65
- (0, import_vitest.it)("quotes strings containing delimiters", () => {
66
- const data = { val: "a,b|c" };
67
- const encoded = (0, import_index.jsonToToon)(data);
68
- (0, import_vitest.expect)(encoded).toContain('"a,b|c"');
69
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
70
- });
71
- (0, import_vitest.it)("handles emoji and unicode", () => {
72
- const data = { "\u{1F680}": "To the moon \u{1F315}", "\xFCber": "m\xFCnchen" };
73
- const encoded = (0, import_index.jsonToToon)(data);
74
- (0, import_vitest.expect)(encoded).toContain("\u{1F680}");
75
- (0, import_vitest.expect)(encoded).toContain("\u{1F315}");
76
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
77
- });
78
- (0, import_vitest.it)("handles control characters by escaping", () => {
79
- const data = { newline: "line1\nline2", tab: "col1 col2" };
80
- const encoded = (0, import_index.jsonToToon)(data);
81
- (0, import_vitest.expect)(encoded).toContain("\\n");
82
- (0, import_vitest.expect)(encoded).toContain("\\t");
83
- (0, import_vitest.expect)((0, import_index.toonToJson)(encoded)).toEqual(data);
84
- });
85
- });
86
- (0, import_vitest.describe)("Deep Nesting", () => {
87
- (0, import_vitest.it)("throws when max depth is exceeded", () => {
88
- let deep = { val: 1 };
89
- for (let i = 0; i < 70; i++) {
90
- deep = { next: deep };
91
- }
92
- (0, import_vitest.expect)(() => (0, import_index.jsonToToon)(deep)).toThrow(/Maximum depth 64 exceeded/);
93
- });
94
- });
95
- (0, import_vitest.describe)("Dates (Standard Smoke)", () => {
96
- (0, import_vitest.it)("supports multiple Date objects in array", () => {
97
- const dates = [/* @__PURE__ */ new Date("2023-01-01"), /* @__PURE__ */ new Date("2024-01-01")];
98
- const encoded = (0, import_index.jsonToToon)(dates);
99
- (0, import_vitest.expect)(encoded).toContain("2023");
100
- (0, import_vitest.expect)(encoded).toContain("2024");
101
- const decoded = (0, import_index.toonToJson)(encoded);
102
- (0, import_vitest.expect)(decoded).toEqual(dates.map((d) => d.toISOString()));
103
- });
104
- });
105
- (0, import_vitest.describe)("New Parsers Edge Cases", () => {
106
- (0, import_vitest.it)("CSV: handles mixed quotes and delimiters", () => {
107
- const csv = `a,"b,c",d
108
- 1,"2|3",4`;
109
- const toon = (0, import_index.csvToToon)(csv, { delimiter: "," });
110
- (0, import_vitest.expect)(toon).toContain("1,2|3,4");
111
- });
112
- (0, import_vitest.it)("HTML: handles internal scripts and styles (content preservation)", () => {
113
- const html = "<div><script>alert(1)</script></div>";
114
- const toon = (0, import_index.htmlToToon)(html);
115
- (0, import_vitest.expect)(toon).toContain("alert(1)");
116
- });
117
- (0, import_vitest.it)("URL: handles duplicate keys as arrays", () => {
118
- const qs = "id=1&id=2";
119
- const toon = (0, import_index.urlToToon)(qs);
120
- (0, import_vitest.expect)(toon).toContain("id: 2");
121
- });
122
- (0, import_vitest.it)("Log: handles empty lines or malformed lines gracefully", () => {
123
- const log = `127.0.0.1 - - [10/Oct:2023] "GET /" 200 123
124
-
125
-
126
- [malformed line]`;
127
- const toon = (0, import_index.logToToon)(log);
128
- (0, import_vitest.expect)(toon).toContain("host: 127.0.0.1");
129
- (0, import_vitest.expect)(toon).toContain('raw: "[malformed line]"');
130
- });
131
- });
132
- });
@@ -1,21 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("snapshot tests for JSON -> TOON", () => {
5
- (0, import_vitest.it)("tabular snapshot", () => {
6
- const data = {
7
- readings: [
8
- { id: 1, a: "x" },
9
- { id: 2, a: "y" }
10
- ],
11
- list: [1, 2, 3]
12
- };
13
- const toon = (0, import_index.jsonToToon)(data);
14
- (0, import_vitest.expect)(toon).toMatchSnapshot();
15
- });
16
- (0, import_vitest.it)("nested snapshot", () => {
17
- const data = { project: { name: "Test", version: "0.1" }, items: [{ id: 1 }, {}] };
18
- const toon = (0, import_index.jsonToToon)(data);
19
- (0, import_vitest.expect)(toon).toMatchSnapshot();
20
- });
21
- });
@@ -1,21 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_index = require("./index");
4
- (0, import_vitest.describe)("Tabular arrays detection and behavior", () => {
5
- (0, import_vitest.it)("detects tabular arrays and emits tabular header", () => {
6
- const arr = [{ a: 1, b: 2 }, { a: 2, b: 3 }];
7
- const t = (0, import_index.jsonToToon)({ rows: arr });
8
- (0, import_vitest.expect)(t).toContain("rows[2]{a,b}:");
9
- const decoded = (0, import_index.toonToJson)(t);
10
- (0, import_vitest.expect)(decoded).toEqual({ rows: arr });
11
- });
12
- (0, import_vitest.it)("rejects tabular row width mismatch in strict mode", () => {
13
- const input = "rows[2]{a,b}:\n 1,2\n 1";
14
- (0, import_vitest.expect)(() => (0, import_index.toonToJson)(input)).toThrow(/Tabular row width mismatch/);
15
- });
16
- (0, import_vitest.it)("skips tabular detection when object shapes differ", () => {
17
- const arr = [{ a: 1, b: 2 }, { a: 2, c: 3 }];
18
- const t = (0, import_index.jsonToToon)({ rows: arr });
19
- (0, import_vitest.expect)(t).toContain("rows[2]:");
20
- });
21
- });
package/dist/url.test.cjs DELETED
@@ -1,25 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_url = require("./url");
4
- (0, import_vitest.describe)("urlToToon", () => {
5
- (0, import_vitest.it)("parses simple query string", () => {
6
- const qs = "foo=bar&baz=123";
7
- const toon = (0, import_url.urlToToon)(qs);
8
- (0, import_vitest.expect)(toon).toContain("foo: bar");
9
- (0, import_vitest.expect)(toon).toContain("baz: 123");
10
- });
11
- (0, import_vitest.it)("handles full url", () => {
12
- const url = "https://example.com/api?a=1";
13
- const toon = (0, import_url.urlToToon)(url);
14
- (0, import_vitest.expect)(toon).toContain("a: 1");
15
- });
16
- (0, import_vitest.it)("expands nested keys", () => {
17
- const qs = "user[name]=Alice&user[age]=30&filter.sort=asc";
18
- const toon = (0, import_url.urlToToon)(qs);
19
- (0, import_vitest.expect)(toon).toContain("user:");
20
- (0, import_vitest.expect)(toon).toContain("name: Alice");
21
- (0, import_vitest.expect)(toon).toContain("age: 30");
22
- (0, import_vitest.expect)(toon).toContain("filter:");
23
- (0, import_vitest.expect)(toon).toContain("sort: asc");
24
- });
25
- });
@@ -1,16 +0,0 @@
1
- "use strict";
2
- var import_xml = require("../src/xml");
3
- var import_vitest = require("vitest");
4
- (0, import_vitest.test)("malformed XML throws error", () => {
5
- const badXml = "<root><unclosed></root>";
6
- (0, import_vitest.expect)(() => (0, import_xml.xmlToJson)(badXml)).toThrow();
7
- });
8
- (0, import_vitest.test)("empty XML returns empty object", () => {
9
- const empty = "";
10
- const result = (0, import_xml.xmlToJson)(empty);
11
- (0, import_vitest.expect)(result).toEqual({});
12
- });
13
- (0, import_vitest.test)("malformed XML throws in xmlToToon", () => {
14
- const badXml = "<root><unclosed></root>";
15
- (0, import_vitest.expect)(() => (0, import_xml.xmlToToon)(badXml)).toThrow();
16
- });
package/dist/xml.test.cjs DELETED
@@ -1,86 +0,0 @@
1
- "use strict";
2
- var import_vitest = require("vitest");
3
- var import_xml = require("./xml");
4
- (0, import_vitest.describe)("xmlToToon", () => {
5
- (0, import_vitest.it)("converts simple XML to TOON", () => {
6
- const xml = `<root><key>value</key></root>`;
7
- const toon = (0, import_xml.xmlToToon)(xml);
8
- (0, import_vitest.expect)(toon).toContain("root:");
9
- (0, import_vitest.expect)(toon).toContain("key: value");
10
- });
11
- (0, import_vitest.it)("handles attributes", () => {
12
- const xml = `<user id="123"><name>Alice</name></user>`;
13
- const toon = (0, import_xml.xmlToToon)(xml);
14
- (0, import_vitest.expect)(toon).toContain('"@_id": 123');
15
- (0, import_vitest.expect)(toon).toContain("name: Alice");
16
- });
17
- (0, import_vitest.it)("handles nested structures", () => {
18
- const xml = `
19
- <order>
20
- <id>99</id>
21
- <item>
22
- <name>Apple</name>
23
- <price>1.5</price>
24
- </item>
25
- <item>
26
- <name>Banana</name>
27
- <price>2.0</price>
28
- </item>
29
- </order>
30
- `;
31
- const toon = (0, import_xml.xmlToToon)(xml);
32
- (0, import_vitest.expect)(toon).toContain("order:");
33
- (0, import_vitest.expect)(toon).toContain("item[2]");
34
- (0, import_vitest.expect)(toon).toContain("Apple");
35
- (0, import_vitest.expect)(toon).toContain("Banana");
36
- });
37
- (0, import_vitest.it)("allows customizing xml options", () => {
38
- const xml = `<data val="true" />`;
39
- const toon1 = (0, import_xml.xmlToToon)(xml);
40
- const toon2 = (0, import_xml.xmlToToon)(xml, { xmlOptions: { parseAttributeValue: false } });
41
- (0, import_vitest.expect)(toon2).toContain('"true"');
42
- });
43
- });
44
- (0, import_vitest.describe)("Edge Cases", () => {
45
- (0, import_vitest.it)("throws or handles invalid XML gracefully (fast-xml-parser usually returns partial or throws)", () => {
46
- const xml = `<root><unclosed></root>`;
47
- try {
48
- const toon = (0, import_xml.xmlToToon)(xml);
49
- (0, import_vitest.expect)(typeof toon).toBe("string");
50
- } catch (e) {
51
- (0, import_vitest.expect)(e).toBeDefined();
52
- }
53
- });
54
- (0, import_vitest.it)("handles CDATA sections", () => {
55
- const xml = `<msg><![CDATA[<sender>John</sender>]]></msg>`;
56
- const toon = (0, import_xml.xmlToToon)(xml);
57
- (0, import_vitest.expect)(toon).toContain("<sender>John</sender>");
58
- });
59
- (0, import_vitest.it)("handles mixed content (text + child nodes)", () => {
60
- const xml = `<p>some <b>bold</b> text</p>`;
61
- const toon = (0, import_xml.xmlToToon)(xml);
62
- (0, import_vitest.expect)(toon).toContain("#text");
63
- (0, import_vitest.expect)(toon).toContain("b: bold");
64
- });
65
- (0, import_vitest.it)("handles HTML entities", () => {
66
- const xml = `<val>Running &amp; Jumping</val>`;
67
- const toon = (0, import_xml.xmlToToon)(xml);
68
- (0, import_vitest.expect)(toon).toContain("Running & Jumping");
69
- });
70
- (0, import_vitest.it)("handles numeric-like values preserved as strings if configured", () => {
71
- const xml = `<item>007</item>`;
72
- const toon = (0, import_xml.xmlToToon)(xml, { xmlOptions: { parseTagValue: false } });
73
- (0, import_vitest.expect)(toon).toContain('"007"');
74
- });
75
- (0, import_vitest.it)("handles empty elements", () => {
76
- const xml = `<void />`;
77
- const toon = (0, import_xml.xmlToToon)(xml);
78
- (0, import_vitest.expect)(toon).toContain('void: ""');
79
- });
80
- (0, import_vitest.it)("handles namespaces", () => {
81
- const xml = `<ns:root xmlns:ns="http://example.com"><ns:child>val</ns:child></ns:root>`;
82
- const toon = (0, import_xml.xmlToToon)(xml);
83
- (0, import_vitest.expect)(toon).toContain('"ns:root":');
84
- (0, import_vitest.expect)(toon).toContain('"ns:child": val');
85
- });
86
- });