From 748624eae856f9f127993d9f661fc74bdeab36aa Mon Sep 17 00:00:00 2001 From: Ruchi Vishwakarma Date: Tue, 1 Jul 2025 07:32:32 +0000 Subject: [PATCH] code update recorded at: 01/07/25 07:32:32 --- handler.js | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 26 +++++ 2 files changed, 329 insertions(+) create mode 100644 handler.js create mode 100644 package.json diff --git a/handler.js b/handler.js new file mode 100644 index 0000000..1da7822 --- /dev/null +++ b/handler.js @@ -0,0 +1,303 @@ +import { decode as decodeHTML, encode as encodeHTML } from "html-entities"; +import { marked } from "marked"; +import { evaluate } from "mathjs"; + +export const handler = async (req, res) => { + try { + if (req.method !== "POST") { + return res.status(405).json({ error: "Method Not Allowed. Use POST." }); + } + + const { operationGroup, operation, value, options = {} } = req.body || {}; + + if (!operationGroup || !operation) { + return res + .status(400) + .json({ error: 'Missing "operationGroup" or "operation".' }); + } + + const input = String(value); + + // ===== TEXT OPERATIONS ===== + const textFormatters = { + uppercase: () => input.toUpperCase(), + lowercase: () => input.toLowerCase(), + capitalize: () => + input.charAt(0).toUpperCase() + input.slice(1).toLowerCase(), + titlecase: () => + input.replace( + /\w\S*/g, + (w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase() + ), + trim: () => input.trim(), + removeWhitespace: () => input.replace(/\s+/g, ""), + replace: () => { + const { find, replaceWith } = options; + if (typeof find !== "string" || typeof replaceWith !== "string") { + throw new Error('"replace" needs "find" and "replaceWith".'); + } + return input.split(find).join(replaceWith); + }, + slugify: () => + input + .toLowerCase() + .replace(/[^\w\s-]/g, "") + .trim() + .replace(/[\s_-]+/g, "-"), + split: () => input.split(options.delimiter ?? ","), + substring: () => { + const start = parseInt(options.start ?? 0); + const end = parseInt(options.end ?? input.length); + return input.substring(start, end); + }, + length: () => input.length, + startsWith: () => input.startsWith(options.prefix ?? ""), + endsWith: () => input.endsWith(options.suffix ?? ""), + contains: () => input.includes(options.text ?? ""), + base64encode: () => Buffer.from(input).toString("base64"), + base64decode: () => Buffer.from(input, "base64").toString("utf8"), + reverse: () => [...input].reverse().join(""), + repeat: () => { + const times = parseInt(options.times ?? 1); + return input.repeat(times); + }, + url_encode: () => encodeURIComponent(input), + url_decode: () => decodeURIComponent(input), + word_count: () => input.trim().split(/\s+/).length, + truncate: () => { + const length = parseInt(options.length ?? 10); + return input.length <= length + ? input + : input.substring(0, length) + "..."; + }, + encode_ascii: () => input.replace(/[^\x00-\x7F]/g, ""), + default_value: () => + input && input.trim() !== "" ? input : options.default ?? "", + email_extract: () => + (input.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-z]{2,}/) ?? [""])[0], + phone_extract: () => + (input.match( + /(?:\+?(\d{1,3}))?[\s.-]?(\(?\d{3}\)?[\s.-]?)?\d{3}[\s.-]?\d{4}/ + ) ?? [""])[0], + url_extract: () => (input.match(/https?:\/\/[^\s]+/g) ?? [""])[0], + number_extract: () => { + const match = input.match(/-?\d+(\.\d+)?/); + return match ? parseFloat(match[0]) : null; + }, + re_extract: () => { + if (!options.pattern) + throw new Error('"re_extract" requires a "pattern".'); + const regex = new RegExp(options.pattern, options.flags || ""); + const match = input.match(regex); + return match ? match[0] : ""; + }, + htmlmarkdown: async () => { + const { default: TurndownService } = await import("turndown"); + const service = new TurndownService(); + return service.turndown(input); + }, + markdown: () => marked.parse(input), + strip_html: () => input.replace(/<[^>]+>/g, ""), + pluralize: async () => { + const { default: pluralize } = await import("pluralize"); + return pluralize(input); + }, + find: () => input.indexOf(options.text), + spreadsheet_formula: () => { + throw new Error('"spreadsheet_formula" is not supported in text.'); + }, + split_into_chunks: () => { + const size = parseInt(options.size ?? 1000); + return input.match(new RegExp(`.{1,${size}}`, "g")) || []; + }, + superhero: () => { + const adj = ["Incredible", "Amazing", "Mighty", "Fantastic"]; + const noun = ["Falcon", "Panther", "Wizard", "Knight"]; + return `${adj[Math.floor(Math.random() * adj.length)]} ${noun[Math.floor(Math.random() * noun.length)] + }`; + }, + }; + + // ===== NUMBER OPERATIONS ===== + const numberFormatters = { + currency: () => { + if (typeof value !== "number") + throw new Error('"value" must be a number.'); + const { locale = "en-US", currency = "USD" } = options; + return new Intl.NumberFormat(locale, { + style: "currency", + currency, + }).format(value); + }, + formatting: () => { + if (typeof value !== "number") + throw new Error('"value" must be a number.'); + const { + locale = "en-US", + minimumFractionDigits = 0, + maximumFractionDigits = 2, + } = options; + return new Intl.NumberFormat(locale, { + minimumFractionDigits, + maximumFractionDigits, + }).format(value); + }, + phone_v2: () => { + const str = String(value).replace(/\D/g, ""); + if (str.length === 10) + return `(${str.slice(0, 3)}) ${str.slice(3, 6)}-${str.slice(6)}`; + if (str.length === 11 && str[0] === "1") + return `+1 (${str.slice(1, 4)}) ${str.slice(4, 7)}-${str.slice(7)}`; + throw new Error("Invalid phone number."); + }, + math_v2: () => { + const num = parseFloat(options.operand ?? 0); + switch (options.operator) { + case "add": + return value + num; + case "subtract": + return value - num; + case "multiply": + return value * num; + case "divide": + return num === 0 ? "NaN" : value / num; + case "modulo": + return value % num; + case "power": + return Math.pow(value, num); + default: + throw new Error(`Unsupported operator: ${options.operator}`); + } + }, + random_number: () => { + const min = parseFloat(options.min ?? 0); + const max = parseFloat(options.max ?? 100); + return Math.random() * (max - min) + min; + }, + spreadsheet_formula: () => { + const formula = (options.formula || "").trim(); + const variables = options.variables || {}; + + if (!formula || typeof formula !== "string") { + throw new Error( + '"spreadsheet_formula" requires a string in options.formula' + ); + } + + const cleaned = formula.startsWith("=") ? formula.slice(1) : formula; + + try { + return evaluate(cleaned, variables); + } catch (e) { + throw new Error(`Invalid formula: ${e.message}`); + } + }, + }; + + // ===== DATE OPERATIONS ===== + const dateFormatters = { + formatting: () => { + const date = new Date(value); + if (isNaN(date)) throw new Error("Invalid date."); + const { locale = "en-US", options: formatOptions = {} } = options; + return new Intl.DateTimeFormat(locale, formatOptions).format(date); + }, + compare_dates: () => { + const date1 = new Date(value); + const date2 = new Date(options.compareWith); + if (isNaN(date1) || isNaN(date2)) throw new Error("Invalid date(s)."); + return date1.getTime() - date2.getTime(); + }, + manipulate: () => { + const date = new Date(value); + if (isNaN(date)) throw new Error("Invalid date."); + const { amount = 0, unit = "days" } = options; + const units = { + days: 86400000, + hours: 3600000, + minutes: 60000, + seconds: 1000, + }; + return new Date( + date.getTime() + amount * (units[unit] || 0) + ).toISOString(); + }, + }; + + // ===== BOOLEAN OPERATIONS ===== + const toBool = (val) => { + if (typeof val === "boolean") return val; + if (typeof val === "string") + return ["true", "1", "yes"].includes(val.toLowerCase()); + if (typeof val === "number") return val !== 0; + return Boolean(val); + }; + + const booleanFormatters = { + not: () => !toBool(value), + + and: () => { + const values = options.values ?? []; + if (!Array.isArray(values)) { + throw new Error('"values" must be an array for "and" operation.'); + } + return [value, ...values].every(toBool); + }, + + or: () => { + const values = options.values ?? []; + if (!Array.isArray(values)) { + throw new Error('"values" must be an array for "or" operation.'); + } + return [value, ...values].some(toBool); + }, + + xor: () => { + const val1 = toBool(value); + const val2 = toBool(options.other); + return (val1 || val2) && !(val1 && val2); + }, + + if_else: () => { + return toBool(value) ? options.then : options.otherwise; + }, + + default_value: () => { + return typeof value === "boolean" ? value : options.default ?? false; + }, + + // Retain your previous helpers + invert: () => !value, + toString: () => String(value), + toNumber: () => (value ? 1 : 0), + }; + + // Choose formatter map + const groupMap = { + text: textFormatters, + number: numberFormatters, + date: dateFormatters, + boolean: booleanFormatters, + }; + + const formatterGroup = groupMap[operationGroup]; + if (!formatterGroup) { + return res + .status(400) + .json({ error: `Unsupported operationGroup: ${operationGroup}` }); + } + + const formatter = formatterGroup[operation]; + if (!formatter) { + return res + .status(400) + .json({ error: `Unsupported operation: ${operation}` }); + } + + const result = await formatter(); + return res.status(200).json({ result }); + } catch (err) { + console.error("Formatter Error:", err.message); + return res.status(500).json({ error: err.message }); + } +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..8b5a7ef --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "boltic-formatter", + "version": "1.0.0", + "description": "A formatter for Boltic that processes text and returns formatted results.", + "main": "handler.js", + "scripts": { + "start": "node handler.js" + }, + "dependencies": { + "@playwright/test": "^1.51.1", + "body-parser": "^2.2.0", + "express": "^4.21.2", + "dayjs": "^1.11.13", + "html-entities": "^2.6.0", + "marked": "^15.0.12", + "mathjs": "^14.5.2", + "pluralize": "^8.0.0", + "turndown": "^7.2.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "author": "Boltic", + "license": "MIT", + "type": "module" +} \ No newline at end of file