UNPKG

typesxml

Version:

Open source XML library written in TypeScript

188 lines 9.19 kB
"use strict"; /******************************************************************************* * Copyright (c) 2023-2026 Maxprograms. * * This program and the accompanying materials * are made available under the terms of the Eclipse License 1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-v10.html * * Contributors: * Maxprograms - initial API and implementation *******************************************************************************/ Object.defineProperty(exports, "__esModule", { value: true }); const node_fs_1 = require("node:fs"); const node_os_1 = require("node:os"); const node_path_1 = require("node:path"); const node_stream_1 = require("node:stream"); const DOMBuilder_js_1 = require("../DOMBuilder.js"); const SAXParser_js_1 = require("../SAXParser.js"); const JsonConversion_js_1 = require("../json/JsonConversion.js"); async function runJsonConversionTests() { const samples = [ '<?xml version="1.0" encoding="UTF-8"?>\n' + '<!--Before root--><!--Second comment-->' + '<!DOCTYPE note [' + '<!ENTITY writer "John Doe">' + '<!ELEMENT note ANY>' + '<!ELEMENT body ANY>' + '<!ELEMENT h:header ANY>' + '<!ELEMENT child ANY>' + '<!ELEMENT empty EMPTY>' + ']>' + '<note xmlns:h="http://example.com/h" category="memo">' + '<h:header><![CDATA[Agenda]]></h:header>' + '<body>Don\'t forget &writer; on Monday<?pi instructions?></body>' + '<empty />' + '</note>', '<?xml version="1.1" encoding="UTF-8" standalone="yes"?>\n' + '<root attr1="value1" attr2="value2">' + 'Text node<child>Inner</child>' + '<child xml:lang="en">More text</child>' + '<![CDATA[raw <content>]]>' + '<?processing data?>' + '<!--After content-->' + '</root>' ]; for (let index = 0; index < samples.length; index++) { const label = `Sample ${index + 1}`; await assertStructuredRoundTrip(samples[index], label); } await assertPlainObjectRoundTrip(); await assertRootInference(); await assertFileConversions(samples[0]); await assertStreamConversions(samples[1]); console.log("JSON conversion tests passed."); } async function assertStructuredRoundTrip(xmlText, label) { const originalDocument = parseXml(xmlText); const simpleJson = (0, JsonConversion_js_1.xmlStringToJsonObject)(xmlText); if (typeof simpleJson !== "object" || simpleJson === null || Array.isArray(simpleJson)) { throw new Error(`Expected simple conversion to yield object JSON for ${label}`); } if ("rootName" in simpleJson || "prolog" in simpleJson || "doctype" in simpleJson) { throw new Error(`Simple conversion leaked document metadata for ${label}`); } const jsonDocument = (0, JsonConversion_js_1.xmlStringToJsonObject)(xmlText, { mode: "roundtrip" }); if (jsonDocument.rootName !== originalDocument.getRoot()?.getName()) { throw new Error(`Root name mismatch for ${label}`); } const rebuiltDocument = (0, JsonConversion_js_1.jsonObjectToXmlDocument)(jsonDocument); if (!originalDocument.equals(rebuiltDocument)) { throw new Error(`XML -> JSON -> XML comparison failed for ${label}`); } if (jsonDocument.prolog && jsonDocument.prolog.length === 0) { throw new Error(`Expected prolog entries for ${label}`); } if (jsonDocument.declaration && jsonDocument.declaration.version === undefined) { throw new Error(`Missing declaration details for ${label}`); } } async function assertPlainObjectRoundTrip() { const source = { library: "painters", books: ["DaVinci", "VanGogh", "Rubens"], prices: [13000, 5000, 20000] }; const document = (0, JsonConversion_js_1.jsonObjectToXmlDocument)(source, "libraryCatalog"); const simpleRoundTrip = (0, JsonConversion_js_1.xmlDocumentToJsonObject)(document); if (typeof simpleRoundTrip !== "object" || simpleRoundTrip === null || Array.isArray(simpleRoundTrip)) { throw new Error("Simple round-trip should yield an object"); } if ("rootName" in simpleRoundTrip) { throw new Error("Simple round-trip should not include root metadata"); } const roundTrip = (0, JsonConversion_js_1.xmlDocumentToJsonObject)(document, { mode: "roundtrip" }); const root = roundTrip.root; if (!root || Array.isArray(root) || typeof root !== "object") { throw new Error("Unexpected JSON structure for plain object round-trip"); } const rootObject = root; if (rootObject.library !== "painters") { throw new Error("Library value mismatch after round-trip"); } const booksEntry = rootObject.books; if (!Array.isArray(booksEntry) || booksEntry.some((item) => typeof item !== "string") || booksEntry.length !== 3) { throw new Error("Books array mismatch after round-trip"); } const pricesEntry = rootObject.prices; if (!Array.isArray(pricesEntry) || pricesEntry.some((entry) => typeof entry !== "string")) { throw new Error("Prices array expected string representations"); } } async function assertRootInference() { const source = { library: { books: ["DaVinci", "VanGogh", "Rubens"] } }; const document = (0, JsonConversion_js_1.jsonObjectToXmlDocument)(source); const root = document.getRoot(); if (!root || root.getName() !== "library") { throw new Error("Expected root element name to be inferred from single property"); } const roundTripJson = (0, JsonConversion_js_1.xmlDocumentToJsonObject)(document); if (typeof roundTripJson !== "object" || roundTripJson === null || Array.isArray(roundTripJson)) { throw new Error("Round-tripped JSON should remain an object"); } if (!("library" in roundTripJson)) { throw new Error("Round-tripped JSON missing inferred property"); } } async function assertFileConversions(xmlText) { const tempDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "typesxml-json-files-")); const xmlInputPath = (0, node_path_1.join)(tempDir, "input.xml"); (0, node_fs_1.writeFileSync)(xmlInputPath, xmlText, "utf8"); const jsonPath = (0, node_path_1.join)(tempDir, "output.json"); await (0, JsonConversion_js_1.xmlFileToJsonFile)(xmlInputPath, jsonPath, "utf8", 2, "utf8", { mode: "roundtrip" }); const parsedJson = JSON.parse((0, node_fs_1.readFileSync)(jsonPath, "utf8")); const rebuiltDocument = (0, JsonConversion_js_1.jsonObjectToXmlDocument)(parsedJson); const originalDocument = parseXml(xmlText); if (!originalDocument.equals(rebuiltDocument)) { throw new Error("File-based XML -> JSON -> XML comparison failed"); } const rebuiltXmlPath = (0, node_path_1.join)(tempDir, "roundtrip.xml"); await (0, JsonConversion_js_1.jsonFileToXmlFile)(jsonPath, rebuiltXmlPath); const roundTripDocument = parseXml((0, node_fs_1.readFileSync)(rebuiltXmlPath, "utf8")); if (!originalDocument.equals(roundTripDocument)) { throw new Error("JSON file -> XML file comparison failed"); } const jsonStringPath = (0, node_path_1.join)(tempDir, "string.json"); await (0, JsonConversion_js_1.xmlStringToJsonFile)(xmlText, jsonStringPath, { mode: "roundtrip" }); const jsonDocument = JSON.parse((0, node_fs_1.readFileSync)(jsonStringPath, "utf8")); await (0, JsonConversion_js_1.jsonObjectToXmlFile)(jsonDocument, (0, node_path_1.join)(tempDir, "from-string.xml")); (0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true }); } async function assertStreamConversions(xmlText) { const xmlDocument = parseXml(xmlText); const xmlStream = node_stream_1.Readable.from([xmlText]); const jsonFromStream = await (0, JsonConversion_js_1.xmlStreamToJsonObject)(xmlStream, { mode: "roundtrip" }); const rebuiltFromStream = (0, JsonConversion_js_1.jsonObjectToXmlDocument)(jsonFromStream); if (!xmlDocument.equals(rebuiltFromStream)) { throw new Error("XML stream round-trip failed"); } const jsonText = JSON.stringify(jsonFromStream); const jsonStream = node_stream_1.Readable.from([jsonText]); const documentFromJsonStream = await (0, JsonConversion_js_1.jsonStreamToXmlDocument)(jsonStream); if (!xmlDocument.equals(documentFromJsonStream)) { throw new Error("JSON stream round-trip failed"); } } function parseXml(xmlText) { const parser = new SAXParser_js_1.SAXParser(); const builder = new DOMBuilder_js_1.DOMBuilder(); builder.initialize(); parser.setContentHandler(builder); parser.setValidating(false); parser.parseString(xmlText); const document = builder.getDocument(); if (!document) { throw new Error("Unable to parse XML text"); } return document; } runJsonConversionTests().catch((error) => { console.error("JSON conversion tests failed:", error); process.exitCode = 1; }); //# sourceMappingURL=JsonConversionTest.js.map