toon-parser 2.0.0 → 2.1.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.
Files changed (52) hide show
  1. package/README.md +36 -6
  2. package/dist/cjs.test.cjs +46 -0
  3. package/dist/complex.test.cjs +35 -0
  4. package/dist/coverage.test.cjs +49 -0
  5. package/dist/csv.cjs +150 -0
  6. package/dist/csv.d.ts +20 -0
  7. package/dist/csv.d.ts.map +1 -0
  8. package/dist/csv.edge.test.cjs +20 -0
  9. package/dist/csv.js +142 -0
  10. package/dist/csv.js.map +1 -0
  11. package/dist/csv.test.cjs +27 -0
  12. package/dist/edgecases.test.cjs +23 -0
  13. package/dist/extra.test.cjs +19 -0
  14. package/dist/html.cjs +176 -0
  15. package/dist/html.d.ts +17 -0
  16. package/dist/html.d.ts.map +1 -0
  17. package/dist/html.edge.test.cjs +16 -0
  18. package/dist/html.js +181 -0
  19. package/dist/html.js.map +1 -0
  20. package/dist/html.test.cjs +28 -0
  21. package/dist/index.cjs +9 -1
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +4 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.test.cjs +59 -0
  27. package/dist/limits.test.cjs +21 -0
  28. package/dist/log.cjs +57 -0
  29. package/dist/log.clf.redos.test.cjs +15 -0
  30. package/dist/log.d.ts +9 -0
  31. package/dist/log.d.ts.map +1 -0
  32. package/dist/log.js +36 -0
  33. package/dist/log.js.map +1 -0
  34. package/dist/log.test.cjs +20 -0
  35. package/dist/property.test.cjs +60 -0
  36. package/dist/smoke.test.cjs +132 -0
  37. package/dist/snapshots.test.cjs +21 -0
  38. package/dist/tabular.test.cjs +21 -0
  39. package/dist/url.cjs +72 -0
  40. package/dist/url.d.ts +3 -0
  41. package/dist/url.d.ts.map +1 -0
  42. package/dist/url.js +57 -0
  43. package/dist/url.js.map +1 -0
  44. package/dist/url.test.cjs +25 -0
  45. package/dist/xml.cjs +22 -0
  46. package/dist/xml.d.ts +1 -0
  47. package/dist/xml.d.ts.map +1 -1
  48. package/dist/xml.edge.test.cjs +16 -0
  49. package/dist/xml.js +22 -1
  50. package/dist/xml.js.map +1 -1
  51. package/dist/xml.test.cjs +86 -0
  52. package/package.json +14 -6
package/dist/xml.cjs CHANGED
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var xml_exports = {};
20
20
  __export(xml_exports, {
21
+ xmlToJson: () => xmlToJson,
21
22
  xmlToToon: () => xmlToToon
22
23
  });
23
24
  module.exports = __toCommonJS(xml_exports);
@@ -34,6 +35,14 @@ const DEFAULT_XML_OPTIONS = {
34
35
  // but users can override this via xmlOptions.
35
36
  };
