UNPKG

@devtools-cli/devtools-cli

Version:

A free collection of essential online developer tools. Convert Base64, format JSON, generate UUIDs, analyze strings, and more. Fast, simple, and easy to use.

1,596 lines (1,578 loc) 74.8 kB
#!/usr/bin/env node // src/index.ts import { Command as Command11 } from "commander"; // src/commands/base64.ts import { Command } from "commander"; // ../core/src/base64.ts function encodeBase64(input) { if (typeof input !== "string") { throw new Error("Input must be a string"); } if (typeof btoa !== "undefined") { return btoa(unescape(encodeURIComponent(input))); } else { return Buffer.from(input, "utf8").toString("base64"); } } function decodeBase64(input) { if (typeof input !== "string") { throw new Error("Input must be a string"); } try { if (typeof atob !== "undefined") { return decodeURIComponent(escape(atob(input))); } else { return Buffer.from(input, "base64").toString("utf8"); } } catch (error) { throw new Error("Invalid Base64 string"); } } // ../core/src/json.ts function validateJson(input) { if (typeof input !== "string") { return { isValid: false, error: "Input must be a string" }; } if (input.trim() === "") { return { isValid: false, error: "Input cannot be empty" }; } try { const data = JSON.parse(input); return { isValid: true, data }; } catch (error) { return { isValid: false, error: error instanceof Error ? error.message : "Invalid JSON" }; } } function formatJson(input, indent = 2) { const validation = validateJson(input); if (!validation.isValid) { throw new Error(validation.error); } return JSON.stringify(validation.data, null, indent); } function minifyJson(input) { const validation = validateJson(input); if (!validation.isValid) { throw new Error(validation.error); } return JSON.stringify(validation.data); } // ../core/src/hex.ts function hexToAscii(hex) { if (typeof hex !== "string") { throw new Error("Input must be a string"); } const cleanHex = hex.replace(/\s+/g, "").toLowerCase(); if (!/^[0-9a-f]*$/i.test(cleanHex)) { throw new Error("Invalid hexadecimal string"); } if (cleanHex.length % 2 !== 0) { throw new Error("Hexadecimal string must have even length"); } let result = ""; for (let i = 0; i < cleanHex.length; i += 2) { const hexPair = cleanHex.substr(i, 2); const charCode = parseInt(hexPair, 16); result += String.fromCharCode(charCode); } return result; } function asciiToHex(ascii) { if (typeof ascii !== "string") { throw new Error("Input must be a string"); } let result = ""; for (let i = 0; i < ascii.length; i++) { const hex = ascii.charCodeAt(i).toString(16); result += hex.padStart(2, "0"); } return result.toUpperCase(); } function hexToBinary(hex) { if (typeof hex !== "string") { throw new Error("Input must be a string"); } const cleanHex = hex.replace(/\s+/g, "").toLowerCase(); if (!/^[0-9a-f]*$/i.test(cleanHex)) { throw new Error("Invalid hexadecimal string"); } let result = ""; for (let i = 0; i < cleanHex.length; i++) { const digit = parseInt(cleanHex[i], 16); result += digit.toString(2).padStart(4, "0"); } return result; } function binaryToHex(binary) { if (typeof binary !== "string") { throw new Error("Input must be a string"); } const cleanBinary = binary.replace(/\s+/g, ""); if (!/^[01]*$/.test(cleanBinary)) { throw new Error("Invalid binary string"); } const paddedBinary = cleanBinary.padStart( Math.ceil(cleanBinary.length / 4) * 4, "0" ); let result = ""; for (let i = 0; i < paddedBinary.length; i += 4) { const nibble = paddedBinary.substr(i, 4); const hex = parseInt(nibble, 2).toString(16); result += hex; } return result.toUpperCase(); } function hexToDecimal(hex) { if (typeof hex !== "string") { throw new Error("Input must be a string"); } const cleanHex = hex.replace(/\s+/g, "").toLowerCase(); if (cleanHex === "") { return 0; } if (!/^[0-9a-f]*$/i.test(cleanHex)) { throw new Error("Invalid hexadecimal string"); } return parseInt(cleanHex, 16); } function decimalToHex(decimal) { if (typeof decimal !== "number" || !Number.isInteger(decimal)) { throw new Error("Input must be an integer"); } if (decimal < 0) { throw new Error("Input must be a non-negative integer"); } return decimal.toString(16).toUpperCase(); } // ../core/src/timestamp.ts function unixToIso(timestamp) { if (typeof timestamp !== "number") { throw new Error("Timestamp must be a number"); } if (timestamp < 0) { throw new Error("Timestamp must be non-negative"); } const timestampMs = timestamp.toString().length <= 10 ? timestamp * 1e3 : timestamp; const date = new Date(timestampMs); if (isNaN(date.getTime())) { throw new Error("Invalid timestamp"); } return date.toISOString(); } function isoToUnix(isoString) { if (typeof isoString !== "string") { throw new Error("Input must be a string"); } const date = new Date(isoString); if (isNaN(date.getTime())) { throw new Error("Invalid ISO string"); } return Math.floor(date.getTime() / 1e3); } function getCurrentUnixTimestamp() { return Math.floor(Date.now() / 1e3); } function getCurrentIsoTimestamp() { return (/* @__PURE__ */ new Date()).toISOString(); } function formatTimestamp(timestamp, options = {}) { let date; if (typeof timestamp === "number") { const timestampMs = timestamp.toString().length <= 10 ? timestamp * 1e3 : timestamp; date = new Date(timestampMs); } else { date = new Date(timestamp); } if (isNaN(date.getTime())) { throw new Error("Invalid timestamp"); } const defaultOptions = { year: "numeric", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZoneName: "short", ...options }; return date.toLocaleDateString("en-US", defaultOptions); } // ../core/src/uuid.ts function generateUuidV4() { if (typeof crypto !== "undefined" && crypto.randomUUID) { return crypto.randomUUID(); } if (typeof crypto !== "undefined" && crypto.getRandomValues) { const array = new Uint8Array(16); crypto.getRandomValues(array); array[6] = array[6] & 15 | 64; array[8] = array[8] & 63 | 128; const hex2 = Array.from(array).map((b) => b.toString(16).padStart(2, "0")).join(""); return [ hex2.slice(0, 8), hex2.slice(8, 12), hex2.slice(12, 16), hex2.slice(16, 20), hex2.slice(20, 32) ].join("-"); } const randomBytes = () => { const bytes2 = []; for (let i = 0; i < 16; i++) { bytes2.push(Math.floor(Math.random() * 256)); } return bytes2; }; const bytes = randomBytes(); bytes[6] = bytes[6] & 15 | 64; bytes[8] = bytes[8] & 63 | 128; const hex = bytes.map((b) => b.toString(16).padStart(2, "0")).join(""); return [ hex.slice(0, 8), hex.slice(8, 12), hex.slice(12, 16), hex.slice(16, 20), hex.slice(20, 32) ].join("-"); } function isValidUuid(uuid) { if (typeof uuid !== "string") { return false; } const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; return uuidRegex.test(uuid); } function generateMultipleUuids(count) { if (typeof count !== "number" || count < 1 || !Number.isInteger(count)) { throw new Error("Count must be a positive integer"); } if (count > 1e3) { throw new Error("Count cannot exceed 1000"); } const uuids = []; for (let i = 0; i < count; i++) { uuids.push(generateUuidV4()); } return uuids; } // ../core/src/cron.ts var CRON_FIELDS = [ { min: 0, max: 59, name: "minute" }, { min: 0, max: 23, name: "hour" }, { min: 1, max: 31, name: "day" }, { min: 1, max: 12, name: "month", values: { "JAN": 1, "FEB": 2, "MAR": 3, "APR": 4, "MAY": 5, "JUN": 6, "JUL": 7, "AUG": 8, "SEP": 9, "OCT": 10, "NOV": 11, "DEC": 12 } }, { min: 0, max: 6, name: "day_of_week", values: { "SUN": 0, "MON": 1, "TUE": 2, "WED": 3, "THU": 4, "FRI": 5, "SAT": 6 } } ]; var COMMON_EXPRESSIONS = { "@yearly": "0 0 1 1 *", "@annually": "0 0 1 1 *", "@monthly": "0 0 1 * *", "@weekly": "0 0 * * 0", "@daily": "0 0 * * *", "@midnight": "0 0 * * *", "@hourly": "0 * * * *" }; function validateCronExpression(expression) { if (!expression || typeof expression !== "string") { return { valid: false, error: "Cron expression is required" }; } const trimmed = expression.trim(); if (trimmed in COMMON_EXPRESSIONS) { return { valid: true }; } const parts = trimmed.split(/\s+/); if (parts.length !== 5) { return { valid: false, error: "Cron expression must have exactly 5 fields (minute hour day month day_of_week)" }; } for (let i = 0; i < parts.length; i++) { const part = parts[i]; const field = CRON_FIELDS[i]; const validation = validateCronField(part, field); if (!validation.valid) { return { valid: false, error: `Invalid ${field.name}: ${validation.error}` }; } } return { valid: true }; } function validateCronField(value, field) { if (value === "*") { return { valid: true }; } if (value.includes("-")) { const [start, end] = value.split("-"); const startNum = parseFieldValue(start, field); const endNum = parseFieldValue(end, field); if (startNum === null || endNum === null) { return { valid: false, error: "Invalid range values" }; } if (startNum < field.min || startNum > field.max || endNum < field.min || endNum > field.max) { return { valid: false, error: `Range values must be between ${field.min} and ${field.max}` }; } if (startNum > endNum) { return { valid: false, error: "Range start must be less than or equal to range end" }; } return { valid: true }; } if (value.includes("/")) { const [range, step] = value.split("/"); const stepNum = parseInt(step, 10); if (isNaN(stepNum) || stepNum <= 0) { return { valid: false, error: "Step value must be a positive integer" }; } if (range !== "*") { return validateCronField(range, field); } return { valid: true }; } if (value.includes(",")) { const values = value.split(","); for (const val of values) { const validation = validateCronField(val.trim(), field); if (!validation.valid) { return validation; } } return { valid: true }; } const num = parseFieldValue(value, field); if (num === null) { return { valid: false, error: "Invalid value" }; } if (num < field.min || num > field.max) { return { valid: false, error: `Value must be between ${field.min} and ${field.max}` }; } return { valid: true }; } function parseFieldValue(value, field) { const num = parseInt(value, 10); if (!isNaN(num)) { return num; } if (field.values && value.toUpperCase() in field.values) { return field.values[value.toUpperCase()]; } return null; } function explainCronExpression(expression) { if (!expression) { return "Invalid cron expression"; } const trimmed = expression.trim(); if (trimmed in COMMON_EXPRESSIONS) { const explanations2 = { "@yearly": "Once a year at midnight on January 1st", "@annually": "Once a year at midnight on January 1st", "@monthly": "Once a month at midnight on the 1st day", "@weekly": "Once a week at midnight on Sunday", "@daily": "Once a day at midnight", "@midnight": "Once a day at midnight", "@hourly": "Once an hour at the beginning of the hour" }; return explanations2[trimmed]; } const validation = validateCronExpression(trimmed); if (!validation.valid) { return `Invalid cron expression: ${validation.error}`; } const parts = trimmed.split(/\s+/); const [minute, hour, day, month, dayOfWeek] = parts; const explanations = []; const timeExplanation = explainTime(minute, hour); explanations.push(timeExplanation); const dateExplanation = explainDate(day, month, dayOfWeek); if (dateExplanation) { explanations.push(dateExplanation); } return explanations.join(" "); } function explainTime(minute, hour) { const minuteDesc = explainField(minute, "minute"); const hourDesc = explainField(hour, "hour"); if (minute === "0" && hour === "*") { return "At the beginning of every hour"; } if (minute === "0" && hour !== "*") { return `At ${hourDesc}`; } if (hour === "*") { return `At ${minuteDesc} of every hour`; } return `At ${minuteDesc} past ${hourDesc}`; } function explainDate(day, month, dayOfWeek) { const parts = []; if (dayOfWeek !== "*") { parts.push(`on ${explainField(dayOfWeek, "day_of_week")}`); } if (day !== "*") { if (dayOfWeek !== "*") { parts.push(`and on ${explainField(day, "day")} of the month`); } else { parts.push(`on ${explainField(day, "day")} of the month`); } } if (month !== "*") { parts.push(`in ${explainField(month, "month")}`); } return parts.join(" "); } function explainField(value, fieldType) { if (value === "*") { return `every ${fieldType}`; } const field = CRON_FIELDS.find((f) => f.name === fieldType); if (!field) { return value; } if (value.includes("-")) { const [start, end] = value.split("-"); return `${formatFieldValue(start, field)} through ${formatFieldValue(end, field)}`; } if (value.includes("/")) { const [range, step] = value.split("/"); if (range === "*") { return `every ${step} ${fieldType}s`; } return `every ${step} ${fieldType}s in range ${explainField(range, fieldType)}`; } if (value.includes(",")) { const values = value.split(",").map((v) => formatFieldValue(v.trim(), field)); if (values.length === 2) { return `${values[0]} and ${values[1]}`; } return `${values.slice(0, -1).join(", ")}, and ${values[values.length - 1]}`; } return formatFieldValue(value, field); } function formatFieldValue(value, field) { const num = parseFieldValue(value, field); if (field.name === "hour") { if (num === 0) return "midnight"; if (num === 12) return "noon"; if (num < 12) return `${num}:00 AM`; return `${num - 12}:00 PM`; } if (field.name === "day_of_week") { const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; return days[num] || value; } if (field.name === "month") { const months = [ "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; return months[num] || value; } if (field.name === "day") { const ordinals = [ "", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th", "30th", "31st" ]; return ordinals[num] || value; } if (field.name === "minute") { if (num === 0) return "0 minutes"; if (num === 1) return "1 minute"; return `${num} minutes`; } return value; } function expandCronExpression(expression) { const trimmed = expression.trim(); return COMMON_EXPRESSIONS[trimmed] || trimmed; } var CRON_PRESETS = [ { name: "Every minute", expression: "* * * * *" }, { name: "Every 5 minutes", expression: "*/5 * * * *" }, { name: "Every 15 minutes", expression: "*/15 * * * *" }, { name: "Every 30 minutes", expression: "*/30 * * * *" }, { name: "Every hour", expression: "@hourly" }, { name: "Every day at midnight", expression: "@daily" }, { name: "Every day at 6 AM", expression: "0 6 * * *" }, { name: "Every day at 6 PM", expression: "0 18 * * *" }, { name: "Every weekday at 9 AM", expression: "0 9 * * 1-5" }, { name: "Every weekend at 10 AM", expression: "0 10 * * 6,0" }, { name: "Every week (Sunday midnight)", expression: "@weekly" }, { name: "Every month (1st at midnight)", expression: "@monthly" }, { name: "Every year (Jan 1st at midnight)", expression: "@yearly" } ]; // ../core/src/string.ts function analyzeString(text) { if (typeof text !== "string") { throw new Error("Input must be a string"); } const length = text.length; const characters = length; const charactersNoSpaces = text.replace(/\s/g, "").length; const words = text.trim() === "" ? 0 : text.trim().split(/\s+/).filter((word) => word.length > 0).length; const sentences = text.trim() === "" ? 0 : text.split(/[.!?]+/).filter((sentence) => sentence.trim().length > 0).length; const paragraphs = text.trim() === "" ? 0 : text.split(/\n\s*\n/).filter((para) => para.trim().length > 0).length; const lines = text === "" ? 0 : text.split(/\n/).length; const bytes = new TextEncoder().encode(text).length; const whitespace = (text.match(/\s/g) || []).length; const digits = (text.match(/\d/g) || []).length; const letters = (text.match(/[a-zA-Z]/g) || []).length; const uppercase = (text.match(/[A-Z]/g) || []).length; const lowercase = (text.match(/[a-z]/g) || []).length; const specialChars = length - letters - digits - whitespace; return { length, characters, charactersNoSpaces, words, sentences, paragraphs, lines, bytes, whitespace, digits, letters, uppercase, lowercase, specialChars }; } function toCamelCase(text) { return text.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => { return index === 0 ? word.toLowerCase() : word.toUpperCase(); }).replace(/\s+/g, "").replace(/[-_]/g, ""); } function toPascalCase(text) { return text.replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => { return word.toUpperCase(); }).replace(/\s+/g, "").replace(/[-_]/g, ""); } function toSnakeCase(text) { return text.replace(/\W+/g, " ").split(/ |\B(?=[A-Z])/).map((word) => word.toLowerCase()).join("_").replace(/_+/g, "_").replace(/^_|_$/g, ""); } function toKebabCase(text) { return text.replace(/\W+/g, " ").split(/ |\B(?=[A-Z])/).map((word) => word.toLowerCase()).join("-").replace(/-+/g, "-").replace(/^-|-$/g, ""); } function toConstantCase(text) { return toSnakeCase(text).toUpperCase(); } function toTitleCase(text) { return text.replace(/\w\S*/g, (txt) => { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); } function toSentenceCase(text) { return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase(); } // ../core/src/xml.ts function validateXml(xmlString) { if (!xmlString || typeof xmlString !== "string") { return { valid: false, error: "XML string is required" }; } try { if (typeof DOMParser !== "undefined") { const parser = new DOMParser(); const doc = parser.parseFromString(xmlString.trim(), "text/xml"); const parserError = doc.querySelector("parsererror"); if (parserError) { const errorText = parserError.textContent || "Unknown XML parsing error"; return { valid: false, error: errorText }; } return { valid: true }; } else { return basicXmlValidation(xmlString); } } catch (error) { return { valid: false, error: error instanceof Error ? error.message : "XML validation failed" }; } } function basicXmlValidation(xmlString) { const trimmed = xmlString.trim(); if (!trimmed.startsWith("<") || !trimmed.endsWith(">")) { return { valid: false, error: "XML must start with < and end with >" }; } const tagStack = []; const tagRegex = /<\/?([a-zA-Z][a-zA-Z0-9]*)[^>]*>/g; let match; while ((match = tagRegex.exec(trimmed)) !== null) { const fullTag = match[0]; const tagName = match[1]; if (fullTag.startsWith("</")) { const lastOpenTag = tagStack.pop(); if (lastOpenTag !== tagName) { return { valid: false, error: `Mismatched closing tag: expected </${lastOpenTag || "?"}> but found </${tagName}>` }; } } else if (!fullTag.endsWith("/>")) { tagStack.push(tagName); } } if (tagStack.length > 0) { return { valid: false, error: `Unclosed tags: ${tagStack.join(", ")}` }; } return { valid: true }; } function formatXml(xmlString, indentSize = 2) { if (!xmlString || typeof xmlString !== "string") { throw new Error("XML string is required"); } const validation = validateXml(xmlString); if (!validation.valid) { throw new Error(`Invalid XML: ${validation.error}`); } try { const cleanXml = xmlString.replace(/>\s*</g, "><").trim(); let formatted = ""; let indent = 0; const indentStr = " ".repeat(indentSize); const tags = cleanXml.split(/(<[^>]*>)/); for (let i = 0; i < tags.length; i++) { const tag = tags[i]; if (!tag) continue; if (tag.match(/^<\/\w/)) { indent--; formatted += indentStr.repeat(Math.max(0, indent)) + tag; if (i < tags.length - 1) formatted += "\n"; } else if (tag.match(/^<\w[^>]*[^\/]>$/)) { formatted += indentStr.repeat(indent) + tag; if (i < tags.length - 1) formatted += "\n"; indent++; } else if (tag.match(/^<\w[^>]*\/>$/)) { formatted += indentStr.repeat(indent) + tag; if (i < tags.length - 1) formatted += "\n"; } else if (tag.match(/^<[?!]/)) { formatted += indentStr.repeat(indent) + tag; if (i < tags.length - 1) formatted += "\n"; } else if (tag.trim()) { formatted += indentStr.repeat(indent) + tag.trim(); if (i < tags.length - 1) formatted += "\n"; } } return formatted; } catch (error) { throw new Error(`XML formatting failed: ${error instanceof Error ? error.message : "Unknown error"}`); } } function minifyXml(xmlString) { if (!xmlString || typeof xmlString !== "string") { throw new Error("XML string is required"); } const validation = validateXml(xmlString); if (!validation.valid) { throw new Error(`Invalid XML: ${validation.error}`); } return xmlString.replace(/>\s+</g, "><").replace(/\s+/g, " ").trim(); } function analyzeXml(xmlString) { if (!xmlString || typeof xmlString !== "string") { throw new Error("XML string is required"); } const validation = validateXml(xmlString); if (!validation.valid) { throw new Error(`Invalid XML: ${validation.error}`); } try { if (typeof DOMParser !== "undefined") { let traverse2 = function(node, depth = 0) { maxDepth = Math.max(maxDepth, depth); if (node.nodeType === Node.ELEMENT_NODE) { elements++; const element = node; attributes += element.attributes.length; } else if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) { textNodes++; } else if (node.nodeType === Node.COMMENT_NODE) { comments++; } for (let i = 0; i < node.childNodes.length; i++) { traverse2(node.childNodes[i], depth + 1); } }; var traverse = traverse2; const parser = new DOMParser(); const doc = parser.parseFromString(xmlString, "text/xml"); let elements = 0; let attributes = 0; let textNodes = 0; let comments = 0; let maxDepth = 0; traverse2(doc, 0); return { elements, attributes, textNodes, comments, depth: maxDepth }; } else { return basicXmlAnalysis(xmlString); } } catch (error) { throw new Error(`XML analysis failed: ${error instanceof Error ? error.message : "Unknown error"}`); } } function basicXmlAnalysis(xmlString) { let elements = 0; let attributes = 0; let textNodes = 0; let comments = 0; let maxDepth = 0; let currentDepth = 0; const selfClosingRegex = /<\w[^>]*\/>/g; const selfClosingMatches = xmlString.match(selfClosingRegex) || []; const openingTagRegex = /<\w[^>]*(?<!\/)\s*>/g; const openingMatches = xmlString.match(openingTagRegex) || []; elements = openingMatches.length + selfClosingMatches.length; const attributeRegex = /\s+\w+\s*=\s*["'][^"']*["']/g; const attributeMatches = xmlString.match(attributeRegex) || []; attributes = attributeMatches.length; const commentRegex = /<!--[\s\S]*?-->/g; const commentMatches = xmlString.match(commentRegex) || []; comments = commentMatches.length; const allTags = xmlString.match(/<[^>]+>/g) || []; for (const tag of allTags) { if (tag.startsWith("</")) { currentDepth--; } else if (!tag.endsWith("/>") && !tag.startsWith("<?") && !tag.startsWith("<!--")) { currentDepth++; maxDepth = Math.max(maxDepth, currentDepth); } } const textContent = xmlString.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim(); if (textContent.length > 0) { const textSegments = textContent.split(" ").filter((segment) => segment.length > 0); textNodes = Math.max(1, Math.floor(textSegments.length / 3)); } return { elements, attributes, textNodes, comments, depth: maxDepth }; } // ../core/src/color.ts function validateHexColor(hex) { if (!hex || typeof hex !== "string") { throw new Error("Hex color string is required"); } const cleanHex = hex.replace("#", ""); if (!/^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(cleanHex)) { throw new Error("Invalid hex color format. Use #RGB or #RRGGBB"); } if (cleanHex.length === 3) { return "#" + cleanHex.split("").map((char) => char + char).join(""); } return "#" + cleanHex.toUpperCase(); } function validateRgbColor(r, g, b) { if (typeof r !== "number" || typeof g !== "number" || typeof b !== "number") { throw new Error("RGB values must be numbers"); } if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { throw new Error("RGB values must be between 0 and 255"); } return { r: Math.round(r), g: Math.round(g), b: Math.round(b) }; } function hexToRgb(hex) { const validHex = validateHexColor(hex); const cleanHex = validHex.replace("#", ""); const r = parseInt(cleanHex.substring(0, 2), 16); const g = parseInt(cleanHex.substring(2, 4), 16); const b = parseInt(cleanHex.substring(4, 6), 16); return { r, g, b }; } function rgbToHex(r, g, b) { const rgb = validateRgbColor(r, g, b); const toHex = (n) => { const hex = n.toString(16); return hex.length === 1 ? "0" + hex : hex; }; return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`.toUpperCase(); } function rgbToHsl(r, g, b) { const rgb = validateRgbColor(r, g, b); const rNorm = rgb.r / 255; const gNorm = rgb.g / 255; const bNorm = rgb.b / 255; const max = Math.max(rNorm, gNorm, bNorm); const min = Math.min(rNorm, gNorm, bNorm); let h = 0; let s = 0; const l = (max + min) / 2; if (max !== min) { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case rNorm: h = (gNorm - bNorm) / d + (gNorm < bNorm ? 6 : 0); break; case gNorm: h = (bNorm - rNorm) / d + 2; break; case bNorm: h = (rNorm - gNorm) / d + 4; break; } h /= 6; } return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }; } function hslToRgb(h, s, l) { if (h < 0 || h > 360 || s < 0 || s > 100 || l < 0 || l > 100) { throw new Error("HSL values out of range: H(0-360), S(0-100), L(0-100)"); } const hNorm = h / 360; const sNorm = s / 100; const lNorm = l / 100; const hue2rgb = (p, q, t) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; let r, g, b; if (sNorm === 0) { r = g = b = lNorm; } else { const q = lNorm < 0.5 ? lNorm * (1 + sNorm) : lNorm + sNorm - lNorm * sNorm; const p = 2 * lNorm - q; r = hue2rgb(p, q, hNorm + 1 / 3); g = hue2rgb(p, q, hNorm); b = hue2rgb(p, q, hNorm - 1 / 3); } return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) }; } function rgbToHsv(r, g, b) { const rgb = validateRgbColor(r, g, b); const rNorm = rgb.r / 255; const gNorm = rgb.g / 255; const bNorm = rgb.b / 255; const max = Math.max(rNorm, gNorm, bNorm); const min = Math.min(rNorm, gNorm, bNorm); const delta = max - min; let h = 0; const s = max === 0 ? 0 : delta / max; const v = max; if (delta !== 0) { switch (max) { case rNorm: h = (gNorm - bNorm) / delta % 6; break; case gNorm: h = (bNorm - rNorm) / delta + 2; break; case bNorm: h = (rNorm - gNorm) / delta + 4; break; } h *= 60; if (h < 0) h += 360; } return { h: Math.round(h), s: Math.round(s * 100), v: Math.round(v * 100) }; } function rgbToCmyk(r, g, b) { const rgb = validateRgbColor(r, g, b); const rNorm = rgb.r / 255; const gNorm = rgb.g / 255; const bNorm = rgb.b / 255; const k = 1 - Math.max(rNorm, gNorm, bNorm); if (k === 1) { return { c: 0, m: 0, y: 0, k: 100 }; } const c = (1 - rNorm - k) / (1 - k); const m = (1 - gNorm - k) / (1 - k); const y = (1 - bNorm - k) / (1 - k); return { c: Math.round(c * 100), m: Math.round(m * 100), y: Math.round(y * 100), k: Math.round(k * 100) }; } function cmykToRgb(c, m, y, k) { if (c < 0 || c > 100 || m < 0 || m > 100 || y < 0 || y > 100 || k < 0 || k > 100) { throw new Error("CMYK values must be between 0 and 100"); } const cNorm = c / 100; const mNorm = m / 100; const yNorm = y / 100; const kNorm = k / 100; const r = 255 * (1 - cNorm) * (1 - kNorm); const g = 255 * (1 - mNorm) * (1 - kNorm); const b = 255 * (1 - yNorm) * (1 - kNorm); return { r: Math.round(r), g: Math.round(g), b: Math.round(b) }; } function calculateLuminance(r, g, b) { const rgb = validateRgbColor(r, g, b); const toLinear = (value) => { const normalized = value / 255; return normalized <= 0.03928 ? normalized / 12.92 : Math.pow((normalized + 0.055) / 1.055, 2.4); }; return 0.2126 * toLinear(rgb.r) + 0.7152 * toLinear(rgb.g) + 0.0722 * toLinear(rgb.b); } function calculateContrastRatio(luminance1, luminance2) { const lighter = Math.max(luminance1, luminance2); const darker = Math.min(luminance1, luminance2); return (lighter + 0.05) / (darker + 0.05); } function analyzeColor(color) { let rgb; if (typeof color === "string") { rgb = hexToRgb(color); } else { rgb = validateRgbColor(color.r, color.g, color.b); } const hex = rgbToHex(rgb.r, rgb.g, rgb.b); const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b); const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b); const cmyk = rgbToCmyk(rgb.r, rgb.g, rgb.b); const luminance = calculateLuminance(rgb.r, rgb.g, rgb.b); const whiteLuminance = 1; const blackLuminance = 0; const contrastWhite = calculateContrastRatio(luminance, whiteLuminance); const contrastBlack = calculateContrastRatio(luminance, blackLuminance); return { hex, rgb, hsl, hsv, cmyk, luminance, contrast: { white: contrastWhite, black: contrastBlack }, accessibility: { aa: Math.max(contrastWhite, contrastBlack) >= 4.5, aaa: Math.max(contrastWhite, contrastBlack) >= 7 } }; } // ../core/src/diff.ts function calculateSimilarity(text1, text2) { if (text1 === text2) return 100; if (text1.length === 0 || text2.length === 0) return 0; const matrix = []; for (let i = 0; i <= text1.length; i++) { matrix[i] = [i]; } for (let j = 0; j <= text2.length; j++) { matrix[0][j] = j; } for (let i = 1; i <= text1.length; i++) { for (let j = 1; j <= text2.length; j++) { if (text1.charAt(i - 1) === text2.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, // substitution matrix[i][j - 1] + 1, // insertion matrix[i - 1][j] + 1 // deletion ); } } } const distance = matrix[text1.length][text2.length]; const maxLength = Math.max(text1.length, text2.length); return Math.round((maxLength - distance) / maxLength * 100); } function longestCommonSubsequence(arr1, arr2) { const m = arr1.length; const n = arr2.length; const lcs = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0)); for (let i = 1; i <= m; i++) { for (let j = 1; j <= n; j++) { if (arr1[i - 1] === arr2[j - 1]) { lcs[i][j] = lcs[i - 1][j - 1] + 1; } else { lcs[i][j] = Math.max(lcs[i - 1][j], lcs[i][j - 1]); } } } return lcs; } function diffLines(text1, text2) { if (typeof text1 !== "string" || typeof text2 !== "string") { throw new Error("Both inputs must be strings"); } const lines1 = text1 === "" ? [] : text1.split("\n"); const lines2 = text2 === "" ? [] : text2.split("\n"); const lcs = longestCommonSubsequence(lines1, lines2); const diffLines2 = []; let i = lines1.length; let j = lines2.length; let lineNumber = 1; while (i > 0 || j > 0) { if (i > 0 && j > 0 && lines1[i - 1] === lines2[j - 1]) { diffLines2.unshift({ type: "unchanged", lineNumber: lineNumber++, content: lines1[i - 1], originalLineNumber: i, newLineNumber: j }); i--; j--; } else if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) { diffLines2.unshift({ type: "added", lineNumber: lineNumber++, content: lines2[j - 1], newLineNumber: j }); j--; } else if (i > 0 && (j === 0 || lcs[i][j - 1] < lcs[i - 1][j])) { diffLines2.unshift({ type: "removed", lineNumber: lineNumber++, content: lines1[i - 1], originalLineNumber: i }); i--; } } const stats = { added: diffLines2.filter((line) => line.type === "added").length, removed: diffLines2.filter((line) => line.type === "removed").length, modified: diffLines2.filter((line) => line.type === "modified").length, unchanged: diffLines2.filter((line) => line.type === "unchanged").length, totalLines: diffLines2.length }; const similarity = calculateSimilarity(text1, text2); return { lines: diffLines2, stats, similarity }; } function diffWords(text1, text2) { if (typeof text1 !== "string" || typeof text2 !== "string") { throw new Error("Both inputs must be strings"); } const words1 = text1.split(/(\s+)/); const words2 = text2.split(/(\s+)/); const lcs = longestCommonSubsequence(words1, words2); const diffLines2 = []; let i = words1.length; let j = words2.length; let lineNumber = 1; while (i > 0 || j > 0) { if (i > 0 && j > 0 && words1[i - 1] === words2[j - 1]) { diffLines2.unshift({ type: "unchanged", lineNumber: lineNumber++, content: words1[i - 1], originalLineNumber: i, newLineNumber: j }); i--; j--; } else if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) { diffLines2.unshift({ type: "added", lineNumber: lineNumber++, content: words2[j - 1], newLineNumber: j }); j--; } else if (i > 0 && (j === 0 || lcs[i][j - 1] < lcs[i - 1][j])) { diffLines2.unshift({ type: "removed", lineNumber: lineNumber++, content: words1[i - 1], originalLineNumber: i }); i--; } } const stats = { added: diffLines2.filter((line) => line.type === "added").length, removed: diffLines2.filter((line) => line.type === "removed").length, modified: diffLines2.filter((line) => line.type === "modified").length, unchanged: diffLines2.filter((line) => line.type === "unchanged").length, totalLines: diffLines2.length }; const similarity = calculateSimilarity(text1, text2); return { lines: diffLines2, stats, similarity }; } function diffCharacters(text1, text2) { if (typeof text1 !== "string" || typeof text2 !== "string") { throw new Error("Both inputs must be strings"); } const chars1 = text1.split(""); const chars2 = text2.split(""); const lcs = longestCommonSubsequence(chars1, chars2); const diffLines2 = []; let i = chars1.length; let j = chars2.length; let lineNumber = 1; while (i > 0 || j > 0) { if (i > 0 && j > 0 && chars1[i - 1] === chars2[j - 1]) { diffLines2.unshift({ type: "unchanged", lineNumber: lineNumber++, content: chars1[i - 1], originalLineNumber: i, newLineNumber: j }); i--; j--; } else if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) { diffLines2.unshift({ type: "added", lineNumber: lineNumber++, content: chars2[j - 1], newLineNumber: j }); j--; } else if (i > 0 && (j === 0 || lcs[i][j - 1] < lcs[i - 1][j])) { diffLines2.unshift({ type: "removed", lineNumber: lineNumber++, content: chars1[i - 1], originalLineNumber: i }); i--; } } const stats = { added: diffLines2.filter((line) => line.type === "added").length, removed: diffLines2.filter((line) => line.type === "removed").length, modified: diffLines2.filter((line) => line.type === "modified").length, unchanged: diffLines2.filter((line) => line.type === "unchanged").length, totalLines: diffLines2.length }; const similarity = calculateSimilarity(text1, text2); return { lines: diffLines2, stats, similarity }; } function diffText(text1, text2, mode = "line") { switch (mode) { case "line": return diffLines(text1, text2); case "word": return diffWords(text1, text2); case "character": return diffCharacters(text1, text2); default: throw new Error(`Unsupported diff mode: ${mode}`); } } function createUnifiedDiff(text1, text2, filename1 = "original", filename2 = "modified") { const diffResult = diffLines(text1, text2); const lines = []; lines.push(`--- ${filename1}`); lines.push(`+++ ${filename2}`); let originalLineNumber = 1; let newLineNumber = 1; for (const diffLine of diffResult.lines) { switch (diffLine.type) { case "removed": lines.push(`-${diffLine.content}`); originalLineNumber++; break; case "added": lines.push(`+${diffLine.content}`); newLineNumber++; break; case "unchanged": lines.push(` ${diffLine.content}`); originalLineNumber++; newLineNumber++; break; } } return lines.join("\n"); } function createSideBySideDiff(text1, text2) { const diffResult = diffLines(text1, text2); const result = []; for (const diffLine of diffResult.lines) { switch (diffLine.type) { case "removed": result.push({ original: [diffLine.content], modified: [""] }); break; case "added": result.push({ original: [""], modified: [diffLine.content] }); break; case "unchanged": result.push({ original: [diffLine.content], modified: [diffLine.content] }); break; } } return result; } // src/commands/base64.ts function createBase64Command() { const base64 = new Command("base64").description("Base64 encoding and decoding utilities"); base64.command("encode").description("Encode text to Base64").argument("<text>", "Text to encode").action((text) => { try { const result = encodeBase64(text); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); base64.command("decode").description("Decode Base64 to text").argument("<encoded>", "Base64 encoded text to decode").action((encoded) => { try { const result = decodeBase64(encoded); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); return base64; } // src/commands/json.ts import { Command as Command2 } from "commander"; function createJsonCommand() { const json = new Command2("json").description("JSON validation and formatting utilities"); json.command("validate").description("Validate JSON string").argument("<json>", "JSON string to validate").action((jsonString) => { try { const result = validateJson(jsonString); if (result.isValid) { console.log("\u2713 Valid JSON"); process.exit(0); } else { console.error("\u2717 Invalid JSON:", result.error); process.exit(1); } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); json.command("format").description("Format JSON with proper indentation").argument("<json>", "JSON string to format").option("-i, --indent <number>", "Number of spaces for indentation", "2").action((jsonString, options) => { try { const indent = parseInt(options.indent, 10); const result = formatJson(jsonString, indent); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); json.command("minify").description("Minify JSON by removing whitespace").argument("<json>", "JSON string to minify").action((jsonString) => { try { const result = minifyJson(jsonString); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); return json; } // src/commands/hex.ts import { Command as Command3 } from "commander"; function createHexCommand() { const hex = new Command3("hex").description("Hexadecimal conversion utilities"); hex.command("to-ascii").description("Convert hex to ASCII").argument("<hex>", "Hexadecimal string to convert").action((hexString) => { try { const result = hexToAscii(hexString); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); hex.command("from-ascii").description("Convert ASCII to hex").argument("<ascii>", "ASCII string to convert").action((ascii) => { try { const result = asciiToHex(ascii); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); hex.command("to-binary").description("Convert hex to binary").argument("<hex>", "Hexadecimal string to convert").action((hexString) => { try { const result = hexToBinary(hexString); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); hex.command("from-binary").description("Convert binary to hex").argument("<binary>", "Binary string to convert").action((binary) => { try { const result = binaryToHex(binary); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); hex.command("to-decimal").description("Convert hex to decimal").argument("<hex>", "Hexadecimal string to convert").action((hexString) => { try { const result = hexToDecimal(hexString); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); hex.command("from-decimal").description("Convert decimal to hex").argument("<decimal>", "Decimal number to convert").action((decimal) => { try { const num = parseInt(decimal, 10); if (isNaN(num)) { throw new Error("Invalid decimal number"); } const result = decimalToHex(num); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); return hex; } // src/commands/timestamp.ts import { Command as Command4 } from "commander"; function createTimestampCommand() { const timestamp = new Command4("timestamp").description("Timestamp conversion utilities"); timestamp.command("to-iso").description("Convert Unix timestamp to ISO string").argument("<timestamp>", "Unix timestamp to convert").action((ts) => { try { const num = parseInt(ts, 10); if (isNaN(num)) { throw new Error("Invalid timestamp"); } const result = unixToIso(num); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); timestamp.command("to-unix").description("Convert ISO string to Unix timestamp").argument("<iso>", "ISO string to convert").action((iso) => { try { const result = isoToUnix(iso); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); timestamp.command("now").description("Get current timestamp").option("-u, --unix", "Output as Unix timestamp").option("-i, --iso", "Output as ISO string").option("-f, --format", "Output as human-readable format").action((options) => { try { if (options.unix) { console.log(getCurrentUnixTimestamp()); } else if (options.iso) { console.log(getCurrentIsoTimestamp()); } else if (options.format) { console.log(formatTimestamp(getCurrentUnixTimestamp())); } else { const unix = getCurrentUnixTimestamp(); const iso = getCurrentIsoTimestamp(); const formatted = formatTimestamp(unix); console.log(`Unix: ${unix}`); console.log(`ISO: ${iso}`); console.log(`Formatted: ${formatted}`); } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); timestamp.command("format").description("Format timestamp as human-readable string").argument("<timestamp>", "Unix timestamp or ISO string to format").action((ts) => { try { const num = parseInt(ts, 10); const input = isNaN(num) ? ts : num; const result = formatTimestamp(input); console.log(result); } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); return timestamp; } // src/commands/uuid.ts import { Command as Command5 } from "commander"; function createUuidCommand() { const uuid = new Command5("uuid").description("UUID generation and validation utilities"); uuid.command("generate").description("Generate UUID v4").option("-c, --count <number>", "Number of UUIDs to generate", "1").action((options) => { try { const count = parseInt(options.count, 10); if (isNaN(count) || count < 1) { throw new Error("Count must be a positive number"); } if (count === 1) { console.log(generateUuidV4()); } else { const uuids = generateMultipleUuids(count); uuids.forEach((uuid2) => console.log(uuid2)); } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); uuid.command("validate").description("Validate UUID format").argument("<uuid>", "UUID to validate").action((uuidString) => { try { const isValid = isValidUuid(uuidString); if (isValid) { console.log("\u2713 Valid UUID"); process.exit(0); } else { console.log("\u2717 Invalid UUID"); process.exit(1); } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } }); return uuid; } // src/commands/cron.ts import { Command as Command6 } from "commander"; function createCronCommand() { const cronCommand = new Command6("cron"); cronCommand.description("Cron expression utilities"); cronCommand.command("validate").description("Validate a cron expression").argument("<expression>", "Cron expression to validate").action((expression) => { const result = validateCronExpression(expression); if (result.valid) { console.log("\u2705 Valid cron expression"); console.log(`Expression: ${expression}`); console.log(`Explanation: ${explainCronExpression(expression)}`); } else { console.error("\u274C Invalid cron expression"); console.error(`Error: ${result.error}`); process.exit(1); } }); cronCommand.command("explain").description("Explain what a cron expression does").argument("<expression>", "Cron expression to explain").action((expression) => { const validation = validateCronExpression(expression); if (!validation.valid) { console.error("\u274C Invalid cron expression"); console.error(`Error: ${validation.error}`); process.exit(1); } console.log(`Expression: ${expression}`); console.log(`Explanation: ${explainCronExpression(expression)}`); const expanded = expandCronExpression(expression); if (expanded !== expression) { console.log(`Expanded: ${expanded}`); } }); cronCommand.command("expand").description("Expand common cron expressions (@hourly, @daily, etc.)").argument("<expression>", "Common cron expressi