diff --git a/index.js b/index.js new file mode 100644 index 0000000..e473902 --- /dev/null +++ b/index.js @@ -0,0 +1,188 @@ +/** + * Adds a prefix to a string. + * @param {string} str - The original string. + * @param {string} prefix - The prefix to add. + * @returns {string} The string with the prefix added. + */ +function addPrefix(str, prefix) { + return prefix + str; +} + +/** + * Removes a prefix from a string. + * @param {string} str - The original string. + * @param {string} prefix - The prefix to remove. + * @returns {string} The string with the prefix removed. + */ +function removePrefix(str, prefix) { + if (str.startsWith(prefix)) { + return str.slice(prefix.length); + } + return str; +} + +/** + * Adds a suffix to a string. + * @param {string} str - The original string. + * @param {string} suffix - The suffix to add. + * @returns {string} The string with the suffix added. + */ +function addSuffix(str, suffix) { + return str + suffix; +} + +/** + * Removes a suffix from a string. + * @param {string} str - The original string. + * @param {string} suffix - The suffix to remove. + * @returns {string} The string with the suffix removed. + */ +function removeSuffix(str, suffix) { + if (str.endsWith(suffix)) { + return str.slice(0, -suffix.length); + } + return str; +} + +/** + * Tokenizes a string into tokens + * @param {string} str + * @returns {Array} tokens + */ +function tokenize(str) { + const tokens = []; + let currentToken = ""; + let inQuotes = false; + let escapeNext = false; + + for (let i = 0; i < str.length; i++) { + const char = str[i]; + + if (escapeNext) { + currentToken += char; + escapeNext = false; + } else if (char === "\\") { + escapeNext = true; + } else if (char === '"') { + inQuotes = !inQuotes; + } else if ((char === " " || char === "\n" || char === "\r") && !inQuotes) { + if (currentToken !== "") { + tokens.push(currentToken); + currentToken = ""; + } + } else { + currentToken += char; + } + } + + if (currentToken !== "") { + tokens.push(currentToken); + } + + return tokens; +} + +/** + * Manipulates the filename based on rules + * @param {string} string + * @param {string} filename + * @returns + */ +function manipulateFilename(string, filename) { + /** + * @type {{dimension: string, action: string, target:string, value: string}} cmd + */ + let cmd; + + /** + * @type {Array<{dimension: string, action: string, target:string, value: string}>} commands + */ + let commands = []; + let state = "next"; + + for (const token of tokenize(string)) { + switch (state) { + case "next": + if (token === "for") { + cmd = {}; + state = "dimension"; + } else { + throw new Error("Syntax Error, command must start with 'for'"); + } + break; + case "dimension": + if (token === "2D" || token === "3D") { + cmd = { ...cmd, dimension: token }; + state = "action"; + } else { + throw new Error("Syntax Error, command must be '2D' or '3D'"); + } + break; + case "action": + if (token === "add" || token === "remove") { + cmd = { ...cmd, action: token }; + state = "target"; + } else { + throw new Error("Syntax Error, command must be 'add' or 'remove'"); + } + break; + case "target": + if (token === "all" && cmd.action === "add") { + throw new Error( + "Syntax Error, you cannot use an 'all' target with an 'add' action, only 'remove' is allowed" + ); + } else if (token === "all" && cmd.action === "remove") { + cmd = { ...cmd, target: token }; + state = "value"; + } else if (token === "prefix" || token === "suffix") { + cmd = { ...cmd, target: token }; + state = "value"; + } else { + throw new Error( + "Syntax Error, command must be 'prefix', 'suffix', or 'all'" + ); + } + break; + case "value": + cmd = { ...cmd, value: token }; + commands.push(cmd); + state = "more"; + case "more": + if (token === "and") { + state = "next"; + } + break; + default: + break; + } + } + + for (const command of commands) { + if (command.target === "prefix" && command.action === "add") { + filename = addPrefix(filename, command.value); + } + if (command.target === "prefix" && command.action === "remove") { + filename = removePrefix(filename, command.value); + } + if (command.target === "suffix" && command.action === "add") { + filename = addSuffix(filename, command.value); + } + if (command.target === "suffix" && command.action === "remove") { + filename = removeSuffix(filename, command.value); + } + if (command.target === "all" && command.action === "remove") { + filename = filename.replace(command.value, ""); + } + } + + return filename; +} + +const cmdStr = `for 2D add prefix "hello-" and + for 2D add suffix "-3" and + for 2D add suffix "-3" and + for 2D add suffix "-4" and + for 2D add suffix "-5" and for 2D remove all "-3"`; +const filename = "example"; +const result = manipulateFilename(cmdStr, filename); +console.log(result); // Output: "hello-example-3"