@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
JavaScript
#!/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