diff --git a/src/core/operations/ParseURI.mjs b/src/core/operations/ParseURI.mjs
new file mode 100644
index 00000000..a272ef53
--- /dev/null
+++ b/src/core/operations/ParseURI.mjs
@@ -0,0 +1,69 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import url from "url";
+
+/**
+ * Parse URI operation
+ */
+class ParseURI extends Operation {
+
+ /**
+ * ParseURI constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Parse URI";
+ this.module = "URL";
+ this.description = "Pretty prints complicated Uniform Resource Identifier (URI) strings for ease of reading. Particularly useful for Uniform Resource Locators (URLs) with a lot of arguments.";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const uri = url.parse(input, true);
+
+ let output = "";
+
+ if (uri.protocol) output += "Protocol:\t" + uri.protocol + "\n";
+ if (uri.auth) output += "Auth:\t\t" + uri.auth + "\n";
+ if (uri.hostname) output += "Hostname:\t" + uri.hostname + "\n";
+ if (uri.port) output += "Port:\t\t" + uri.port + "\n";
+ if (uri.pathname) output += "Path name:\t" + uri.pathname + "\n";
+ if (uri.query) {
+ const keys = Object.keys(uri.query);
+ let padding = 0;
+
+ keys.forEach(k => {
+ padding = (k.length > padding) ? k.length : padding;
+ });
+
+ output += "Arguments:\n";
+ for (const key in uri.query) {
+ output += "\t" + key.padEnd(padding, " ");
+ if (uri.query[key].length) {
+ output += " = " + uri.query[key] + "\n";
+ } else {
+ output += "\n";
+ }
+ }
+ }
+ if (uri.hash) output += "Hash:\t\t" + uri.hash + "\n";
+
+ return output;
+ }
+
+}
+
+export default ParseURI;
diff --git a/src/core/operations/URLDecode.mjs b/src/core/operations/URLDecode.mjs
new file mode 100644
index 00000000..1d4555b0
--- /dev/null
+++ b/src/core/operations/URLDecode.mjs
@@ -0,0 +1,44 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+
+/**
+ * URL Decode operation
+ */
+class URLDecode extends Operation {
+
+ /**
+ * URLDecode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "URL Decode";
+ this.module = "URL";
+ this.description = "Converts URI/URL percent-encoded characters back to their raw values.
e.g. %3d
becomes =
";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const data = input.replace(/\+/g, "%20");
+ try {
+ return decodeURIComponent(data);
+ } catch (err) {
+ return unescape(data);
+ }
+ }
+
+}
+
+export default URLDecode;
diff --git a/src/core/operations/URLEncode.mjs b/src/core/operations/URLEncode.mjs
new file mode 100644
index 00000000..b1637594
--- /dev/null
+++ b/src/core/operations/URLEncode.mjs
@@ -0,0 +1,68 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+
+/**
+ * URL Encode operation
+ */
+class URLEncode extends Operation {
+
+ /**
+ * URLEncode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "URL Encode";
+ this.module = "URL";
+ this.description = "Encodes problematic characters into percent-encoding, a format supported by URIs/URLs.
e.g. =
becomes %3d
";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Encode all special chars",
+ "type": "boolean",
+ "value": false
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const encodeAll = args[0];
+ return encodeAll ? this.encodeAllChars(input) : encodeURI(input);
+ }
+
+ /**
+ * Encode characters in URL outside of encodeURI() function spec
+ *
+ * @param {string} str
+ * @returns {string}
+ */
+ encodeAllChars (str) {
+ //TODO Do this programatically
+ return encodeURIComponent(str)
+ .replace(/!/g, "%21")
+ .replace(/#/g, "%23")
+ .replace(/'/g, "%27")
+ .replace(/\(/g, "%28")
+ .replace(/\)/g, "%29")
+ .replace(/\*/g, "%2A")
+ .replace(/-/g, "%2D")
+ .replace(/\./g, "%2E")
+ .replace(/_/g, "%5F")
+ .replace(/~/g, "%7E");
+ }
+
+}
+
+
+export default URLEncode;
diff --git a/src/core/operations/legacy/URL.js b/src/core/operations/legacy/URL.js
deleted file mode 100755
index 2f30c952..00000000
--- a/src/core/operations/legacy/URL.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/* globals unescape */
-import url from "url";
-
-
-/**
- * URL operations.
- * Namespace is appended with an underscore to prevent overwriting the global URL object.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @namespace
- */
-const URL_ = {
-
- /**
- * @constant
- * @default
- */
- ENCODE_ALL: false,
-
- /**
- * URL Encode operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- runTo: function(input, args) {
- const encodeAll = args[0];
- return encodeAll ? URL_._encodeAllChars(input) : encodeURI(input);
- },
-
-
- /**
- * URL Decode operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- runFrom: function(input, args) {
- const data = input.replace(/\+/g, "%20");
- try {
- return decodeURIComponent(data);
- } catch (err) {
- return unescape(data);
- }
- },
-
-
- /**
- * Parse URI operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- runParse: function(input, args) {
- const uri = url.parse(input, true);
-
- let output = "";
-
- if (uri.protocol) output += "Protocol:\t" + uri.protocol + "\n";
- if (uri.auth) output += "Auth:\t\t" + uri.auth + "\n";
- if (uri.hostname) output += "Hostname:\t" + uri.hostname + "\n";
- if (uri.port) output += "Port:\t\t" + uri.port + "\n";
- if (uri.pathname) output += "Path name:\t" + uri.pathname + "\n";
- if (uri.query) {
- let keys = Object.keys(uri.query),
- padding = 0;
-
- keys.forEach(k => {
- padding = (k.length > padding) ? k.length : padding;
- });
-
- output += "Arguments:\n";
- for (let key in uri.query) {
- output += "\t" + key.padEnd(padding, " ");
- if (uri.query[key].length) {
- output += " = " + uri.query[key] + "\n";
- } else {
- output += "\n";
- }
- }
- }
- if (uri.hash) output += "Hash:\t\t" + uri.hash + "\n";
-
- return output;
- },
-
-
- /**
- * URL encodes additional special characters beyond the standard set.
- *
- * @private
- * @param {string} str
- * @returns {string}
- */
- _encodeAllChars: function(str) {
- //TODO Do this programatically
- return encodeURIComponent(str)
- .replace(/!/g, "%21")
- .replace(/#/g, "%23")
- .replace(/'/g, "%27")
- .replace(/\(/g, "%28")
- .replace(/\)/g, "%29")
- .replace(/\*/g, "%2A")
- .replace(/-/g, "%2D")
- .replace(/\./g, "%2E")
- .replace(/_/g, "%5F")
- .replace(/~/g, "%7E");
- },
-
-};
-
-export default URL_;