diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js index 1b068644..da0c9f0a 100755 --- a/src/core/config/Categories.js +++ b/src/core/config/Categories.js @@ -162,6 +162,8 @@ const Categories = [ "Unique", "Split", "Filter", + "Head", + "Tail", "Count occurrences", "Expand alphabet range", "Parse escaped string", diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index 16f6f1b7..ca6bdbbd 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -3196,7 +3196,59 @@ const OperationConfig = { outputType: "html", args: [ ] - } + }, + "Head": { + description: [ + "Like the UNIX head utility.", + "
", + "Gets the first n lines.", + "
", + "You can select all but the last n lines by entering a negative value for n.", + "
", + "The delimiter can be changed so that instead of lines, fields (i.e. commas) are selected instead.", + ].join("\n"), + run: StrUtils.runHead, + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: StrUtils.DELIMITER_OPTIONS + }, + { + name: "Number", + type: "number", + value: 10, + }, + ] + }, + "Tail": { + description: [ + "Like the UNIX tail utility.", + "
", + "Gets the last n lines.", + "
", + "Optionally you can select all lines after line n by entering a negative value for n.", + "
", + "The delimiter can be changed so that instead of lines, fields (i.e. commas) are selected instead.", + ].join("\n"), + run: StrUtils.runTail, + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: StrUtils.DELIMITER_OPTIONS + }, + { + name: "Number", + type: "number", + value: 10, + }, + ] + }, }; export default OperationConfig; diff --git a/src/core/operations/StrUtils.js b/src/core/operations/StrUtils.js index 816d4abc..00d2c561 100755 --- a/src/core/operations/StrUtils.js +++ b/src/core/operations/StrUtils.js @@ -460,6 +460,62 @@ const StrUtils = { }, + /** + * Head lines operation. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runHead: function(input, args) { + let delimiter = args[0], + number = args[1]; + + delimiter = Utils.charRep[delimiter]; + let splitInput = input.split(delimiter); + + return splitInput + .filter((line, lineIndex) => { + lineIndex += 1; + + if (number < 0) { + return lineIndex <= splitInput.length + number; + } else { + return lineIndex <= number; + } + }) + .join(delimiter); + }, + + + /** + * Tail lines operation. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runTail: function(input, args) { + let delimiter = args[0], + number = args[1]; + + delimiter = Utils.charRep[delimiter]; + let splitInput = input.split(delimiter); + + return splitInput + .filter((line, lineIndex) => { + lineIndex += 1; + + if (number < 0) { + return lineIndex > -number; + } else { + return lineIndex > splitInput.length - number; + } + }) + .join(delimiter); + }, + + /** * Adds HTML highlights to matches within a string. * diff --git a/test/tests/operations/StrUtils.js b/test/tests/operations/StrUtils.js index ada89137..1450d1ba 100644 --- a/test/tests/operations/StrUtils.js +++ b/test/tests/operations/StrUtils.js @@ -34,4 +34,202 @@ TestRegister.addTests([ } ], }, + { + name: "Head 0", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", 0] + } + ], + }, + { + name: "Head 1", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", 1] + } + ], + }, + { + name: "Head 2", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1, 2].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", 2] + } + ], + }, + { + name: "Head 6", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1, 2, 3, 4, 5, 6].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", 6] + } + ], + }, + { + name: "Head big", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1, 2, 3, 4, 5, 6].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", 100] + } + ], + }, + { + name: "Head all but 1", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1, 2, 3, 4, 5].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", -1] + } + ], + }, + { + name: "Head all but 2", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1, 2, 3, 4].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", -2] + } + ], + }, + { + name: "Head all but 6", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", -6] + } + ], + }, + { + name: "Head all but big", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [].join("\n"), + recipeConfig: [ + { + "op": "Head", + "args": ["Line feed", -100] + } + ], + }, + { + name: "Tail 0", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", 0] + } + ], + }, + { + name: "Tail 1", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [6].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", 1] + } + ], + }, + { + name: "Tail 2", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [5, 6].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", 2] + } + ], + }, + { + name: "Tail 6", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1, 2, 3, 4, 5, 6].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", 6] + } + ], + }, + { + name: "Tail big", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [1, 2, 3, 4, 5, 6].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", 100] + } + ], + }, + { + name: "Tail all but 1", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [2, 3, 4, 5, 6].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", -1] + } + ], + }, + { + name: "Tail all but 2", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [3, 4, 5, 6].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", -2] + } + ], + }, + { + name: "Tail all but 6", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", -6] + } + ], + }, + { + name: "Tail all but big", + input: [1, 2, 3, 4, 5, 6].join("\n"), + expectedOutput: [].join("\n"), + recipeConfig: [ + { + "op": "Tail", + "args": ["Line feed", -100] + } + ], + }, ]);