@utilix-tech/sdk 0.1.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.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +199 -0
  3. package/dist/api-8aZtWhSj.d.cts +308 -0
  4. package/dist/api-8aZtWhSj.d.ts +308 -0
  5. package/dist/chunk-2CJSLYWI.js +520 -0
  6. package/dist/chunk-3BAHSW4C.js +1385 -0
  7. package/dist/chunk-6YPV2AB5.js +1246 -0
  8. package/dist/chunk-BPVAB4P2.js +1126 -0
  9. package/dist/chunk-FL53T24A.js +257 -0
  10. package/dist/chunk-L6KCTHUW.js +1086 -0
  11. package/dist/chunk-MLKGABMK.js +7 -0
  12. package/dist/chunk-ROTPLW7T.js +265 -0
  13. package/dist/chunk-TSAGO3XP.js +1253 -0
  14. package/dist/chunk-UC656APA.js +1080 -0
  15. package/dist/chunk-W4UBLYFU.js +1219 -0
  16. package/dist/chunk-XST6X3HT.js +896 -0
  17. package/dist/chunk-XXYZLLHI.js +2227 -0
  18. package/dist/chunk-ZKL2VX2G.js +2215 -0
  19. package/dist/chunk-ZPQZEIXP.js +685 -0
  20. package/dist/code-QNrdLIR3.d.cts +327 -0
  21. package/dist/code-QNrdLIR3.d.ts +327 -0
  22. package/dist/color-tPwZCr9H.d.cts +229 -0
  23. package/dist/color-tPwZCr9H.d.ts +229 -0
  24. package/dist/css-Cf7AMGM-.d.cts +318 -0
  25. package/dist/css-Cf7AMGM-.d.ts +318 -0
  26. package/dist/data-rMjWNiOJ.d.cts +215 -0
  27. package/dist/data-rMjWNiOJ.d.ts +215 -0
  28. package/dist/encoding-7gmq-vkV.d.cts +108 -0
  29. package/dist/encoding-7gmq-vkV.d.ts +108 -0
  30. package/dist/generators-BGtRGpJZ.d.cts +118 -0
  31. package/dist/generators-BGtRGpJZ.d.ts +118 -0
  32. package/dist/hashing-CnetQFD_.d.cts +76 -0
  33. package/dist/hashing-CnetQFD_.d.ts +76 -0
  34. package/dist/index.cjs +15466 -0
  35. package/dist/index.d.cts +18 -0
  36. package/dist/index.d.ts +18 -0
  37. package/dist/index.js +20 -0
  38. package/dist/json-BjSoIS1h.d.cts +198 -0
  39. package/dist/json-BjSoIS1h.d.ts +198 -0
  40. package/dist/misc-DcVBManm.d.cts +201 -0
  41. package/dist/misc-DcVBManm.d.ts +201 -0
  42. package/dist/network-CNtmrDeN.d.cts +170 -0
  43. package/dist/network-CNtmrDeN.d.ts +170 -0
  44. package/dist/text-DqAjPtQ0.d.cts +319 -0
  45. package/dist/text-DqAjPtQ0.d.ts +319 -0
  46. package/dist/time-DbT8fjaF.d.cts +145 -0
  47. package/dist/time-DbT8fjaF.d.ts +145 -0
  48. package/dist/tools/api.cjs +1216 -0
  49. package/dist/tools/api.d.cts +1 -0
  50. package/dist/tools/api.d.ts +1 -0
  51. package/dist/tools/api.js +2 -0
  52. package/dist/tools/code.cjs +2212 -0
  53. package/dist/tools/code.d.cts +1 -0
  54. package/dist/tools/code.d.ts +1 -0
  55. package/dist/tools/code.js +2 -0
  56. package/dist/tools/color.cjs +1122 -0
  57. package/dist/tools/color.d.cts +1 -0
  58. package/dist/tools/color.d.ts +1 -0
  59. package/dist/tools/color.js +2 -0
  60. package/dist/tools/css.cjs +1242 -0
  61. package/dist/tools/css.d.cts +1 -0
  62. package/dist/tools/css.d.ts +1 -0
  63. package/dist/tools/css.js +2 -0
  64. package/dist/tools/data.cjs +1097 -0
  65. package/dist/tools/data.d.cts +1 -0
  66. package/dist/tools/data.d.ts +1 -0
  67. package/dist/tools/data.js +2 -0
  68. package/dist/tools/encoding.cjs +261 -0
  69. package/dist/tools/encoding.d.cts +1 -0
  70. package/dist/tools/encoding.d.ts +1 -0
  71. package/dist/tools/encoding.js +2 -0
  72. package/dist/tools/generators.cjs +521 -0
  73. package/dist/tools/generators.d.cts +1 -0
  74. package/dist/tools/generators.d.ts +1 -0
  75. package/dist/tools/generators.js +2 -0
  76. package/dist/tools/hashing.cjs +259 -0
  77. package/dist/tools/hashing.d.cts +1 -0
  78. package/dist/tools/hashing.d.ts +1 -0
  79. package/dist/tools/hashing.js +2 -0
  80. package/dist/tools/json.cjs +1270 -0
  81. package/dist/tools/json.d.cts +1 -0
  82. package/dist/tools/json.d.ts +1 -0
  83. package/dist/tools/json.js +2 -0
  84. package/dist/tools/misc.cjs +1082 -0
  85. package/dist/tools/misc.d.cts +1 -0
  86. package/dist/tools/misc.d.ts +1 -0
  87. package/dist/tools/misc.js +2 -0
  88. package/dist/tools/network.cjs +1381 -0
  89. package/dist/tools/network.d.cts +1 -0
  90. package/dist/tools/network.d.ts +1 -0
  91. package/dist/tools/network.js +2 -0
  92. package/dist/tools/text.cjs +2224 -0
  93. package/dist/tools/text.d.cts +1 -0
  94. package/dist/tools/text.d.ts +1 -0
  95. package/dist/tools/text.js +2 -0
  96. package/dist/tools/time.cjs +681 -0
  97. package/dist/tools/time.d.cts +1 -0
  98. package/dist/tools/time.d.ts +1 -0
  99. package/dist/tools/time.js +2 -0
  100. package/dist/tools/units.cjs +892 -0
  101. package/dist/tools/units.d.cts +1 -0
  102. package/dist/tools/units.d.ts +1 -0
  103. package/dist/tools/units.js +2 -0
  104. package/dist/units-6lwDYBvX.d.cts +302 -0
  105. package/dist/units-6lwDYBvX.d.ts +302 -0
  106. package/package.json +148 -0
