diff --git a/src/core/operations/CSSBeautify.mjs b/src/core/operations/CSSBeautify.mjs new file mode 100644 index 00000000..d9835550 --- /dev/null +++ b/src/core/operations/CSSBeautify.mjs @@ -0,0 +1,47 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * CSS Beautify operation + */ +class CSSBeautify extends Operation { + + /** + * CSSBeautify constructor + */ + constructor() { + super(); + + this.name = "CSS Beautify"; + this.module = "Code"; + this.description = "Indents and prettifies Cascading Style Sheets (CSS) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Indent string", + "type": "binaryShortString", + "value": "\\t" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const indentStr = args[0]; + return vkbeautify.css(input, indentStr); + } + +} + +export default CSSBeautify; diff --git a/src/core/operations/CSSMinify.mjs b/src/core/operations/CSSMinify.mjs new file mode 100644 index 00000000..2d489edc --- /dev/null +++ b/src/core/operations/CSSMinify.mjs @@ -0,0 +1,47 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * CSS Minify operation + */ +class CSSMinify extends Operation { + + /** + * CSSMinify constructor + */ + constructor() { + super(); + + this.name = "CSS Minify"; + this.module = "Code"; + this.description = "Compresses Cascading Style Sheets (CSS) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Preserve comments", + "type": "boolean", + "value": false + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const preserveComments = args[0]; + return vkbeautify.cssmin(input, preserveComments); + } + +} + +export default CSSMinify; diff --git a/src/core/operations/CSSSelector.mjs b/src/core/operations/CSSSelector.mjs new file mode 100644 index 00000000..5894066e --- /dev/null +++ b/src/core/operations/CSSSelector.mjs @@ -0,0 +1,88 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import nwmatcher from "nwmatcher"; +import Operation from "../Operation"; + +/** + * CSS selector operation + */ +class CSSSelector extends Operation { + + /** + * CSSSelector constructor + */ + constructor() { + super(); + + this.name = "CSS selector"; + this.module = "Code"; + this.description = "Extract information from an HTML document with a CSS selector"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "CSS selector", + "type": "string", + "value": "" + }, + { + "name": "Delimiter", + "type": "binaryShortString", + "value": "\\n" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [query, delimiter] = args, + parser = new DOMParser(); + let dom, + result; + + if (!query.length || !input.length) { + return ""; + } + + try { + dom = parser.parseFromString(input); + } catch (err) { + return "Invalid input HTML."; + } + + try { + const matcher = nwmatcher({document: dom}); + result = matcher.select(query, dom); + } catch (err) { + return "Invalid CSS Selector. Details:\n" + err.message; + } + + const nodeToString = function(node) { + return node.toString(); + /* xmldom does not return the outerHTML value. + switch (node.nodeType) { + case node.ELEMENT_NODE: return node.outerHTML; + case node.ATTRIBUTE_NODE: return node.value; + case node.TEXT_NODE: return node.wholeText; + case node.COMMENT_NODE: return node.data; + case node.DOCUMENT_NODE: return node.outerHTML; + default: throw new Error("Unknown Node Type: " + node.nodeType); + }*/ + }; + + return result + .map(nodeToString) + .join(delimiter); + } + +} + +export default CSSSelector; diff --git a/src/core/operations/Diff.mjs b/src/core/operations/Diff.mjs index 6627cf6e..90697140 100644 --- a/src/core/operations/Diff.mjs +++ b/src/core/operations/Diff.mjs @@ -6,7 +6,7 @@ import Operation from "../Operation"; import Utils from "../Utils"; -import * as JsDiff from "diff"; +import JsDiff from "diff"; import OperationError from "../errors/OperationError"; /** diff --git a/src/core/operations/JPathExpression.mjs b/src/core/operations/JPathExpression.mjs new file mode 100644 index 00000000..21b4284f --- /dev/null +++ b/src/core/operations/JPathExpression.mjs @@ -0,0 +1,68 @@ +/** + * @author Matt C (matt@artemisbot.uk) + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import jpath from "jsonpath"; +import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; + +/** + * JPath expression operation + */ +class JPathExpression extends Operation { + + /** + * JPathExpression constructor + */ + constructor() { + super(); + + this.name = "JPath expression"; + this.module = "Code"; + this.description = "Extract information from a JSON object with a JPath query."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Query", + "type": "string", + "value": "" + }, + { + "name": "Result delimiter", + "type": "binaryShortString", + "value": "\\n" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [query, delimiter] = args; + let results, + obj; + + try { + obj = JSON.parse(input); + } catch (err) { + throw new OperationError(`Invalid input JSON: ${err.message}`); + } + + try { + results = jpath.query(obj, query); + } catch (err) { + throw new OperationError(`Invalid JPath expression: ${err.message}`); + } + + return results.map(result => JSON.stringify(result)).join(delimiter); + } + +} + +export default JPathExpression; diff --git a/src/core/operations/JSONBeautify.mjs b/src/core/operations/JSONBeautify.mjs new file mode 100644 index 00000000..15fb7f58 --- /dev/null +++ b/src/core/operations/JSONBeautify.mjs @@ -0,0 +1,48 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * JSON Beautify operation + */ +class JSONBeautify extends Operation { + + /** + * JSONBeautify constructor + */ + constructor() { + super(); + + this.name = "JSON Beautify"; + this.module = "Code"; + this.description = "Indents and prettifies JavaScript Object Notation (JSON) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Indent string", + "type": "binaryShortString", + "value": "\\t" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const indentStr = args[0]; + if (!input) return ""; + return vkbeautify.json(input, indentStr); + } + +} + +export default JSONBeautify; diff --git a/src/core/operations/JSONMinify.mjs b/src/core/operations/JSONMinify.mjs new file mode 100644 index 00000000..ca594397 --- /dev/null +++ b/src/core/operations/JSONMinify.mjs @@ -0,0 +1,41 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * JSON Minify operation + */ +class JSONMinify extends Operation { + + /** + * JSONMinify constructor + */ + constructor() { + super(); + + this.name = "JSON Minify"; + this.module = "Code"; + this.description = "Compresses JavaScript Object Notation (JSON) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + if (!input) return ""; + return vkbeautify.jsonmin(input); + } + +} + +export default JSONMinify; diff --git a/src/core/operations/SQLBeautify.mjs b/src/core/operations/SQLBeautify.mjs new file mode 100644 index 00000000..1862972a --- /dev/null +++ b/src/core/operations/SQLBeautify.mjs @@ -0,0 +1,47 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * SQL Beautify operation + */ +class SQLBeautify extends Operation { + + /** + * SQLBeautify constructor + */ + constructor() { + super(); + + this.name = "SQL Beautify"; + this.module = "Code"; + this.description = "Indents and prettifies Structured Query Language (SQL) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Indent string", + "type": "binaryShortString", + "value": "\\t" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const indentStr = args[0]; + return vkbeautify.sql(input, indentStr); + } + +} + +export default SQLBeautify; diff --git a/src/core/operations/SQLMinify.mjs b/src/core/operations/SQLMinify.mjs new file mode 100644 index 00000000..d81e29ad --- /dev/null +++ b/src/core/operations/SQLMinify.mjs @@ -0,0 +1,40 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * SQL Minify operation + */ +class SQLMinify extends Operation { + + /** + * SQLMinify constructor + */ + constructor() { + super(); + + this.name = "SQL Minify"; + this.module = "Code"; + this.description = "Compresses Structured Query Language (SQL) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + return vkbeautify.sqlmin(input); + } + +} + +export default SQLMinify; diff --git a/src/core/operations/XMLBeautify.mjs b/src/core/operations/XMLBeautify.mjs new file mode 100644 index 00000000..4c059411 --- /dev/null +++ b/src/core/operations/XMLBeautify.mjs @@ -0,0 +1,47 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * XML Beautify operation + */ +class XMLBeautify extends Operation { + + /** + * XMLBeautify constructor + */ + constructor() { + super(); + + this.name = "XML Beautify"; + this.module = "Code"; + this.description = "Indents and prettifies eXtensible Markup Language (XML) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Indent string", + "type": "binaryShortString", + "value": "\\t" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const indentStr = args[0]; + return vkbeautify.xml(input, indentStr); + } + +} + +export default XMLBeautify; diff --git a/src/core/operations/XMLMinify.mjs b/src/core/operations/XMLMinify.mjs new file mode 100644 index 00000000..9c4fb2f6 --- /dev/null +++ b/src/core/operations/XMLMinify.mjs @@ -0,0 +1,47 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import vkbeautify from "vkbeautify"; +import Operation from "../Operation"; + +/** + * XML Minify operation + */ +class XMLMinify extends Operation { + + /** + * XMLMinify constructor + */ + constructor() { + super(); + + this.name = "XML Minify"; + this.module = "Code"; + this.description = "Compresses eXtensible Markup Language (XML) code."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Preserve comments", + "type": "boolean", + "value": false + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const preserveComments = args[0]; + return vkbeautify.xmlmin(input, preserveComments); + } + +} + +export default XMLMinify; diff --git a/src/core/operations/XPathExpression.mjs b/src/core/operations/XPathExpression.mjs new file mode 100644 index 00000000..4e83aff1 --- /dev/null +++ b/src/core/operations/XPathExpression.mjs @@ -0,0 +1,72 @@ +/** + * @author Mikescher (https://github.com/Mikescher | https://mikescher.com) + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import xpath from "xpath"; +import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; + +/** + * XPath expression operation + */ +class XPathExpression extends Operation { + + /** + * XPathExpression constructor + */ + constructor() { + super(); + + this.name = "XPath expression"; + this.module = "Code"; + this.description = "Extract information from an XML document with an XPath query"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "XPath", + "type": "string", + "value": "" + }, + { + "name": "Result delimiter", + "type": "binaryShortString", + "value": "\\n" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [query, delimiter] = args; + + let doc; + try { + doc = new DOMParser().parseFromString(input, "application/xml"); + } catch (err) { + throw new OperationError("Invalid input XML."); + } + + let nodes; + try { + nodes = xpath.select(query, doc); + } catch (err) { + throw new OperationError(`Invalid XPath. Details:\n${err.message}.`); + } + + const nodeToString = function(node) { + return node.toString(); + }; + + return nodes.map(nodeToString).join(delimiter); + } + +} + +export default XPathExpression; diff --git a/test/index.mjs b/test/index.mjs index c03cf046..cd7a2278 100644 --- a/test/index.mjs +++ b/test/index.mjs @@ -34,7 +34,7 @@ import "./tests/operations/CartesianProduct"; import "./tests/operations/CharEnc"; import "./tests/operations/Ciphers"; import "./tests/operations/Checksum"; -// import "./tests/operations/Code"; +import "./tests/operations/Code"; import "./tests/operations/Compress"; import "./tests/operations/Crypt"; import "./tests/operations/DateTime"; @@ -54,7 +54,7 @@ import "./tests/operations/OTP"; import "./tests/operations/PowerSet"; // import "./tests/operations/Regex"; import "./tests/operations/Rotate"; -// import "./tests/operations/StrUtils"; +import "./tests/operations/StrUtils"; import "./tests/operations/SeqUtils"; import "./tests/operations/SetDifference"; import "./tests/operations/SetIntersection"; diff --git a/test/tests/operations/Code.mjs b/test/tests/operations/Code.mjs index 3b282b67..00643ed1 100644 --- a/test/tests/operations/Code.mjs +++ b/test/tests/operations/Code.mjs @@ -310,6 +310,7 @@ TestRegister.addTests([ } ], }, + /* Since we don't pack ops before running tests, there's no polyfill for DomParser() { name: "CSS selector", input: '
\n

hello

\n

world

\n

again

\n
', @@ -331,5 +332,5 @@ TestRegister.addTests([ "args": ["/div/p[@class=\"a\"]", "\\n"] } ] - } + }*/ ]);