@nmakarov/cli-toolkit 0.11.3 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db.cjs +97 -2
- package/dist/db.cjs.map +1 -1
- package/dist/db.js +93 -1
- package/dist/db.js.map +1 -1
- package/dist/filedatabase.cjs +195 -15
- package/dist/filedatabase.cjs.map +1 -1
- package/dist/filedatabase.js +192 -14
- package/dist/filedatabase.js.map +1 -1
- package/dist/index.cjs +288 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +283 -13
- package/dist/index.js.map +1 -1
- package/dist/mock-server.cjs +168 -13
- package/dist/mock-server.cjs.map +1 -1
- package/dist/mock-server.js +168 -13
- package/dist/mock-server.js.map +1 -1
- package/dist/utils.cjs +251 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.js +199 -0
- package/dist/utils.js.map +1 -0
- package/package.json +6 -1
package/dist/utils.cjs
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/utils.ts
|
|
31
|
+
var utils_exports = {};
|
|
32
|
+
__export(utils_exports, {
|
|
33
|
+
bytesToHumanReadable: () => bytesToHumanReadable,
|
|
34
|
+
dateDiff: () => dateDiff,
|
|
35
|
+
ensurePath: () => ensurePath,
|
|
36
|
+
ensurePathSync: () => ensurePathSync,
|
|
37
|
+
formatDate: () => formatDate,
|
|
38
|
+
fromISOString: () => fromISOString,
|
|
39
|
+
generateVersionName: () => generateVersionName,
|
|
40
|
+
getDirname: () => getDirname,
|
|
41
|
+
getFileExtension: () => getFileExtension,
|
|
42
|
+
getFreeDiskSpace: () => getFreeDiskSpace,
|
|
43
|
+
humanReadableToBytes: () => humanReadableToBytes,
|
|
44
|
+
isTimestampFolder: () => isTimestampFolder,
|
|
45
|
+
maskValue: () => maskValue,
|
|
46
|
+
md5: () => md5,
|
|
47
|
+
nowISO: () => nowISO,
|
|
48
|
+
toISOString: () => toISOString
|
|
49
|
+
});
|
|
50
|
+
module.exports = __toCommonJS(utils_exports);
|
|
51
|
+
|
|
52
|
+
// src/utils/date-utils.ts
|
|
53
|
+
function formatDate(value, options = {}) {
|
|
54
|
+
if (value === void 0 || value === null) {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
const { timezone = "UTC", format = "iso" } = options;
|
|
58
|
+
let date;
|
|
59
|
+
if (value instanceof Date) {
|
|
60
|
+
date = value;
|
|
61
|
+
} else if (typeof value === "string") {
|
|
62
|
+
date = new Date(value);
|
|
63
|
+
} else if (typeof value === "number") {
|
|
64
|
+
date = new Date(value);
|
|
65
|
+
} else {
|
|
66
|
+
return "";
|
|
67
|
+
}
|
|
68
|
+
if (isNaN(date.getTime())) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
switch (format) {
|
|
72
|
+
case "iso":
|
|
73
|
+
return date.toISOString();
|
|
74
|
+
case "iso-date":
|
|
75
|
+
return date.toISOString().split("T")[0];
|
|
76
|
+
case "iso-time":
|
|
77
|
+
return date.toISOString().split("T")[1];
|
|
78
|
+
case "human":
|
|
79
|
+
if (timezone === "user") {
|
|
80
|
+
return date.toLocaleString();
|
|
81
|
+
}
|
|
82
|
+
return date.toUTCString();
|
|
83
|
+
default:
|
|
84
|
+
return date.toISOString();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function toISOString(value) {
|
|
88
|
+
return formatDate(value, { timezone: "UTC", format: "iso" });
|
|
89
|
+
}
|
|
90
|
+
function nowISO() {
|
|
91
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
92
|
+
}
|
|
93
|
+
function fromISOString(isoString) {
|
|
94
|
+
return new Date(isoString);
|
|
95
|
+
}
|
|
96
|
+
function dateDiff(start, end) {
|
|
97
|
+
const startDate = start instanceof Date ? start : new Date(start);
|
|
98
|
+
const endDate = end instanceof Date ? end : new Date(end);
|
|
99
|
+
const diffMs = endDate.getTime() - startDate.getTime();
|
|
100
|
+
return {
|
|
101
|
+
milliseconds: diffMs,
|
|
102
|
+
seconds: Math.floor(diffMs / 1e3),
|
|
103
|
+
minutes: Math.floor(diffMs / (1e3 * 60)),
|
|
104
|
+
hours: Math.floor(diffMs / (1e3 * 60 * 60)),
|
|
105
|
+
days: Math.floor(diffMs / (1e3 * 60 * 60 * 24))
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function isTimestampFolder(folderName) {
|
|
109
|
+
const isoRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|\.\d{3}Z)$/;
|
|
110
|
+
if (!isoRegex.test(folderName)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const date = new Date(folderName);
|
|
114
|
+
return !isNaN(date.getTime()) && date.getTime() > 0;
|
|
115
|
+
}
|
|
116
|
+
function generateVersionName(existingVersions = []) {
|
|
117
|
+
if (existingVersions.length === 0) {
|
|
118
|
+
const now = /* @__PURE__ */ new Date();
|
|
119
|
+
return now.toISOString().split(".")[0] + "Z";
|
|
120
|
+
}
|
|
121
|
+
const maxTimestamp = existingVersions.reduce((max, version) => {
|
|
122
|
+
const versionDate = new Date(version);
|
|
123
|
+
const maxDate2 = new Date(max);
|
|
124
|
+
return versionDate > maxDate2 ? version : max;
|
|
125
|
+
});
|
|
126
|
+
const maxDate = new Date(maxTimestamp);
|
|
127
|
+
const nextDate = new Date(maxDate.getTime() + 1e3);
|
|
128
|
+
return nextDate.toISOString().split(".")[0] + "Z";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/utils/fs-utils.ts
|
|
132
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
133
|
+
var import_path = __toESM(require("path"), 1);
|
|
134
|
+
var import_url = require("url");
|
|
135
|
+
async function ensurePath(...pathParts) {
|
|
136
|
+
const fullPath = import_path.default.resolve(...pathParts);
|
|
137
|
+
if (!import_fs.default.existsSync(fullPath)) {
|
|
138
|
+
await import_fs.default.promises.mkdir(fullPath, { recursive: true });
|
|
139
|
+
}
|
|
140
|
+
return fullPath;
|
|
141
|
+
}
|
|
142
|
+
function ensurePathSync(...pathParts) {
|
|
143
|
+
const fullPath = import_path.default.resolve(...pathParts);
|
|
144
|
+
if (!import_fs.default.existsSync(fullPath)) {
|
|
145
|
+
import_fs.default.mkdirSync(fullPath, { recursive: true });
|
|
146
|
+
}
|
|
147
|
+
return fullPath;
|
|
148
|
+
}
|
|
149
|
+
function getFileExtension(dataType) {
|
|
150
|
+
switch (dataType) {
|
|
151
|
+
case "json-array":
|
|
152
|
+
case "json-object":
|
|
153
|
+
return "json";
|
|
154
|
+
case "text":
|
|
155
|
+
return "txt";
|
|
156
|
+
case "xml":
|
|
157
|
+
return "xml";
|
|
158
|
+
default:
|
|
159
|
+
return "json";
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function getDirname(metaUrl) {
|
|
163
|
+
return import_path.default.dirname((0, import_url.fileURLToPath)(metaUrl));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/utils/os-utils.ts
|
|
167
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
168
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
169
|
+
var import_child_process = require("child_process");
|
|
170
|
+
function getFreeDiskSpace(targetPath) {
|
|
171
|
+
try {
|
|
172
|
+
let pathToCheck = targetPath;
|
|
173
|
+
if (!import_fs2.default.existsSync(targetPath)) {
|
|
174
|
+
const parentDir = import_path2.default.dirname(targetPath);
|
|
175
|
+
if (import_fs2.default.existsSync(parentDir)) {
|
|
176
|
+
pathToCheck = parentDir;
|
|
177
|
+
} else {
|
|
178
|
+
pathToCheck = process.platform === "win32" ? "C:\\" : "/";
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (process.platform === "win32") {
|
|
182
|
+
return null;
|
|
183
|
+
} else {
|
|
184
|
+
const stdout = (0, import_child_process.execSync)(`df -k "${pathToCheck}"`, { encoding: "utf8" });
|
|
185
|
+
const lines = stdout.trim().split("\n");
|
|
186
|
+
const parts = lines[1].split(/\s+/);
|
|
187
|
+
const freeKb = parseInt(parts[3], 10);
|
|
188
|
+
return freeKb * 1024;
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/utils/format-utils.ts
|
|
196
|
+
function bytesToHumanReadable(bytes) {
|
|
197
|
+
if (bytes === 0) return "0 B";
|
|
198
|
+
const k = 1024;
|
|
199
|
+
const sizes = ["B", "KB", "MB", "GB", "TB", "PB"];
|
|
200
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
201
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
202
|
+
}
|
|
203
|
+
function humanReadableToBytes(humanString) {
|
|
204
|
+
const units = {
|
|
205
|
+
"B": 1,
|
|
206
|
+
"KB": 1024,
|
|
207
|
+
"MB": 1024 * 1024,
|
|
208
|
+
"GB": 1024 * 1024 * 1024,
|
|
209
|
+
"TB": 1024 * 1024 * 1024 * 1024,
|
|
210
|
+
"PB": 1024 * 1024 * 1024 * 1024 * 1024
|
|
211
|
+
};
|
|
212
|
+
const match = humanString.trim().match(/^([\d.]+)\s*([A-Z]+)$/i);
|
|
213
|
+
if (!match) {
|
|
214
|
+
throw new Error(`Invalid format: ${humanString}. Expected format like "2MB" or "1.5 GB"`);
|
|
215
|
+
}
|
|
216
|
+
const value = parseFloat(match[1]);
|
|
217
|
+
const unit = match[2].toUpperCase();
|
|
218
|
+
if (!units[unit]) {
|
|
219
|
+
throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(", ")}`);
|
|
220
|
+
}
|
|
221
|
+
return Math.round(value * units[unit]);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/utils/crypto-utils.ts
|
|
225
|
+
var import_crypto = __toESM(require("crypto"), 1);
|
|
226
|
+
function md5(value) {
|
|
227
|
+
return import_crypto.default.createHash("md5").update(value).digest("hex");
|
|
228
|
+
}
|
|
229
|
+
function maskValue(value) {
|
|
230
|
+
return `[md5:${md5(value)}]`;
|
|
231
|
+
}
|
|
232
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
233
|
+
0 && (module.exports = {
|
|
234
|
+
bytesToHumanReadable,
|
|
235
|
+
dateDiff,
|
|
236
|
+
ensurePath,
|
|
237
|
+
ensurePathSync,
|
|
238
|
+
formatDate,
|
|
239
|
+
fromISOString,
|
|
240
|
+
generateVersionName,
|
|
241
|
+
getDirname,
|
|
242
|
+
getFileExtension,
|
|
243
|
+
getFreeDiskSpace,
|
|
244
|
+
humanReadableToBytes,
|
|
245
|
+
isTimestampFolder,
|
|
246
|
+
maskValue,
|
|
247
|
+
md5,
|
|
248
|
+
nowISO,
|
|
249
|
+
toISOString
|
|
250
|
+
});
|
|
251
|
+
//# sourceMappingURL=utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/utils/date-utils.ts","../src/utils/fs-utils.ts","../src/utils/os-utils.ts","../src/utils/format-utils.ts","../src/utils/crypto-utils.ts"],"sourcesContent":["// Re-export everything from the utils module directory\nexport * from \"./utils/index.js\";\n\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\nexport interface DateFormatOptions {\n timezone?: \"UTC\" | \"user\";\n format?: \"iso\" | \"iso-date\" | \"iso-time\" | \"human\";\n}\n\n/**\n * Format a date string or Date object to ISO8601 format in specified timezone\n * Always returns UTC-based ISO strings (YYYY-MM-DDTHH:mm:ssZ) as internal representation\n * \n * @param value - Date object, ISO string, or timestamp\n * @param options - Formatting options\n * @returns ISO8601 formatted string\n */\nexport function formatDate(value: Date | string | number | undefined, options: DateFormatOptions = {}): string {\n if (value === undefined || value === null) {\n return \"\";\n }\n\n const { timezone = \"UTC\", format = \"iso\" } = options;\n \n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === \"string\") {\n date = new Date(value);\n } else if (typeof value === \"number\") {\n date = new Date(value);\n } else {\n return \"\";\n }\n\n if (isNaN(date.getTime())) {\n return \"\";\n }\n\n // Format based on requested format\n switch (format) {\n case \"iso\":\n // Full ISO8601: 2025-01-01T01:01:01Z\n return date.toISOString();\n \n case \"iso-date\":\n // Date only: 2025-01-01\n return date.toISOString().split(\"T\")[0];\n \n case \"iso-time\":\n // Time only: 01:01:01Z\n return date.toISOString().split(\"T\")[1];\n \n case \"human\":\n // Human-readable: Jan 1, 2025 01:01:01 UTC\n if (timezone === \"user\") {\n return date.toLocaleString();\n }\n return date.toUTCString();\n \n default:\n return date.toISOString();\n }\n}\n\n/**\n * Parse a date value and return ISO8601 string in UTC\n * This is the canonical format for internal storage\n * \n * @param value - Date object or string\n * @returns ISO8601 string in UTC timezone\n */\nexport function toISOString(value: Date | string | number | undefined): string {\n return formatDate(value, { timezone: \"UTC\", format: \"iso\" });\n}\n\n/**\n * Get current timestamp as ISO8601 string in UTC\n * @returns Current time as ISO8601 string\n */\nexport function nowISO(): string {\n return new Date().toISOString();\n}\n\n/**\n * Parse ISO8601 string to Date object\n * @param isoString - ISO8601 formatted string\n * @returns Date object\n */\nexport function fromISOString(isoString: string): Date {\n return new Date(isoString);\n}\n\n/**\n * Calculate difference between two dates in various units\n * @param start - Start date (ISO string or Date)\n * @param end - End date (ISO string or Date)\n * @returns Object with duration in multiple units\n */\nexport function dateDiff(\n start: Date | string,\n end: Date | string\n): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\n} {\n const startDate = start instanceof Date ? start : new Date(start);\n const endDate = end instanceof Date ? end : new Date(end);\n \n const diffMs = endDate.getTime() - startDate.getTime();\n \n return {\n milliseconds: diffMs,\n seconds: Math.floor(diffMs / 1000),\n minutes: Math.floor(diffMs / (1000 * 60)),\n hours: Math.floor(diffMs / (1000 * 60 * 60)),\n days: Math.floor(diffMs / (1000 * 60 * 60 * 24))\n };\n}\n\n/**\n * Check if a folder name looks like an ISO8601 timestamp\n * Used to identify version folders vs regular folders\n * @param folderName - Folder name to check\n * @returns true if the folder name is a valid ISO8601 timestamp\n */\nexport function isTimestampFolder(folderName: string): boolean {\n // Match ISO8601 format: YYYY-MM-DDTHH:mm:ssZ\n const isoRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|\\.\\d{3}Z)$/;\n \n if (!isoRegex.test(folderName)) {\n return false;\n }\n \n const date = new Date(folderName);\n return !isNaN(date.getTime()) && date.getTime() > 0;\n}\n\n/**\n * Generate a new version name (ISO8601 timestamp)\n * If existingVersions provided, ensures the new version is later than all existing ones\n * @param existingVersions - Array of existing version timestamps\n * @returns New version timestamp that is unique and later than existing ones\n */\nexport function generateVersionName(existingVersions: string[] = []): string {\n if (existingVersions.length === 0) {\n // No existing versions, use current timestamp\n const now = new Date();\n return now.toISOString().split(\".\")[0] + \"Z\";\n }\n \n // Find the maximum timestamp among all existing versions\n const maxTimestamp = existingVersions.reduce((max, version) => {\n const versionDate = new Date(version);\n const maxDate = new Date(max);\n return versionDate > maxDate ? version : max;\n });\n \n // Increment by 1 second to ensure uniqueness\n const maxDate = new Date(maxTimestamp);\n const nextDate = new Date(maxDate.getTime() + 1000);\n \n return nextDate.toISOString().split(\".\")[0] + \"Z\";\n}\n\n","/**\n * File System Utilities\n * \n * Helper functions for file system operations like path management,\n * directory creation, and file type detection\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Ensure a directory path exists, creating it if necessary\n * Returns the absolute path\n */\nexport async function ensurePath(...pathParts: string[]): Promise<string> {\n const fullPath = path.resolve(...pathParts);\n \n if (!fs.existsSync(fullPath)) {\n await fs.promises.mkdir(fullPath, { recursive: true });\n }\n \n return fullPath;\n}\n\n/**\n * Synchronous version of ensurePath\n */\nexport function ensurePathSync(...pathParts: string[]): string {\n const fullPath = path.resolve(...pathParts);\n \n if (!fs.existsSync(fullPath)) {\n fs.mkdirSync(fullPath, { recursive: true });\n }\n \n return fullPath;\n}\n\n/**\n * Get file extension for a given data type\n */\nexport function getFileExtension(dataType: string): string {\n switch (dataType) {\n case \"json-array\":\n case \"json-object\":\n return \"json\";\n case \"text\":\n return \"txt\";\n case \"xml\":\n return \"xml\";\n default:\n return \"json\";\n }\n}\n\n/**\n * Get __dirname equivalent for ES modules\n * \n * Returns the directory path of the module file\n * Useful for resolving relative paths in ES modules where __dirname is not available\n * \n * @param metaUrl - The import.meta.url from the calling module (must be passed from calling module)\n * @returns The directory path of the module\n * \n * @example\n * ```typescript\n * import { getDirname } from \"@nmakarov/cli-toolkit/utils\";\n * const __dirname = getDirname(import.meta.url);\n * ```\n */\nexport function getDirname(metaUrl: string | URL): string {\n return path.dirname(fileURLToPath(metaUrl));\n}\n\n","/**\n * Operating System Utilities\n * \n * Helper functions for interacting with the operating system\n * to get system statistics and information\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { execSync } from \"child_process\";\n\n/**\n * Get free disk space for a given path (in bytes)\n * Returns null if unable to determine\n * Uses `df` command on Unix-like systems\n */\nexport function getFreeDiskSpace(targetPath: string): number | null {\n try {\n // If the target path doesn't exist, use its parent directory\n let pathToCheck = targetPath;\n if (!fs.existsSync(targetPath)) {\n const parentDir = path.dirname(targetPath);\n if (fs.existsSync(parentDir)) {\n pathToCheck = parentDir;\n } else {\n // If parent doesn't exist either, use the root directory\n pathToCheck = process.platform === \"win32\" ? \"C:\\\\\" : \"/\";\n }\n }\n\n if (process.platform === \"win32\") {\n // Windows: use wmic command\n // Note: This is a simplified implementation, may need adjustments\n return null; // TODO: Implement robust Windows support\n } else {\n // Unix-like systems: use df command\n const stdout = execSync(`df -k \"${pathToCheck}\"`, { encoding: \"utf8\" });\n const lines = stdout.trim().split(\"\\n\");\n const parts = lines[1].split(/\\s+/); // second line, split on whitespace\n const freeKb = parseInt(parts[3], 10); // 4th column is \"Available\"\n return freeKb * 1024; // Convert to bytes\n }\n } catch (error) {\n // Silently fail and return null\n return null;\n }\n}\n\n","/**\n * Formatting Utilities\n * \n * Helper functions for converting between different data formats\n * and human-readable representations\n */\n\n/**\n * Convert bytes to human-readable format (e.g., \"1.5 MB\")\n */\nexport function bytesToHumanReadable(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n \n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n \n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n}\n\n/**\n * Convert human-readable format to bytes (e.g., \"1.5 MB\" -> 1572864)\n */\nexport function humanReadableToBytes(humanString: string): number {\n const units: Record<string, number> = {\n \"B\": 1,\n \"KB\": 1024,\n \"MB\": 1024 * 1024,\n \"GB\": 1024 * 1024 * 1024,\n \"TB\": 1024 * 1024 * 1024 * 1024,\n \"PB\": 1024 * 1024 * 1024 * 1024 * 1024,\n };\n \n const match = humanString.trim().match(/^([\\d.]+)\\s*([A-Z]+)$/i);\n if (!match) {\n throw new Error(`Invalid format: ${humanString}. Expected format like \"2MB\" or \"1.5 GB\"`);\n }\n \n const value = parseFloat(match[1]);\n const unit = match[2].toUpperCase();\n \n if (!units[unit]) {\n throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(\", \")}`);\n }\n \n return Math.round(value * units[unit]);\n}\n\n","/**\n * Cryptography Utilities\n * \n * Helper functions for hashing, encryption, and data masking\n */\n\nimport crypto from \"crypto\";\n\n/**\n * Calculate MD5 hash of a string (useful for content fingerprinting)\n */\nexport function md5(value: string): string {\n return crypto.createHash(\"md5\").update(value).digest(\"hex\");\n}\n\n/**\n * Sanitize sensitive data by replacing with MD5 hash\n * Useful for logging sensitive information while maintaining traceability\n */\nexport function maskValue(value: string): string {\n return `[md5:${md5(value)}]`;\n}\n\n"],"mappings":"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","names":["maxDate","path","fs","import_fs","import_path","fs","path","crypto"]}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// src/utils/date-utils.ts
|
|
2
|
+
function formatDate(value, options = {}) {
|
|
3
|
+
if (value === void 0 || value === null) {
|
|
4
|
+
return "";
|
|
5
|
+
}
|
|
6
|
+
const { timezone = "UTC", format = "iso" } = options;
|
|
7
|
+
let date;
|
|
8
|
+
if (value instanceof Date) {
|
|
9
|
+
date = value;
|
|
10
|
+
} else if (typeof value === "string") {
|
|
11
|
+
date = new Date(value);
|
|
12
|
+
} else if (typeof value === "number") {
|
|
13
|
+
date = new Date(value);
|
|
14
|
+
} else {
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
if (isNaN(date.getTime())) {
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
switch (format) {
|
|
21
|
+
case "iso":
|
|
22
|
+
return date.toISOString();
|
|
23
|
+
case "iso-date":
|
|
24
|
+
return date.toISOString().split("T")[0];
|
|
25
|
+
case "iso-time":
|
|
26
|
+
return date.toISOString().split("T")[1];
|
|
27
|
+
case "human":
|
|
28
|
+
if (timezone === "user") {
|
|
29
|
+
return date.toLocaleString();
|
|
30
|
+
}
|
|
31
|
+
return date.toUTCString();
|
|
32
|
+
default:
|
|
33
|
+
return date.toISOString();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function toISOString(value) {
|
|
37
|
+
return formatDate(value, { timezone: "UTC", format: "iso" });
|
|
38
|
+
}
|
|
39
|
+
function nowISO() {
|
|
40
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
41
|
+
}
|
|
42
|
+
function fromISOString(isoString) {
|
|
43
|
+
return new Date(isoString);
|
|
44
|
+
}
|
|
45
|
+
function dateDiff(start, end) {
|
|
46
|
+
const startDate = start instanceof Date ? start : new Date(start);
|
|
47
|
+
const endDate = end instanceof Date ? end : new Date(end);
|
|
48
|
+
const diffMs = endDate.getTime() - startDate.getTime();
|
|
49
|
+
return {
|
|
50
|
+
milliseconds: diffMs,
|
|
51
|
+
seconds: Math.floor(diffMs / 1e3),
|
|
52
|
+
minutes: Math.floor(diffMs / (1e3 * 60)),
|
|
53
|
+
hours: Math.floor(diffMs / (1e3 * 60 * 60)),
|
|
54
|
+
days: Math.floor(diffMs / (1e3 * 60 * 60 * 24))
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function isTimestampFolder(folderName) {
|
|
58
|
+
const isoRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|\.\d{3}Z)$/;
|
|
59
|
+
if (!isoRegex.test(folderName)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const date = new Date(folderName);
|
|
63
|
+
return !isNaN(date.getTime()) && date.getTime() > 0;
|
|
64
|
+
}
|
|
65
|
+
function generateVersionName(existingVersions = []) {
|
|
66
|
+
if (existingVersions.length === 0) {
|
|
67
|
+
const now = /* @__PURE__ */ new Date();
|
|
68
|
+
return now.toISOString().split(".")[0] + "Z";
|
|
69
|
+
}
|
|
70
|
+
const maxTimestamp = existingVersions.reduce((max, version) => {
|
|
71
|
+
const versionDate = new Date(version);
|
|
72
|
+
const maxDate2 = new Date(max);
|
|
73
|
+
return versionDate > maxDate2 ? version : max;
|
|
74
|
+
});
|
|
75
|
+
const maxDate = new Date(maxTimestamp);
|
|
76
|
+
const nextDate = new Date(maxDate.getTime() + 1e3);
|
|
77
|
+
return nextDate.toISOString().split(".")[0] + "Z";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/utils/fs-utils.ts
|
|
81
|
+
import fs from "fs";
|
|
82
|
+
import path from "path";
|
|
83
|
+
import { fileURLToPath } from "url";
|
|
84
|
+
async function ensurePath(...pathParts) {
|
|
85
|
+
const fullPath = path.resolve(...pathParts);
|
|
86
|
+
if (!fs.existsSync(fullPath)) {
|
|
87
|
+
await fs.promises.mkdir(fullPath, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
return fullPath;
|
|
90
|
+
}
|
|
91
|
+
function ensurePathSync(...pathParts) {
|
|
92
|
+
const fullPath = path.resolve(...pathParts);
|
|
93
|
+
if (!fs.existsSync(fullPath)) {
|
|
94
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
return fullPath;
|
|
97
|
+
}
|
|
98
|
+
function getFileExtension(dataType) {
|
|
99
|
+
switch (dataType) {
|
|
100
|
+
case "json-array":
|
|
101
|
+
case "json-object":
|
|
102
|
+
return "json";
|
|
103
|
+
case "text":
|
|
104
|
+
return "txt";
|
|
105
|
+
case "xml":
|
|
106
|
+
return "xml";
|
|
107
|
+
default:
|
|
108
|
+
return "json";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function getDirname(metaUrl) {
|
|
112
|
+
return path.dirname(fileURLToPath(metaUrl));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/utils/os-utils.ts
|
|
116
|
+
import fs2 from "fs";
|
|
117
|
+
import path2 from "path";
|
|
118
|
+
import { execSync } from "child_process";
|
|
119
|
+
function getFreeDiskSpace(targetPath) {
|
|
120
|
+
try {
|
|
121
|
+
let pathToCheck = targetPath;
|
|
122
|
+
if (!fs2.existsSync(targetPath)) {
|
|
123
|
+
const parentDir = path2.dirname(targetPath);
|
|
124
|
+
if (fs2.existsSync(parentDir)) {
|
|
125
|
+
pathToCheck = parentDir;
|
|
126
|
+
} else {
|
|
127
|
+
pathToCheck = process.platform === "win32" ? "C:\\" : "/";
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (process.platform === "win32") {
|
|
131
|
+
return null;
|
|
132
|
+
} else {
|
|
133
|
+
const stdout = execSync(`df -k "${pathToCheck}"`, { encoding: "utf8" });
|
|
134
|
+
const lines = stdout.trim().split("\n");
|
|
135
|
+
const parts = lines[1].split(/\s+/);
|
|
136
|
+
const freeKb = parseInt(parts[3], 10);
|
|
137
|
+
return freeKb * 1024;
|
|
138
|
+
}
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/utils/format-utils.ts
|
|
145
|
+
function bytesToHumanReadable(bytes) {
|
|
146
|
+
if (bytes === 0) return "0 B";
|
|
147
|
+
const k = 1024;
|
|
148
|
+
const sizes = ["B", "KB", "MB", "GB", "TB", "PB"];
|
|
149
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
150
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
151
|
+
}
|
|
152
|
+
function humanReadableToBytes(humanString) {
|
|
153
|
+
const units = {
|
|
154
|
+
"B": 1,
|
|
155
|
+
"KB": 1024,
|
|
156
|
+
"MB": 1024 * 1024,
|
|
157
|
+
"GB": 1024 * 1024 * 1024,
|
|
158
|
+
"TB": 1024 * 1024 * 1024 * 1024,
|
|
159
|
+
"PB": 1024 * 1024 * 1024 * 1024 * 1024
|
|
160
|
+
};
|
|
161
|
+
const match = humanString.trim().match(/^([\d.]+)\s*([A-Z]+)$/i);
|
|
162
|
+
if (!match) {
|
|
163
|
+
throw new Error(`Invalid format: ${humanString}. Expected format like "2MB" or "1.5 GB"`);
|
|
164
|
+
}
|
|
165
|
+
const value = parseFloat(match[1]);
|
|
166
|
+
const unit = match[2].toUpperCase();
|
|
167
|
+
if (!units[unit]) {
|
|
168
|
+
throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(", ")}`);
|
|
169
|
+
}
|
|
170
|
+
return Math.round(value * units[unit]);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/utils/crypto-utils.ts
|
|
174
|
+
import crypto from "crypto";
|
|
175
|
+
function md5(value) {
|
|
176
|
+
return crypto.createHash("md5").update(value).digest("hex");
|
|
177
|
+
}
|
|
178
|
+
function maskValue(value) {
|
|
179
|
+
return `[md5:${md5(value)}]`;
|
|
180
|
+
}
|
|
181
|
+
export {
|
|
182
|
+
bytesToHumanReadable,
|
|
183
|
+
dateDiff,
|
|
184
|
+
ensurePath,
|
|
185
|
+
ensurePathSync,
|
|
186
|
+
formatDate,
|
|
187
|
+
fromISOString,
|
|
188
|
+
generateVersionName,
|
|
189
|
+
getDirname,
|
|
190
|
+
getFileExtension,
|
|
191
|
+
getFreeDiskSpace,
|
|
192
|
+
humanReadableToBytes,
|
|
193
|
+
isTimestampFolder,
|
|
194
|
+
maskValue,
|
|
195
|
+
md5,
|
|
196
|
+
nowISO,
|
|
197
|
+
toISOString
|
|
198
|
+
};
|
|
199
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/date-utils.ts","../src/utils/fs-utils.ts","../src/utils/os-utils.ts","../src/utils/format-utils.ts","../src/utils/crypto-utils.ts"],"sourcesContent":["/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\nexport interface DateFormatOptions {\n timezone?: \"UTC\" | \"user\";\n format?: \"iso\" | \"iso-date\" | \"iso-time\" | \"human\";\n}\n\n/**\n * Format a date string or Date object to ISO8601 format in specified timezone\n * Always returns UTC-based ISO strings (YYYY-MM-DDTHH:mm:ssZ) as internal representation\n * \n * @param value - Date object, ISO string, or timestamp\n * @param options - Formatting options\n * @returns ISO8601 formatted string\n */\nexport function formatDate(value: Date | string | number | undefined, options: DateFormatOptions = {}): string {\n if (value === undefined || value === null) {\n return \"\";\n }\n\n const { timezone = \"UTC\", format = \"iso\" } = options;\n \n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === \"string\") {\n date = new Date(value);\n } else if (typeof value === \"number\") {\n date = new Date(value);\n } else {\n return \"\";\n }\n\n if (isNaN(date.getTime())) {\n return \"\";\n }\n\n // Format based on requested format\n switch (format) {\n case \"iso\":\n // Full ISO8601: 2025-01-01T01:01:01Z\n return date.toISOString();\n \n case \"iso-date\":\n // Date only: 2025-01-01\n return date.toISOString().split(\"T\")[0];\n \n case \"iso-time\":\n // Time only: 01:01:01Z\n return date.toISOString().split(\"T\")[1];\n \n case \"human\":\n // Human-readable: Jan 1, 2025 01:01:01 UTC\n if (timezone === \"user\") {\n return date.toLocaleString();\n }\n return date.toUTCString();\n \n default:\n return date.toISOString();\n }\n}\n\n/**\n * Parse a date value and return ISO8601 string in UTC\n * This is the canonical format for internal storage\n * \n * @param value - Date object or string\n * @returns ISO8601 string in UTC timezone\n */\nexport function toISOString(value: Date | string | number | undefined): string {\n return formatDate(value, { timezone: \"UTC\", format: \"iso\" });\n}\n\n/**\n * Get current timestamp as ISO8601 string in UTC\n * @returns Current time as ISO8601 string\n */\nexport function nowISO(): string {\n return new Date().toISOString();\n}\n\n/**\n * Parse ISO8601 string to Date object\n * @param isoString - ISO8601 formatted string\n * @returns Date object\n */\nexport function fromISOString(isoString: string): Date {\n return new Date(isoString);\n}\n\n/**\n * Calculate difference between two dates in various units\n * @param start - Start date (ISO string or Date)\n * @param end - End date (ISO string or Date)\n * @returns Object with duration in multiple units\n */\nexport function dateDiff(\n start: Date | string,\n end: Date | string\n): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\n} {\n const startDate = start instanceof Date ? start : new Date(start);\n const endDate = end instanceof Date ? end : new Date(end);\n \n const diffMs = endDate.getTime() - startDate.getTime();\n \n return {\n milliseconds: diffMs,\n seconds: Math.floor(diffMs / 1000),\n minutes: Math.floor(diffMs / (1000 * 60)),\n hours: Math.floor(diffMs / (1000 * 60 * 60)),\n days: Math.floor(diffMs / (1000 * 60 * 60 * 24))\n };\n}\n\n/**\n * Check if a folder name looks like an ISO8601 timestamp\n * Used to identify version folders vs regular folders\n * @param folderName - Folder name to check\n * @returns true if the folder name is a valid ISO8601 timestamp\n */\nexport function isTimestampFolder(folderName: string): boolean {\n // Match ISO8601 format: YYYY-MM-DDTHH:mm:ssZ\n const isoRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|\\.\\d{3}Z)$/;\n \n if (!isoRegex.test(folderName)) {\n return false;\n }\n \n const date = new Date(folderName);\n return !isNaN(date.getTime()) && date.getTime() > 0;\n}\n\n/**\n * Generate a new version name (ISO8601 timestamp)\n * If existingVersions provided, ensures the new version is later than all existing ones\n * @param existingVersions - Array of existing version timestamps\n * @returns New version timestamp that is unique and later than existing ones\n */\nexport function generateVersionName(existingVersions: string[] = []): string {\n if (existingVersions.length === 0) {\n // No existing versions, use current timestamp\n const now = new Date();\n return now.toISOString().split(\".\")[0] + \"Z\";\n }\n \n // Find the maximum timestamp among all existing versions\n const maxTimestamp = existingVersions.reduce((max, version) => {\n const versionDate = new Date(version);\n const maxDate = new Date(max);\n return versionDate > maxDate ? version : max;\n });\n \n // Increment by 1 second to ensure uniqueness\n const maxDate = new Date(maxTimestamp);\n const nextDate = new Date(maxDate.getTime() + 1000);\n \n return nextDate.toISOString().split(\".\")[0] + \"Z\";\n}\n\n","/**\n * File System Utilities\n * \n * Helper functions for file system operations like path management,\n * directory creation, and file type detection\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Ensure a directory path exists, creating it if necessary\n * Returns the absolute path\n */\nexport async function ensurePath(...pathParts: string[]): Promise<string> {\n const fullPath = path.resolve(...pathParts);\n \n if (!fs.existsSync(fullPath)) {\n await fs.promises.mkdir(fullPath, { recursive: true });\n }\n \n return fullPath;\n}\n\n/**\n * Synchronous version of ensurePath\n */\nexport function ensurePathSync(...pathParts: string[]): string {\n const fullPath = path.resolve(...pathParts);\n \n if (!fs.existsSync(fullPath)) {\n fs.mkdirSync(fullPath, { recursive: true });\n }\n \n return fullPath;\n}\n\n/**\n * Get file extension for a given data type\n */\nexport function getFileExtension(dataType: string): string {\n switch (dataType) {\n case \"json-array\":\n case \"json-object\":\n return \"json\";\n case \"text\":\n return \"txt\";\n case \"xml\":\n return \"xml\";\n default:\n return \"json\";\n }\n}\n\n/**\n * Get __dirname equivalent for ES modules\n * \n * Returns the directory path of the module file\n * Useful for resolving relative paths in ES modules where __dirname is not available\n * \n * @param metaUrl - The import.meta.url from the calling module (must be passed from calling module)\n * @returns The directory path of the module\n * \n * @example\n * ```typescript\n * import { getDirname } from \"@nmakarov/cli-toolkit/utils\";\n * const __dirname = getDirname(import.meta.url);\n * ```\n */\nexport function getDirname(metaUrl: string | URL): string {\n return path.dirname(fileURLToPath(metaUrl));\n}\n\n","/**\n * Operating System Utilities\n * \n * Helper functions for interacting with the operating system\n * to get system statistics and information\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { execSync } from \"child_process\";\n\n/**\n * Get free disk space for a given path (in bytes)\n * Returns null if unable to determine\n * Uses `df` command on Unix-like systems\n */\nexport function getFreeDiskSpace(targetPath: string): number | null {\n try {\n // If the target path doesn't exist, use its parent directory\n let pathToCheck = targetPath;\n if (!fs.existsSync(targetPath)) {\n const parentDir = path.dirname(targetPath);\n if (fs.existsSync(parentDir)) {\n pathToCheck = parentDir;\n } else {\n // If parent doesn't exist either, use the root directory\n pathToCheck = process.platform === \"win32\" ? \"C:\\\\\" : \"/\";\n }\n }\n\n if (process.platform === \"win32\") {\n // Windows: use wmic command\n // Note: This is a simplified implementation, may need adjustments\n return null; // TODO: Implement robust Windows support\n } else {\n // Unix-like systems: use df command\n const stdout = execSync(`df -k \"${pathToCheck}\"`, { encoding: \"utf8\" });\n const lines = stdout.trim().split(\"\\n\");\n const parts = lines[1].split(/\\s+/); // second line, split on whitespace\n const freeKb = parseInt(parts[3], 10); // 4th column is \"Available\"\n return freeKb * 1024; // Convert to bytes\n }\n } catch (error) {\n // Silently fail and return null\n return null;\n }\n}\n\n","/**\n * Formatting Utilities\n * \n * Helper functions for converting between different data formats\n * and human-readable representations\n */\n\n/**\n * Convert bytes to human-readable format (e.g., \"1.5 MB\")\n */\nexport function bytesToHumanReadable(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n \n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n \n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n}\n\n/**\n * Convert human-readable format to bytes (e.g., \"1.5 MB\" -> 1572864)\n */\nexport function humanReadableToBytes(humanString: string): number {\n const units: Record<string, number> = {\n \"B\": 1,\n \"KB\": 1024,\n \"MB\": 1024 * 1024,\n \"GB\": 1024 * 1024 * 1024,\n \"TB\": 1024 * 1024 * 1024 * 1024,\n \"PB\": 1024 * 1024 * 1024 * 1024 * 1024,\n };\n \n const match = humanString.trim().match(/^([\\d.]+)\\s*([A-Z]+)$/i);\n if (!match) {\n throw new Error(`Invalid format: ${humanString}. Expected format like \"2MB\" or \"1.5 GB\"`);\n }\n \n const value = parseFloat(match[1]);\n const unit = match[2].toUpperCase();\n \n if (!units[unit]) {\n throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(\", \")}`);\n }\n \n return Math.round(value * units[unit]);\n}\n\n","/**\n * Cryptography Utilities\n * \n * Helper functions for hashing, encryption, and data masking\n */\n\nimport crypto from \"crypto\";\n\n/**\n * Calculate MD5 hash of a string (useful for content fingerprinting)\n */\nexport function md5(value: string): string {\n return crypto.createHash(\"md5\").update(value).digest(\"hex\");\n}\n\n/**\n * Sanitize sensitive data by replacing with MD5 hash\n * Useful for logging sensitive information while maintaining traceability\n */\nexport function maskValue(value: string): string {\n return `[md5:${md5(value)}]`;\n}\n\n"],"mappings":"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","names":["maxDate","fs","path"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nmakarov/cli-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "A comprehensive toolkit for building CLI applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -61,6 +61,11 @@
|
|
|
61
61
|
"types": "./dist/db.d.ts",
|
|
62
62
|
"import": "./dist/db.js",
|
|
63
63
|
"require": "./dist/db.cjs"
|
|
64
|
+
},
|
|
65
|
+
"./utils": {
|
|
66
|
+
"types": "./dist/utils.d.ts",
|
|
67
|
+
"import": "./dist/utils.js",
|
|
68
|
+
"require": "./dist/utils.cjs"
|
|
64
69
|
}
|
|
65
70
|
},
|
|
66
71
|
"scripts": {
|