@@ -0,0 +1,896 @@
1
+ import { __export } from './chunk-MLKGABMK.js';
2
+
3
+ // src/tools/units.ts
4
+ var units_exports = {};
5
+ __export(units_exports, {
6
+ BASE_LABELS: () => BASE_LABELS,
7
+ BASE_PREFIXES: () => BASE_PREFIXES,
8
+ BYTE_UNITS: () => BYTE_UNITS,
9
+ COMMON_CURRENCIES: () => COMMON_CURRENCIES,
10
+ COMMON_LOCALES: () => COMMON_LOCALES,
11
+ COMMON_PERMISSIONS: () => COMMON_PERMISSIONS,
12
+ COMMON_RATIOS: () => COMMON_RATIOS,
13
+ COMMON_SIZES: () => COMMON_SIZES,
14
+ COMMON_VIEWPORTS: () => COMMON_VIEWPORTS,
15
+ autoFormat: () => autoFormat,
16
+ bumpVersion: () => bumpVersion,
17
+ calcAspectRatio: () => calcAspectRatio,
18
+ calcSubnet: () => calcSubnet,
19
+ compareSemver: () => compareSemver,
20
+ convert: () => convert,
21
+ convertBytes: () => convertBytes,
22
+ convertIp: () => convertIp,
23
+ coverBox: () => coverBox,
24
+ decimalToIp: () => decimalToIp,
25
+ decimalToIpCidr: () => decimalToIpCidr,
26
+ describePermissions: () => describePermissions,
27
+ fitIntoBox: () => fitIntoBox,
28
+ formatNumber: () => formatNumber,
29
+ formatValue: () => formatValue,
30
+ formatVwValue: () => formatVwValue,
31
+ formatWithSeparator: () => formatWithSeparator,
32
+ gcd: () => gcd,
33
+ ipFromBinary: () => ipFromBinary,
34
+ ipFromDecimal: () => ipFromDecimal,
35
+ ipFromHex: () => ipFromHex,
36
+ ipToBinary: () => ipToBinary,
37
+ ipToDecimal: () => ipToDecimal,
38
+ ipToDecimalCidr: () => ipToDecimalCidr,
39
+ ipToHex: () => ipToHex,
40
+ ipToOctal: () => ipToOctal,
41
+ isValid: () => isValid,
42
+ isValidCidr: () => isValidCidr,
43
+ isValidIp: () => isValidIp,
44
+ isValidIpv4: () => isValidIpv4,
45
+ octalToPermissions: () => octalToPermissions,
46
+ parseFileSize: () => parseFileSize,
47
+ parseInput: () => parseInput,
48
+ parseNumberString: () => parseNumberString,
49
+ parseSemver: () => parseSemver,
50
+ permissionsToChmod: () => permissionsToChmod,
51
+ permissionsToOctal: () => permissionsToOctal,
52
+ permissionsToSymbolic: () => permissionsToSymbolic,
53
+ ptToPx: () => ptToPx,
54
+ pxToAll: () => pxToAll,
55
+ pxToViewport: () => pxToViewport,
56
+ remToPx: () => remToPx,
57
+ satisfiesRange: () => satisfiesRange,
58
+ scaleByHeight: () => scaleByHeight,
59
+ scaleByWidth: () => scaleByWidth,
60
+ sortVersions: () => sortVersions,
61
+ splitSubnet: () => splitSubnet,
62
+ symbolicToPermissions: () => symbolicToPermissions,
63
+ viewportToPx: () => viewportToPx
64
+ });
65
+ function pxToAll(px, baseFontSize = 16, viewportWidth = 1440, viewportHeight = 900) {
66
+ return {
67
+ px,
68
+ rem: px / baseFontSize,
69
+ em: px / baseFontSize,
70
+ pt: px * 0.75,
71
+ vw: px / viewportWidth * 100,
72
+ vh: px / viewportHeight * 100
73
+ };
74
+ }
75
+ function remToPx(rem, baseFontSize = 16) {
76
+ return rem * baseFontSize;
77
+ }
78
+ function ptToPx(pt) {
79
+ return pt / 0.75;
80
+ }
81
+ function formatValue(value, unit, decimals = 4) {
82
+ return `${value.toFixed(decimals)}${unit}`;
83
+ }
84
+ var COMMON_SIZES = [
85
+ { px: 8, label: "8px \u2014 Extra small spacing / icon size" },
86
+ { px: 12, label: "12px \u2014 Small text / caption" },
87
+ { px: 14, label: "14px \u2014 Body small / secondary text" },
88
+ { px: 16, label: "16px \u2014 Base font size / body text" },
89
+ { px: 18, label: "18px \u2014 Body large / lead text" },
90
+ { px: 20, label: "20px \u2014 Subheading / large body" },
91
+ { px: 24, label: "24px \u2014 H4 / section title" },
92
+ { px: 32, label: "32px \u2014 H3 / card heading" },
93
+ { px: 48, label: "48px \u2014 H2 / page section heading" },
94
+ { px: 64, label: "64px \u2014 H1 / hero heading" }
95
+ ];
96
+ function pxToViewport(px, viewportWidth = 1440, viewportHeight = 900) {
97
+ const vw = parseFloat((px / viewportWidth * 100).toFixed(4));
98
+ const vh = parseFloat((px / viewportHeight * 100).toFixed(4));
99
+ const vmin = parseFloat((px / Math.min(viewportWidth, viewportHeight) * 100).toFixed(4));
100
+ const vmax = parseFloat((px / Math.max(viewportWidth, viewportHeight) * 100).toFixed(4));
101
+ const percent = vw;
102
+ return { px, vw, vh, vmin, vmax, percent };
103
+ }
104
+ function viewportToPx(vw, viewportWidth = 1440) {
105
+ return parseFloat((vw / 100 * viewportWidth).toFixed(2));
106
+ }
107
+ var COMMON_VIEWPORTS = [
108
+ { label: "Mobile", width: 375, height: 812 },
109
+ { label: "Tablet", width: 768, height: 1024 },
110
+ { label: "Laptop", width: 1280, height: 800 },
111
+ { label: "Desktop", width: 1440, height: 900 },
112
+ { label: "Wide", width: 1920, height: 1080 },
113
+ { label: "4K", width: 3840, height: 2160 },
114
+ { label: "iPad Pro", width: 1024, height: 1366 },
115
+ { label: "Surface Pro", width: 912, height: 1368 }
116
+ ];
117
+ function formatVwValue(value, decimals = 2) {
118
+ return `${value.toFixed(decimals)}vw`;
119
+ }
120
+ var BYTE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB", "KiB", "MiB", "GiB", "TiB"];
121
+ var TO_BYTES = {
122
+ B: 1,
123
+ KB: 1e3,
124
+ MB: 1e3 ** 2,
125
+ GB: 1e3 ** 3,
126
+ TB: 1e3 ** 4,
127
+ PB: 1e3 ** 5,
128
+ KiB: 1024,
129
+ MiB: 1024 ** 2,
130
+ GiB: 1024 ** 3,
131
+ TiB: 1024 ** 4
132
+ };
133
+ function convertBytes(value, fromUnit) {
134
+ const bytes = value * TO_BYTES[fromUnit];
135
+ return BYTE_UNITS.reduce((acc, unit) => {
136
+ const converted = bytes / TO_BYTES[unit];
137
+ acc[unit] = {
138
+ value: converted,
139
+ unit,
140
+ formatted: `${converted.toFixed(2)} ${unit}`
141
+ };
142
+ return acc;
143
+ }, {});
144
+ }
145
+ var SI_UNITS = ["PB", "TB", "GB", "MB", "KB", "B"];
146
+ function autoFormat(bytes) {
147
+ for (const unit of SI_UNITS) {
148
+ if (bytes >= TO_BYTES[unit]) {
149
+ const value = bytes / TO_BYTES[unit];
150
+ return `${value.toFixed(2)} ${unit}`;
151
+ }
152
+ }
153
+ return `${bytes.toFixed(2)} B`;
154
+ }
155
+ var UNIT_ALIASES = {
156
+ b: "B",
157
+ kb: "KB",
158
+ mb: "MB",
159
+ gb: "GB",
160
+ tb: "TB",
161
+ pb: "PB",
162
+ kib: "KiB",
163
+ mib: "MiB",
164
+ gib: "GiB",
165
+ tib: "TiB"
166
+ };
167
+ function parseFileSize(input) {
168
+ if (!input || input.trim() === "") return null;
169
+ const match = input.trim().match(/^([0-9]*\.?[0-9]+)\s*([a-zA-Z]+)$/);
170
+ if (!match) return null;
171
+ const numericValue = parseFloat(match[1]);
172
+ if (isNaN(numericValue)) return null;
173
+ const unitStr = match[2].toLowerCase();
174
+ const unit = UNIT_ALIASES[unitStr];
175
+ if (!unit) return null;
176
+ return numericValue * TO_BYTES[unit];
177
+ }
178
+ var BASE_PREFIXES = {
179
+ 2: "0b",
180
+ 8: "0o",
181
+ 10: "",
182
+ 16: "0x"
183
+ };
184
+ var BASE_LABELS = {
185
+ 2: "Binary",
186
+ 8: "Octal",
187
+ 10: "Decimal",
188
+ 16: "Hex"
189
+ };
190
+ function parseInput(input, fromBase) {
191
+ const trimmed = input.trim();
192
+ if (!trimmed) return { value: 0n, error: "Empty input" };
193
+ const clean = trimmed.replace(/^0b/i, "").replace(/^0o/i, "").replace(/^0x/i, "").replace(/[\s_]/g, "");
194
+ if (!clean) return { value: 0n, error: "Empty input" };
195
+ const validChars = {
196
+ 2: /^[01]+$/,
197
+ 8: /^[0-7]+$/,
198
+ 10: /^-?\d+$/,
199
+ 16: /^[0-9a-fA-F]+$/
200
+ };
201
+ if (!validChars[fromBase].test(clean)) {
202
+ return { value: 0n, error: `Invalid character for base ${fromBase}` };
203
+ }
204
+ try {
205
+ const value = BigInt(
206
+ fromBase === 10 ? clean : `0${fromBase === 2 ? "b" : fromBase === 8 ? "o" : "x"}${clean}`
207
+ );
208
+ return { value };
209
+ } catch {
210
+ return { value: 0n, error: "Parse error" };
211
+ }
212
+ }
213
+ function convert(input, fromBase) {
214
+ const { value, error } = parseInput(input, fromBase);
215
+ if (error && error !== "Empty input") {
216
+ return { binary: "", octal: "", decimal: "", hex: "", error };
217
+ }
218
+ if (error === "Empty input") {
219
+ return { binary: "", octal: "", decimal: "", hex: "" };
220
+ }
221
+ return {
222
+ binary: value.toString(2),
223
+ octal: value.toString(8),
224
+ decimal: value.toString(10),
225
+ hex: value.toString(16).toUpperCase()
226
+ };
227
+ }
228
+ function formatWithSeparator(value, groupSize = 4) {
229
+ if (value.length <= groupSize) return value;
230
+ const chunks = [];
231
+ let i = value.length;
232
+ while (i > 0) {
233
+ chunks.unshift(value.slice(Math.max(0, i - groupSize), i));
234
+ i -= groupSize;
235
+ }
236
+ return chunks.join(" ");
237
+ }
238
+ var COMMON_LOCALES = [
239
+ { locale: "en-US", label: "English (US)", example: "1,234.56" },
240
+ { locale: "en-GB", label: "English (UK)", example: "1,234.56" },
241
+ { locale: "de-DE", label: "German (Germany)", example: "1.234,56" },
242
+ { locale: "fr-FR", label: "French (France)", example: "1 234,56" },
243
+ { locale: "ja-JP", label: "Japanese (Japan)", example: "1,234.56" },
244
+ { locale: "zh-CN", label: "Chinese (Simplified)", example: "1,234.56" },
245
+ { locale: "zh-TW", label: "Chinese (Traditional)", example: "1,234.56" },
246
+ { locale: "ko-KR", label: "Korean (Korea)", example: "1,234.56" },
247
+ { locale: "es-ES", label: "Spanish (Spain)", example: "1.234,56" },
248
+ { locale: "es-MX", label: "Spanish (Mexico)", example: "1,234.56" },
249
+ { locale: "pt-BR", label: "Portuguese (Brazil)", example: "1.234,56" },
250
+ { locale: "pt-PT", label: "Portuguese (Portugal)", example: "1 234,56" },
251
+ { locale: "ru-RU", label: "Russian (Russia)", example: "1 234,56" },
252
+ { locale: "ar-SA", label: "Arabic (Saudi Arabia)", example: "\u0661\u066C\u0662\u0663\u0664\u066B\u0665\u0666" },
253
+ { locale: "hi-IN", label: "Hindi (India)", example: "1,234.56" },
254
+ { locale: "it-IT", label: "Italian (Italy)", example: "1.234,56" },
255
+ { locale: "nl-NL", label: "Dutch (Netherlands)", example: "1.234,56" },
256
+ { locale: "sv-SE", label: "Swedish (Sweden)", example: "1 234,56" },
257
+ { locale: "tr-TR", label: "Turkish (Turkey)", example: "1.234,56" },
258
+ { locale: "pl-PL", label: "Polish (Poland)", example: "1 234,56" }
259
+ ];
260
+ var COMMON_CURRENCIES = [
261
+ { code: "USD", name: "US Dollar", symbol: "$" },
262
+ { code: "EUR", name: "Euro", symbol: "\u20AC" },
263
+ { code: "GBP", name: "British Pound", symbol: "\xA3" },
264
+ { code: "JPY", name: "Japanese Yen", symbol: "\xA5" },
265
+ { code: "CNY", name: "Chinese Yuan", symbol: "\xA5" },
266
+ { code: "KRW", name: "South Korean Won", symbol: "\u20A9" },
267
+ { code: "INR", name: "Indian Rupee", symbol: "\u20B9" },
268
+ { code: "CAD", name: "Canadian Dollar", symbol: "CA$" },
269
+ { code: "AUD", name: "Australian Dollar", symbol: "A$" },
270
+ { code: "CHF", name: "Swiss Franc", symbol: "CHF" },
271
+ { code: "BRL", name: "Brazilian Real", symbol: "R$" },
272
+ { code: "MXN", name: "Mexican Peso", symbol: "MX$" },
273
+ { code: "SEK", name: "Swedish Krona", symbol: "kr" },
274
+ { code: "NOK", name: "Norwegian Krone", symbol: "kr" },
275
+ { code: "DKK", name: "Danish Krone", symbol: "kr" },
276
+ { code: "RUB", name: "Russian Ruble", symbol: "\u20BD" },
277
+ { code: "TRY", name: "Turkish Lira", symbol: "\u20BA" },
278
+ { code: "SAR", name: "Saudi Riyal", symbol: "\uFDFC" },
279
+ { code: "AED", name: "UAE Dirham", symbol: "\u062F.\u0625" },
280
+ { code: "SGD", name: "Singapore Dollar", symbol: "S$" }
281
+ ];
282
+ function formatNumber(value, options) {
283
+ if (!isFinite(value)) {
284
+ return { error: "Value must be a finite number" };
285
+ }
286
+ try {
287
+ const intlOptions = {};
288
+ if (options.style === "decimal") {
289
+ intlOptions.style = "decimal";
290
+ } else if (options.style === "currency") {
291
+ if (!options.currency) {
292
+ return { error: "Currency code is required for currency style" };
293
+ }
294
+ intlOptions.style = "currency";
295
+ intlOptions.currency = options.currency;
296
+ } else if (options.style === "percent") {
297
+ intlOptions.style = "percent";
298
+ } else if (options.style === "scientific") {
299
+ intlOptions.notation = "scientific";
300
+ } else if (options.style === "engineering") {
301
+ intlOptions.notation = "engineering";
302
+ } else if (options.style === "compact") {
303
+ intlOptions.notation = "compact";
304
+ }
305
+ if (options.minimumFractionDigits !== void 0) {
306
+ intlOptions.minimumFractionDigits = options.minimumFractionDigits;
307
+ }
308
+ if (options.maximumFractionDigits !== void 0) {
309
+ intlOptions.maximumFractionDigits = options.maximumFractionDigits;
310
+ }
311
+ if (options.useGrouping !== void 0) {
312
+ intlOptions.useGrouping = options.useGrouping;
313
+ }
314
+ return new Intl.NumberFormat(options.locale, intlOptions).format(value);
315
+ } catch (e) {
316
+ return { error: e instanceof Error ? e.message : "Formatting failed" };
317
+ }
318
+ }
319
+ function parseNumberString(input) {
320
+ if (!input || typeof input !== "string") {
321
+ return { error: "Input must be a non-empty string" };
322
+ }
323
+ const trimmed = input.trim();
324
+ if (trimmed === "") {
325
+ return { error: "Input must be a non-empty string" };
326
+ }
327
+ const cleaned = trimmed.replace(/[,،٬]/g, "").replace(/\s/g, "").replace(/[٫]/g, ".");
328
+ const result = parseFloat(cleaned);
329
+ if (isNaN(result)) {
330
+ return { error: `Cannot parse "${input}" as a number` };
331
+ }
332
+ return result;
333
+ }
334
+ var COMMON_RATIOS = [
335
+ { ratio: "16:9", decimal: 16 / 9, description: "Widescreen HD, most monitors and TVs" },
336
+ { ratio: "4:3", decimal: 4 / 3, description: "Traditional TV, older monitors" },
337
+ { ratio: "1:1", decimal: 1, description: "Square, Instagram posts" },
338
+ { ratio: "21:9", decimal: 21 / 9, description: "Ultra-wide cinema" },
339
+ { ratio: "3:2", decimal: 3 / 2, description: "Photography (35mm film)" },
340
+ { ratio: "9:16", decimal: 9 / 16, description: "Portrait, mobile video" },
341
+ { ratio: "5:4", decimal: 5 / 4, description: "Old monitors, medium format" },
342
+ { ratio: "2:1", decimal: 2, description: "Univisium, dual-square" }
343
+ ];
344
+ function gcd(a, b) {
345
+ a = Math.abs(Math.round(a));
346
+ b = Math.abs(Math.round(b));
347
+ while (b !== 0) {
348
+ const t = b;
349
+ b = a % b;
350
+ a = t;
351
+ }
352
+ return a;
353
+ }
354
+ function calcAspectRatio(width, height) {
355
+ if (!Number.isFinite(width) || !Number.isFinite(height)) {
356
+ return { error: "Width and height must be finite numbers" };
357
+ }
358
+ if (width <= 0 || height <= 0) {
359
+ return { error: "Width and height must be positive numbers" };
360
+ }
361
+ const g = gcd(width, height);
362
+ const rw = width / g;
363
+ const rh = height / g;
364
+ const ratio = `${rw}:${rh}`;
365
+ const decimal = width / height;
366
+ const percentage = height / width * 100;
367
+ const tolerance = 0.01;
368
+ const isCommon = COMMON_RATIOS.some((r) => Math.abs(r.decimal - decimal) < tolerance);
369
+ return { ratio, decimal, percentage, gcd: g, isCommon };
370
+ }
371
+ function scaleByWidth(dimensions, newWidth) {
372
+ const scale = newWidth / dimensions.width;
373
+ return {
374
+ width: newWidth,
375
+ height: Math.round(dimensions.height * scale)
376
+ };
377
+ }
378
+ function scaleByHeight(dimensions, newHeight) {
379
+ const scale = newHeight / dimensions.height;
380
+ return {
381
+ width: Math.round(dimensions.width * scale),
382
+ height: newHeight
383
+ };
384
+ }
385
+ function fitIntoBox(dimensions, box) {
386
+ const widthScale = box.width / dimensions.width;
387
+ const heightScale = box.height / dimensions.height;
388
+ const scale = Math.min(widthScale, heightScale);
389
+ return {
390
+ width: Math.round(dimensions.width * scale),
391
+ height: Math.round(dimensions.height * scale)
392
+ };
393
+ }
394
+ function coverBox(dimensions, box) {
395
+ const widthScale = box.width / dimensions.width;
396
+ const heightScale = box.height / dimensions.height;
397
+ const scale = Math.max(widthScale, heightScale);
398
+ return {
399
+ width: Math.round(dimensions.width * scale),
400
+ height: Math.round(dimensions.height * scale)
401
+ };
402
+ }
403
+ function parsePermBits(bits) {
404
+ return {
405
+ read: (bits & 4) !== 0,
406
+ write: (bits & 2) !== 0,
407
+ execute: (bits & 1) !== 0
408
+ };
409
+ }
410
+ function permToNum(p) {
411
+ return (p.read ? 4 : 0) + (p.write ? 2 : 0) + (p.execute ? 1 : 0);
412
+ }
413
+ function octalToPermissions(octal) {
414
+ const clean = octal.replace(/^0+/, "") || "0";
415
+ if (!/^\d+$/.test(clean)) return { error: "Invalid octal: must contain only digits" };
416
+ let num;
417
+ if (clean.length <= 3) {
418
+ if (!/^[0-7]+$/.test(clean)) return { error: "Invalid octal: digits must be 0-7" };
419
+ num = parseInt(clean, 8);
420
+ return {
421
+ owner: parsePermBits(num >> 6 & 7),
422
+ group: parsePermBits(num >> 3 & 7),
423
+ others: parsePermBits(num & 7)
424
+ };
425
+ } else if (clean.length === 4) {
426
+ if (!/^[0-7]+$/.test(clean)) return { error: "Invalid octal: digits must be 0-7" };
427
+ num = parseInt(clean, 8);
428
+ const special = num >> 9 & 7;
429
+ return {
430
+ owner: parsePermBits(num >> 6 & 7),
431
+ group: parsePermBits(num >> 3 & 7),
432
+ others: parsePermBits(num & 7),
433
+ setuid: (special & 4) !== 0,
434
+ setgid: (special & 2) !== 0,
435
+ sticky: (special & 1) !== 0
436
+ };
437
+ } else {
438
+ return { error: "Invalid octal: too many digits" };
439
+ }
440
+ }
441
+ function permissionsToOctal(perms) {
442
+ const owner = permToNum(perms.owner);
443
+ const group = permToNum(perms.group);
444
+ const others = permToNum(perms.others);
445
+ const setuid = perms.setuid ? 4 : 0;
446
+ const setgid = perms.setgid ? 2 : 0;
447
+ const sticky = perms.sticky ? 1 : 0;
448
+ const special = setuid + setgid + sticky;
449
+ if (special > 0) {
450
+ return `${special}${owner}${group}${others}`;
451
+ }
452
+ return `${owner}${group}${others}`;
453
+ }
454
+ function parsePermSymbol(sym) {
455
+ if (sym.length !== 3) return null;
456
+ const read = sym[0] === "r";
457
+ const write = sym[1] === "w";
458
+ const execute = sym[2] === "x" || sym[2] === "s" || sym[2] === "t";
459
+ if (sym[0] !== "r" && sym[0] !== "-") return null;
460
+ if (sym[1] !== "w" && sym[1] !== "-") return null;
461
+ if (sym[2] !== "x" && sym[2] !== "-" && sym[2] !== "s" && sym[2] !== "t" && sym[2] !== "S" && sym[2] !== "T")
462
+ return null;
463
+ return { read, write, execute };
464
+ }
465
+ function symbolicToPermissions(symbolic) {
466
+ const s = symbolic.length === 10 ? symbolic.slice(1) : symbolic;
467
+ if (s.length !== 9) return { error: "Invalid symbolic: must be 9 characters (e.g. rwxr-xr-x)" };
468
+ const ownerSym = s.slice(0, 3);
469
+ const groupSym = s.slice(3, 6);
470
+ const otherSym = s.slice(6, 9);
471
+ const owner = parsePermSymbol(ownerSym);
472
+ const group = parsePermSymbol(groupSym);
473
+ const others = parsePermSymbol(otherSym);
474
+ if (!owner) return { error: "Invalid owner permissions" };
475
+ if (!group) return { error: "Invalid group permissions" };
476
+ if (!others) return { error: "Invalid others permissions" };
477
+ const setuid = s[2] === "s" || s[2] === "S";
478
+ const setgid = s[5] === "s" || s[5] === "S";
479
+ const sticky = s[8] === "t" || s[8] === "T";
480
+ return { owner, group, others, setuid, setgid, sticky };
481
+ }
482
+ function permToSym(p, special, specialChar) {
483
+ const r = p.read ? "r" : "-";
484
+ const w = p.write ? "w" : "-";
485
+ let x;
486
+ if (special) {
487
+ x = p.execute ? specialChar ?? "s" : specialChar?.toUpperCase() ?? "S";
488
+ } else {
489
+ x = p.execute ? "x" : "-";
490
+ }
491
+ return r + w + x;
492
+ }
493
+ function permissionsToSymbolic(perms) {
494
+ const owner = permToSym(perms.owner, perms.setuid, "s");
495
+ const group = permToSym(perms.group, perms.setgid, "s");
496
+ const others = permToSym(perms.others, perms.sticky, "t");
497
+ return owner + group + others;
498
+ }
499
+ function permissionsToChmod(perms) {
500
+ return `chmod ${permissionsToOctal(perms)} file`;
501
+ }
502
+ function describePermissions(perms) {
503
+ function describe(p) {
504
+ const parts = [];
505
+ if (p.read) parts.push("read");
506
+ if (p.write) parts.push("write");
507
+ if (p.execute) parts.push("execute");
508
+ return parts.length ? parts.join(", ") : "no permissions";
509
+ }
510
+ const lines = [
511
+ `Owner: ${describe(perms.owner)}`,
512
+ `Group: ${describe(perms.group)}`,
513
+ `Others: ${describe(perms.others)}`
514
+ ];
515
+ if (perms.setuid) lines.push("Setuid bit is set");
516
+ if (perms.setgid) lines.push("Setgid bit is set");
517
+ if (perms.sticky) lines.push("Sticky bit is set");
518
+ return lines;
519
+ }
520
+ var COMMON_PERMISSIONS = [
521
+ {
522
+ octal: "755",
523
+ symbolic: "rwxr-xr-x",
524
+ description: "Owner full, group/others read+execute",
525
+ use: "Executable files, web directories"
526
+ },
527
+ {
528
+ octal: "644",
529
+ symbolic: "rw-r--r--",
530
+ description: "Owner read+write, group/others read",
531
+ use: "Regular files, web content"
532
+ },
533
+ {
534
+ octal: "600",
535
+ symbolic: "rw-------",
536
+ description: "Owner read+write only",
537
+ use: "Private keys, sensitive config files"
538
+ },
539
+ {
540
+ octal: "777",
541
+ symbolic: "rwxrwxrwx",
542
+ description: "Everyone full permissions",
543
+ use: "Temporary shared directories (use with caution)"
544
+ },
545
+ {
546
+ octal: "700",
547
+ symbolic: "rwx------",
548
+ description: "Owner full, nobody else",
549
+ use: "Private executables, secure directories"
550
+ },
551
+ {
552
+ octal: "664",
553
+ symbolic: "rw-rw-r--",
554
+ description: "Owner+group read+write, others read",
555
+ use: "Shared project files"
556
+ },
557
+ {
558
+ octal: "666",
559
+ symbolic: "rw-rw-rw-",
560
+ description: "Everyone read+write, no execute",
561
+ use: "Shared data files"
562
+ },
563
+ {
564
+ octal: "400",
565
+ symbolic: "r--------",
566
+ description: "Owner read only",
567
+ use: "Read-only files, SSH authorized_keys"
568
+ }
569
+ ];
570
+ function isValidIpv4(ip) {
571
+ const parts = ip.split(".");
572
+ if (parts.length !== 4) return false;
573
+ return parts.every((part) => {
574
+ if (!/^\d+$/.test(part)) return false;
575
+ const n = parseInt(part, 10);
576
+ return n >= 0 && n <= 255;
577
+ });
578
+ }
579
+ function ipToDecimal(ip) {
580
+ if (!isValidIpv4(ip)) throw new Error(`Invalid IPv4 address: ${ip}`);
581
+ const parts = ip.split(".").map(Number);
582
+ return (parts[0] << 24 >>> 0) + (parts[1] << 16 >>> 0) + (parts[2] << 8 >>> 0) + parts[3];
583
+ }
584
+ function decimalToIp(decimal) {
585
+ const d = decimal >>> 0;
586
+ return [
587
+ d >>> 24 & 255,
588
+ d >>> 16 & 255,
589
+ d >>> 8 & 255,
590
+ d & 255
591
+ ].join(".");
592
+ }
593
+ function ipToHex(ip) {
594
+ if (!isValidIpv4(ip)) throw new Error(`Invalid IPv4 address: ${ip}`);
595
+ const parts = ip.split(".").map(Number);
596
+ return "0x" + parts.map((p) => p.toString(16).toUpperCase().padStart(2, "0")).join("");
597
+ }
598
+ function ipToBinary(ip) {
599
+ if (!isValidIpv4(ip)) throw new Error(`Invalid IPv4 address: ${ip}`);
600
+ return ip.split(".").map((part) => parseInt(part, 10).toString(2).padStart(8, "0")).join(".");
601
+ }
602
+ function ipToOctal(ip) {
603
+ if (!isValidIpv4(ip)) throw new Error(`Invalid IPv4 address: ${ip}`);
604
+ return ip.split(".").map((part) => "0" + parseInt(part, 10).toString(8)).join(".");
605
+ }
606
+ function convertIp(ip) {
607
+ let cidrPrefix;
608
+ let rawIp = ip.trim();
609
+ const cidrMatch = rawIp.match(/^(.+?)(\/.+)$/);
610
+ if (cidrMatch) {
611
+ rawIp = cidrMatch[1];
612
+ cidrPrefix = cidrMatch[2];
613
+ }
614
+ if (!isValidIpv4(rawIp)) {
615
+ return { error: `Invalid IPv4 address: ${rawIp}` };
616
+ }
617
+ const decimal = ipToDecimal(rawIp);
618
+ const result = {
619
+ dotted: rawIp,
620
+ decimal,
621
+ hex: ipToHex(rawIp),
622
+ binary: ipToBinary(rawIp),
623
+ octal: ipToOctal(rawIp),
624
+ integer: decimal
625
+ };
626
+ if (cidrPrefix !== void 0) {
627
+ result.cidrPrefix = cidrPrefix;
628
+ }
629
+ return result;
630
+ }
631
+ function ipFromHex(hex) {
632
+ const cleaned = hex.trim().replace(/^0x/i, "");
633
+ if (!/^[0-9a-fA-F]{8}$/.test(cleaned)) {
634
+ return { error: `Invalid hex IP: ${hex}` };
635
+ }
636
+ const decimal = parseInt(cleaned, 16);
637
+ return decimalToIp(decimal);
638
+ }
639
+ function ipFromBinary(binary) {
640
+ const parts = binary.trim().split(".");
641
+ if (parts.length !== 4) {
642
+ return { error: `Invalid binary IP (expected 4 octets): ${binary}` };
643
+ }
644
+ if (!parts.every((p) => /^[01]{8}$/.test(p))) {
645
+ return { error: `Invalid binary IP (each octet must be 8 bits): ${binary}` };
646
+ }
647
+ const dotted = parts.map((p) => parseInt(p, 2).toString()).join(".");
648
+ return dotted;
649
+ }
650
+ function ipFromDecimal(decimal) {
651
+ return decimalToIp(decimal);
652
+ }
653
+ function isValidIp(ip) {
654
+ const parts = ip.split(".");
655
+ if (parts.length !== 4) return false;
656
+ return parts.every((p) => {
657
+ if (!/^\d+$/.test(p)) return false;
658
+ const n = parseInt(p, 10);
659
+ return n >= 0 && n <= 255;
660
+ });
661
+ }
662
+ function isValidCidr(cidr) {
663
+ const parts = cidr.split("/");
664
+ if (parts.length !== 2) return false;
665
+ if (!isValidIp(parts[0])) return false;
666
+ const prefix = parseInt(parts[1], 10);
667
+ return /^\d+$/.test(parts[1]) && prefix >= 0 && prefix <= 32;
668
+ }
669
+ function ipToDecimalCidr(ip) {
670
+ if (!isValidIp(ip)) return { error: `Invalid IP address: '${ip}'` };
671
+ const parts = ip.split(".").map(Number);
672
+ return (parts[0] << 24 | parts[1] << 16 | parts[2] << 8 | parts[3]) >>> 0;
673
+ }
674
+ function decimalToIpCidr(decimal) {
675
+ const d = decimal >>> 0;
676
+ return [
677
+ d >>> 24 & 255,
678
+ d >>> 16 & 255,
679
+ d >>> 8 & 255,
680
+ d & 255
681
+ ].join(".");
682
+ }
683
+ function getIpClass(firstOctet) {
684
+ if (firstOctet >= 1 && firstOctet <= 126) return "A";
685
+ if (firstOctet >= 128 && firstOctet <= 191) return "B";
686
+ if (firstOctet >= 192 && firstOctet <= 223) return "C";
687
+ if (firstOctet >= 224 && firstOctet <= 239) return "D";
688
+ if (firstOctet >= 240 && firstOctet <= 255) return "E";
689
+ return "unknown";
690
+ }
691
+ function checkPrivate(ipDec) {
692
+ const a = ipDec >>> 24 & 255;
693
+ const b = ipDec >>> 16 & 255;
694
+ if (a === 10) return true;
695
+ if (a === 172 && b >= 16 && b <= 31) return true;
696
+ if (a === 192 && b === 168) return true;
697
+ if (a === 127) return true;
698
+ return false;
699
+ }
700
+ function calcSubnet(cidr) {
701
+ if (!isValidCidr(cidr)) return { error: `Invalid CIDR: '${cidr}'` };
702
+ const [ipStr, prefixStr] = cidr.split("/");
703
+ const prefix = parseInt(prefixStr, 10);
704
+ const ipDecResult = ipToDecimalCidr(ipStr);
705
+ if (typeof ipDecResult === "object") return ipDecResult;
706
+ const maskDec = prefix === 0 ? 0 : 4294967295 << 32 - prefix >>> 0;
707
+ const wildcardDec = ~maskDec >>> 0;
708
+ const networkDec = (ipDecResult & maskDec) >>> 0;
709
+ const broadcastDec = (networkDec | wildcardDec) >>> 0;
710
+ const totalHosts = prefix >= 31 ? Math.pow(2, 32 - prefix) : Math.pow(2, 32 - prefix) - 2;
711
+ const usableHosts = prefix >= 31 ? totalHosts : Math.max(0, totalHosts);
712
+ let firstHostDec;
713
+ let lastHostDec;
714
+ if (prefix >= 31) {
715
+ firstHostDec = networkDec;
716
+ lastHostDec = broadcastDec;
717
+ } else {
718
+ firstHostDec = networkDec + 1 >>> 0;
719
+ lastHostDec = broadcastDec - 1 >>> 0;
720
+ }
721
+ const firstOctet = networkDec >>> 24 & 255;
722
+ return {
723
+ networkAddress: decimalToIpCidr(networkDec),
724
+ broadcastAddress: decimalToIpCidr(broadcastDec),
725
+ subnetMask: decimalToIpCidr(maskDec),
726
+ wildcardMask: decimalToIpCidr(wildcardDec),
727
+ firstHost: decimalToIpCidr(firstHostDec),
728
+ lastHost: decimalToIpCidr(lastHostDec),
729
+ totalHosts,
730
+ usableHosts,
731
+ prefix,
732
+ ipClass: getIpClass(firstOctet),
733
+ isPrivate: checkPrivate(networkDec)
734
+ };
735
+ }
736
+ function splitSubnet(cidr, newPrefix) {
737
+ if (!isValidCidr(cidr)) return { error: `Invalid CIDR: '${cidr}'` };
738
+ const [, prefixStr] = cidr.split("/");
739
+ const prefix = parseInt(prefixStr, 10);
740
+ if (newPrefix <= prefix)
741
+ return { error: `New prefix ${newPrefix} must be greater than original prefix ${prefix}` };
742
+ if (newPrefix > 32) return { error: `New prefix must be <= 32` };
743
+ const base = calcSubnet(cidr);
744
+ if ("error" in base) return base;
745
+ const networkDecResult = ipToDecimalCidr(base.networkAddress);
746
+ if (typeof networkDecResult === "object") return networkDecResult;
747
+ const count = Math.pow(2, newPrefix - prefix);
748
+ const subnetSize = Math.pow(2, 32 - newPrefix);
749
+ const results = [];
750
+ for (let i = 0; i < count; i++) {
751
+ const subnetIpDec = networkDecResult + i * subnetSize >>> 0;
752
+ const subnetCidr = `${decimalToIpCidr(subnetIpDec)}/${newPrefix}`;
753
+ const info = calcSubnet(subnetCidr);
754
+ if ("error" in info) return info;
755
+ results.push(info);
756
+ }
757
+ return results;
758
+ }
759
+ var SEMVER_RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9._-]+?))?(?:\+([a-zA-Z0-9._-]+))?$/;
760
+ function parseSemver(version) {
761
+ const m = version.trim().match(SEMVER_RE);
762
+ if (!m) return { error: `Invalid semver: '${version}'` };
763
+ const result = {
764
+ major: parseInt(m[1], 10),
765
+ minor: parseInt(m[2], 10),
766
+ patch: parseInt(m[3], 10),
767
+ raw: version.trim()
768
+ };
769
+ if (m[4] !== void 0) result.prerelease = m[4];
770
+ if (m[5] !== void 0) result.build = m[5];
771
+ return result;
772
+ }
773
+ function isValid(version) {
774
+ return SEMVER_RE.test(version.trim());
775
+ }
776
+ function comparePrerelease(a, b) {
777
+ if (a === void 0 && b === void 0) return 0;
778
+ if (a === void 0) return 1;
779
+ if (b === void 0) return -1;
780
+ const aParts = a.split(".");
781
+ const bParts = b.split(".");
782
+ const len = Math.max(aParts.length, bParts.length);
783
+ for (let i = 0; i < len; i++) {
784
+ const ap = aParts[i];
785
+ const bp = bParts[i];
786
+ if (ap === void 0) return -1;
787
+ if (bp === void 0) return 1;
788
+ const aNum = parseInt(ap, 10);
789
+ const bNum = parseInt(bp, 10);
790
+ const aIsNum = !isNaN(aNum) && String(aNum) === ap;
791
+ const bIsNum = !isNaN(bNum) && String(bNum) === bp;
792
+ if (aIsNum && bIsNum) {
793
+ if (aNum < bNum) return -1;
794
+ if (aNum > bNum) return 1;
795
+ } else if (aIsNum) {
796
+ return -1;
797
+ } else if (bIsNum) {
798
+ return 1;
799
+ } else {
800
+ if (ap < bp) return -1;
801
+ if (ap > bp) return 1;
802
+ }
803
+ }
804
+ return 0;
805
+ }
806
+ function compareVersionObjects(a, b) {
807
+ if (a.major !== b.major) return a.major < b.major ? -1 : 1;
808
+ if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;
809
+ if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;
810
+ return comparePrerelease(a.prerelease, b.prerelease);
811
+ }
812
+ function compareSemver(a, b) {
813
+ const pa = parseSemver(a);
814
+ if ("error" in pa) return pa;
815
+ const pb = parseSemver(b);
816
+ if ("error" in pb) return pb;
817
+ return compareVersionObjects(pa, pb);
818
+ }
819
+ function satisfiesRange(version, range) {
820
+ const pv = parseSemver(version);
821
+ if ("error" in pv) return pv;
822
+ const trimmedRange = range.trim();
823
+ if (trimmedRange === "*" || trimmedRange === "") return true;
824
+ const andParts = trimmedRange.split(/\s+/);
825
+ for (const part of andParts) {
826
+ const result = satisfiesSingleRange(pv, part.trim());
827
+ if (typeof result === "object" && "error" in result) return result;
828
+ if (!result) return false;
829
+ }
830
+ return true;
831
+ }
832
+ function satisfiesSingleRange(pv, range) {
833
+ if (range === "*") return true;
834
+ const caretMatch = range.match(/^\^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9._-]+))?$/);
835
+ if (caretMatch) {
836
+ const major = parseInt(caretMatch[1], 10);
837
+ const minor = parseInt(caretMatch[2], 10);
838
+ const patch = parseInt(caretMatch[3], 10);
839
+ const pre = caretMatch[4];
840
+ const lower = { major, minor, patch, prerelease: pre};
841
+ let upper;
842
+ if (major !== 0) {
843
+ upper = { major: major + 1, minor: 0, patch: 0, raw: "" };
844
+ } else if (minor !== 0) {
845
+ upper = { major: 0, minor: minor + 1, patch: 0, raw: "" };
846
+ } else {
847
+ upper = { major: 0, minor: 0, patch: patch + 1, raw: "" };
848
+ }
849
+ return compareVersionObjects(pv, lower) >= 0 && compareVersionObjects(pv, upper) < 0;
850
+ }
851
+ const tildeMatch = range.match(/^~v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9._-]+))?$/);
852
+ if (tildeMatch) {
853
+ const major = parseInt(tildeMatch[1], 10);
854
+ const minor = parseInt(tildeMatch[2], 10);
855
+ const patch = parseInt(tildeMatch[3], 10);
856
+ const pre = tildeMatch[4];
857
+ const lower = { major, minor, patch, prerelease: pre};
858
+ const upper = { major, minor: minor + 1, patch: 0};
859
+ return compareVersionObjects(pv, lower) >= 0 && compareVersionObjects(pv, upper) < 0;
860
+ }
861
+ const opMatch = range.match(/^(>=|<=|>|<|=)v?(.+)$/);
862
+ if (opMatch) {
863
+ const op = opMatch[1];
864
+ const parsed = parseSemver(opMatch[2]);
865
+ if ("error" in parsed) return parsed;
866
+ const cmp = compareVersionObjects(pv, parsed);
867
+ if (op === ">=") return cmp >= 0;
868
+ if (op === "<=") return cmp <= 0;
869
+ if (op === ">") return cmp > 0;
870
+ if (op === "<") return cmp < 0;
871
+ if (op === "=") return cmp === 0;
872
+ }
873
+ const plain = parseSemver(range);
874
+ if (!("error" in plain)) {
875
+ return compareVersionObjects(pv, plain) === 0;
876
+ }
877
+ return { error: `Unsupported range: '${range}'` };
878
+ }
879
+ function bumpVersion(version, bump) {
880
+ const pv = parseSemver(version);
881
+ if ("error" in pv) return pv;
882
+ if (bump === "major") return `${pv.major + 1}.0.0`;
883
+ if (bump === "minor") return `${pv.major}.${pv.minor + 1}.0`;
884
+ return `${pv.major}.${pv.minor}.${pv.patch + 1}`;
885
+ }
886
+ function sortVersions(versions, order = "asc") {
887
+ return [...versions].sort((a, b) => {
888
+ const pa = parseSemver(a);
889
+ const pb = parseSemver(b);
890
+ if ("error" in pa || "error" in pb) return 0;
891
+ const cmp = compareVersionObjects(pa, pb);
892
+ return order === "asc" ? cmp : -cmp;
893
+ });
894
+ }
895
+
896
+ export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_VIEWPORTS, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, compareSemver, convert, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, viewportToPx };