36
37
  function xmlToToon(xml, options = {}) {
38
+ const trimmed = xml.trim();
39
+ if (!trimmed) {
40
+ return (0, import_index.jsonToToon)({}, options);
41
+ }
42
+ const validation = import_fast_xml_parser.XMLValidator.validate(xml);
43
+ if (validation !== true) {
44
+ throw new Error("Malformed XML");
45
+ }
37
46
  const parser = new import_fast_xml_parser.XMLParser({
38
47
  ...DEFAULT_XML_OPTIONS,
39
48
  ...options.xmlOptions
@@ -41,7 +50,20 @@ function xmlToToon(xml, options = {}) {
41
50
  const jsonObj = parser.parse(xml);
42
51
  return (0, import_index.jsonToToon)(jsonObj, options);
43
52
  }
53
+ function xmlToJson(xml, options = {}) {
54
+ if (!xml.trim()) return {};
55
+ const validation = import_fast_xml_parser.XMLValidator.validate(xml);
56
+ if (validation !== true) {
57
+ throw new Error("Malformed XML");
58
+ }
59
+ const parser = new import_fast_xml_parser.XMLParser({
60
+ ...DEFAULT_XML_OPTIONS,
61
+ ...options.xmlOptions
62
+ });
63
+ return parser.parse(xml);
64
+ }
44
65
  // Annotate the CommonJS export names for ESM import in node:
45
66
  0 && (module.exports = {
67
+ xmlToJson,
46
68
  xmlToToon
47
69
  });
package/dist/xml.d.ts CHANGED
@@ -21,4 +21,5 @@ export interface XmlToToonOptions extends JsonToToonOptions {
21
21
  * @returns The resulting TOON string.
22
22
  */
23
23
  export declare function xmlToToon(xml: string, options?: XmlToToonOptions): string;
24
+ export declare function xmlToJson(xml: string, options?: XmlToToonOptions): unknown;
24
25
  //# sourceMappingURL=xml.d.ts.map
package/dist/xml.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../src/xml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAc,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;CAClC;AAaD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAQ7E"}
1
+ {"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../src/xml.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAc,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;CAClC;AAaD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAkB7E;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAc9E"}
@@ -0,0 +1,16 @@
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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { XMLParser } from 'fast-xml-parser';
1
+ import { XMLParser, XMLValidator } from 'fast-xml-parser';
2
2
  import { jsonToToon } from './index.js';
3
3
  const DEFAULT_XML_OPTIONS = {
4
4
  ignoreAttributes: false,
@@ -18,6 +18,14 @@ const DEFAULT_XML_OPTIONS = {
18
18
  * @returns The resulting TOON string.
19
19
  */
20
20
  export function xmlToToon(xml, options = {}) {
21
+ const trimmed = xml.trim();
22
+ if (!trimmed) {
23
+ return jsonToToon({}, options);
24
+ }
25
+ const validation = XMLValidator.validate(xml);
26
+ if (validation !== true) {
27
+ throw new Error('Malformed XML');
28
+ }
21
29
  const parser = new XMLParser({
22
30
  ...DEFAULT_XML_OPTIONS,
23
31
  ...options.xmlOptions
@@ -25,4 +33,17 @@ export function xmlToToon(xml, options = {}) {
25
33
  const jsonObj = parser.parse(xml);
26
34
  return jsonToToon(jsonObj, options);
27
35
  }
36
+ export function xmlToJson(xml, options = {}) {
37
+ if (!xml.trim())
38
+ return {};
39
+ const validation = XMLValidator.validate(xml);
40
+ if (validation !== true) {
41
+ throw new Error('Malformed XML');
42
+ }
43
+ const parser = new XMLParser({
44
+ ...DEFAULT_XML_OPTIONS,
45
+ ...options.xmlOptions
46
+ });
47
+ return parser.parse(xml);
48
+ }
28
49
  //# sourceMappingURL=xml.js.map
package/dist/xml.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"xml.js","sourceRoot":"","sources":["../src/xml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAqB,MAAM,YAAY,CAAC;AAgB3D,MAAM,mBAAmB,GAAwB;IAC/C,gBAAgB,EAAE,KAAK;IACvB,mBAAmB,EAAE,IAAI;IACzB,mBAAmB,EAAE,IAAI;IACzB,iBAAiB,EAAE,IAAI;IACvB,gEAAgE;IAChE,4CAA4C;IAC5C,iFAAiF;IACjF,8CAA8C;CAC/C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,UAA4B,EAAE;IACnE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,GAAG,mBAAmB;QACtB,GAAG,OAAO,CAAC,UAAU;KACtB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"xml.js","sourceRoot":"","sources":["../src/xml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAc,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAqB,MAAM,YAAY,CAAC;AAgB3D,MAAM,mBAAmB,GAAwB;IAC/C,gBAAgB,EAAE,KAAK;IACvB,mBAAmB,EAAE,IAAI;IACzB,mBAAmB,EAAE,IAAI;IACzB,iBAAiB,EAAE,IAAI;IACvB,gEAAgE;IAChE,4CAA4C;IAC5C,iFAAiF;IACjF,8CAA8C;CAC/C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,UAA4B,EAAE;IACnE,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,GAAG,mBAAmB;QACtB,GAAG,OAAO,CAAC,UAAU;KACtB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,UAA4B,EAAE;IACnE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IAE3B,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,GAAG,mBAAmB;QACtB,GAAG,OAAO,CAAC,UAAU;KACtB,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,86 @@
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
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toon-parser",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Safe JSON <-> TOON encoder/decoder with strict validation.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -20,11 +20,15 @@
20
20
  "typecheck": "tsc -p tsconfig.json --noEmit",
21
21
  "build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
22
22
  "build:js": "tsc -p tsconfig.json",
23
- "build:cjs": "esbuild src/index.ts src/xml.ts --format=cjs --outdir=dist/cjs --platform=node && node ./scripts/build-copy-cjs-output.js",
23
+ "build:cjs": "esbuild src/**/*.ts --format=cjs --outdir=dist/cjs --platform=node && node ./scripts/build-copy-cjs-output.js",
24
24
  "build": "npm run typecheck && npm run build:types && npm run build:js && npm run build:cjs",
25
25
  "clean": "rimraf dist",
26
26
  "clean:node": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
27
- "prepare": "npm run build"
27
+ "prepare": "npm run build",
28
+ "lint": "eslint . --ext .ts,.tsx",
29
+ "verify-docs": "node scripts/verify-docs.js",
30
+ "test": "vitest --run",
31
+ "coverage": "vitest --run --coverage"
28
32
  },
29
33
  "keywords": [
30
34
  "json",
@@ -47,12 +51,16 @@
47
51
  "sideEffects": false,
48
52
  "devDependencies": {
49
53
  "fast-check": "^4.3.0",
50
- "rimraf": "^6.0.0"
54
+ "rimraf": "^6.0.0",
55
+ "eslint": "^9.0.0",
56
+ "@typescript-eslint/parser": "^8.48.1",
57
+ "@typescript-eslint/eslint-plugin": "^8.48.1"
51
58
  },
52
59
  "engines": {
53
60
  "node": ">=18"
54
61
  },
55
62
  "dependencies": {
56
- "fast-xml-parser": "^5.3.2"
63
+ "fast-xml-parser": "^5.3.2",
64
+ "node-html-parser": "^7.0.1"
57
65
  }
58
- }
66
+ }