From c8e306d4f4063d0df834bac57f6f596139d7feef Mon Sep 17 00:00:00 2001 From: David Marshall Date: Wed, 19 Apr 2023 18:59:37 -0400 Subject: [PATCH] CC-1523: YAML-JSON conversion --- package-lock.json | 31 +++++++++++++--- package.json | 1 + src/core/config/Categories.json | 2 + src/core/operations/JSONToYAML.mjs | 48 ++++++++++++++++++++++++ src/core/operations/YAMLToJSON.mjs | 53 +++++++++++++++++++++++++++ tests/operations/tests/JSONtoYAML.mjs | 36 ++++++++++++++++++ tests/operations/tests/YAMLtoJSON.mjs | 37 +++++++++++++++++++ 7 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 src/core/operations/JSONToYAML.mjs create mode 100644 src/core/operations/YAMLToJSON.mjs create mode 100644 tests/operations/tests/JSONtoYAML.mjs create mode 100644 tests/operations/tests/YAMLtoJSON.mjs diff --git a/package-lock.json b/package-lock.json index 9b939b88..f5321e73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,6 +92,7 @@ "xmldom": "^0.6.0", "xpath": "0.0.32", "xregexp": "^5.1.1", + "yaml": "^2.2.1", "zlibjs": "^0.3.1" }, "devDependencies": { @@ -4799,6 +4800,15 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/create-ecdh": { "version": "4.0.4", "license": "MIT", @@ -13733,11 +13743,11 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "license": "ISC", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { @@ -17117,6 +17127,14 @@ "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" + }, + "dependencies": { + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } } }, "create-ecdh": { @@ -23150,8 +23168,9 @@ "dev": true }, "yaml": { - "version": "1.10.2", - "dev": true + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==" }, "yargs": { "version": "16.2.0", diff --git a/package.json b/package.json index f5d9a7f9..952077b7 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "xmldom": "^0.6.0", "xpath": "0.0.32", "xregexp": "^5.1.1", + "yaml": "^2.2.1", "zlibjs": "^0.3.1" }, "scripts": { diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index ce2f01f5..bf07bd2e 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -65,6 +65,8 @@ "Parse TLV", "CSV to JSON", "JSON to CSV", + "YAML to JSON", + "JSON to YAML", "Avro to JSON", "CBOR Encode", "CBOR Decode" diff --git a/src/core/operations/JSONToYAML.mjs b/src/core/operations/JSONToYAML.mjs new file mode 100644 index 00000000..9c9a596f --- /dev/null +++ b/src/core/operations/JSONToYAML.mjs @@ -0,0 +1,48 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +import YAML from 'yaml' +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * JSON to YAML operation + */ +class JSONToYAML extends Operation { + + /** + * JSONToYAML constructor + */ + constructor() { + super(); + + this.name = "JSON to YAML"; + this.module = "Default"; + this.description = "Converts JSON data to a YAML."; + this.infoURL = "https://yaml.org/spec/1.2.2/"; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {JSON} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const doc = new YAML.Document(); + try { + doc.contents = JSON.parse(input.replace(/(\w+):/gm, `"$1":`)); + return doc.toString() + } catch (err) { + throw new OperationError("Unable to parse JSON to YAML: " + err.toString()); + } + } + +} + +export default JSONToYAML; diff --git a/src/core/operations/YAMLToJSON.mjs b/src/core/operations/YAMLToJSON.mjs new file mode 100644 index 00000000..c08c5418 --- /dev/null +++ b/src/core/operations/YAMLToJSON.mjs @@ -0,0 +1,53 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +import YAML from 'yaml' +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * YAML To JSON operation + */ +class YAMLToJSON extends Operation { + + /** + * YAMLToJSON constructor + */ + constructor() { + super(); + + this.name = "YAML to JSON"; + this.module = "Default"; + this.description = "Converts YAML data to a JSON based on the definition in RFC 4180."; + this.infoURL = "https://en.wikipedia.org/wiki/JSON"; + this.inputType = "string"; + this.outputType = "JSON"; + this.args = [ + { + name: "Use Spaces", + type: "number", + value: 0 + } + ]; + } + + /** + * @param {YAML} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [spaces] = args; + try { + return JSON.stringify(YAML.parseDocument(input).toJSON(), null, spaces); + } catch (err) { + throw new OperationError("Unable to parse YAML To JSON: " + err.toString()); + } + } + +} + +export default YAMLToJSON; diff --git a/tests/operations/tests/JSONtoYAML.mjs b/tests/operations/tests/JSONtoYAML.mjs new file mode 100644 index 00000000..c289ae29 --- /dev/null +++ b/tests/operations/tests/JSONtoYAML.mjs @@ -0,0 +1,36 @@ +/** + * JSON to YAML tests. + * + * @author mshwed [m@ttshwed.com] + * + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +const EXPECTED_YAML = "version: 1.0.0\ndependencies:\n yaml: ^1.10.0\npackage:\n exclude:\n - .idea/**\n - .gitignore\n"; + +TestRegister.addTests([ + { + name: "JSON to YAML: no spacing", + input: JSON.stringify({"version":"1.0.0","dependencies":{"yaml":"^1.10.0"},"package":{"exclude":[".idea/**",".gitignore"]}}), + expectedOutput: EXPECTED_YAML, + recipeConfig: [ + { + op: "JSON to YAML", + args: [] + }, + ], + }, + { + name: "JSON to YAML: with spacing", + input: JSON.stringify({"version":"1.0.0","dependencies":{"yaml":"^1.10.0"},"package":{"exclude":[".idea/**",".gitignore"]}}, null, 4), + expectedOutput: EXPECTED_YAML, + recipeConfig: [ + { + op: "JSON to YAML", + args: [] + }, + ], + } +]); diff --git a/tests/operations/tests/YAMLtoJSON.mjs b/tests/operations/tests/YAMLtoJSON.mjs new file mode 100644 index 00000000..e8528180 --- /dev/null +++ b/tests/operations/tests/YAMLtoJSON.mjs @@ -0,0 +1,37 @@ +/** + * YAML to JSON tests. + * + * @author mshwed [m@ttshwed.com] + * + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +const EXPECTED_JSON_SINGLE = '{"version":"1.0.0","dependencies":{"yaml":"^1.10.0"},"package":{"exclude":[".idea/**",".gitignore"]}}'; +const EXPECTED_JSON_SPACED_SINGLE = '{\n"version": "1.0.0",\n"dependencies": {\n "yaml": "^1.10.0"\n },\n"package": {\n "exclude": [\n ".idea/**",\n ".gitignore"\n ]\n }\n}'; + +TestRegister.addTests([ + { + name: "YAML to JSON: simple", + input: "version: 1.0.0\ndependencies:\n yaml: ^1.10.0\npackage:\n exclude:\n - .idea/**\n - .gitignore\n", + expectedOutput: EXPECTED_JSON_SINGLE, + recipeConfig: [ + { + op: "YAML to JSON", + args: [0] + }, + ], + }, + { + name: "YAML to JSON: spacing", + input: "version: 1.0.0\ndependencies:\n yaml: ^1.10.0\npackage:\n exclude:\n - .idea/**\n - .gitignore\n", + expectedOutput: EXPECTED_JSON_SPACED_SINGLE, + recipeConfig: [ + { + op: "YAML to JSON", + args: [2] + }, + ], + } +]);