@ztimson/utils 0.29.0 → 0.29.2

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/index.cjs CHANGED
@@ -1237,9 +1237,46 @@ ${opts.message || this.desc}`;
1237
1237
  function formatDate(format = "YYYY-MM-DD H:mm", date = /* @__PURE__ */ new Date(), tz = "local") {
1238
1238
  if (typeof date === "number" || typeof date === "string") date = new Date(date);
1239
1239
  if (isNaN(date.getTime())) throw new Error("Invalid date input");
1240
- const numericTz = typeof tz === "number";
1241
- const localTz = tz === "local" || !numericTz && tz.toLowerCase?.() === "local";
1242
- const tzName = localTz ? Intl.DateTimeFormat().resolvedOptions().timeZone : numericTz ? "UTC" : tz;
1240
+ const TIMEZONE_MAP = [
1241
+ { name: "IDLW", iana: "Etc/GMT+12", offset: -720 },
1242
+ { name: "SST", iana: "Pacific/Pago_Pago", offset: -660 },
1243
+ { name: "HST", iana: "Pacific/Honolulu", offset: -600 },
1244
+ { name: "AKST", iana: "America/Anchorage", offset: -540 },
1245
+ { name: "PST", iana: "America/Los_Angeles", offset: -480 },
1246
+ { name: "MST", iana: "America/Denver", offset: -420 },
1247
+ { name: "CST", iana: "America/Chicago", offset: -360 },
1248
+ { name: "EST", iana: "America/New_York", offset: -300 },
1249
+ { name: "AST", iana: "America/Halifax", offset: -240 },
1250
+ { name: "BRT", iana: "America/Sao_Paulo", offset: -180 },
1251
+ { name: "MAT", iana: "Atlantic/South_Georgia", offset: -120 },
1252
+ { name: "AZOT", iana: "Atlantic/Azores", offset: -60 },
1253
+ { name: "UTC", iana: "UTC", offset: 0 },
1254
+ { name: "CET", iana: "Europe/Paris", offset: 60 },
1255
+ { name: "EET", iana: "Europe/Athens", offset: 120 },
1256
+ { name: "MSK", iana: "Europe/Moscow", offset: 180 },
1257
+ { name: "GST", iana: "Asia/Dubai", offset: 240 },
1258
+ { name: "PKT", iana: "Asia/Karachi", offset: 300 },
1259
+ { name: "IST", iana: "Asia/Kolkata", offset: 330 },
1260
+ { name: "BST", iana: "Asia/Dhaka", offset: 360 },
1261
+ { name: "ICT", iana: "Asia/Bangkok", offset: 420 },
1262
+ { name: "CST", iana: "Asia/Shanghai", offset: 480 },
1263
+ { name: "JST", iana: "Asia/Tokyo", offset: 540 },
1264
+ { name: "AEST", iana: "Australia/Sydney", offset: 600 },
1265
+ { name: "SBT", iana: "Pacific/Guadalcanal", offset: 660 },
1266
+ { name: "TOT", iana: "Pacific/Tongatapu", offset: 780 },
1267
+ { name: "LINT", iana: "Pacific/Kiritimati", offset: 840 }
1268
+ ];
1269
+ let numericTz = typeof tz === "number";
1270
+ const localTz = tz === "local" || !numericTz && tz.toString().toLowerCase?.() === "local";
1271
+ let tzName = localTz ? Intl.DateTimeFormat().resolvedOptions().timeZone : numericTz ? "UTC" : tz;
1272
+ let offsetMinutes = 0;
1273
+ if (numericTz) {
1274
+ offsetMinutes = Math.abs(tz) < 24 ? tz * 60 : tz;
1275
+ const closest = TIMEZONE_MAP.reduce(
1276
+ (prev, curr) => Math.abs(curr.offset - offsetMinutes) < Math.abs(prev.offset - offsetMinutes) ? curr : prev
1277
+ );
1278
+ tzName = closest.iana;
1279
+ }
1243
1280
  if (!numericTz && tzName !== "UTC") {
1244
1281
  try {
1245
1282
  new Intl.DateTimeFormat("en-US", { timeZone: tzName }).format();
@@ -1289,8 +1326,7 @@ ${opts.message || this.desc}`;
1289
1326
  }
1290
1327
  };
1291
1328
  } else {
1292
- const offset = numericTz ? tz : 0;
1293
- zonedDate = new Date(date.getTime() + offset * 60 * 60 * 1e3);
1329
+ zonedDate = new Date(date.getTime() + offsetMinutes * 60 * 1e3);
1294
1330
  get = (fn2) => zonedDate[`getUTC${fn2}`]();
1295
1331
  }
1296
1332
  function numSuffix2(n) {
@@ -1300,10 +1336,9 @@ ${opts.message || this.desc}`;
1300
1336
  }
1301
1337
  function getTZOffset() {
1302
1338
  if (numericTz) {
1303
- const total = tz * 60;
1304
- const hours = Math.floor(Math.abs(total) / 60);
1305
- const mins = Math.abs(total) % 60;
1306
- return `${tz >= 0 ? "+" : "-"}${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
1339
+ const hours = Math.floor(Math.abs(offsetMinutes) / 60);
1340
+ const mins = Math.abs(offsetMinutes) % 60;
1341
+ return `${offsetMinutes >= 0 ? "+" : "-"}${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
1307
1342
  }
1308
1343
  try {
1309
1344
  const offset = new Intl.DateTimeFormat("en-US", { timeZone: tzName, timeZoneName: "longOffset", hour: "2-digit", minute: "2-digit" }).formatToParts(date).find((p) => p.type === "timeZoneName")?.value.match(/([+-]\d{2}:\d{2})/)?.[1];
@@ -1313,7 +1348,6 @@ ${opts.message || this.desc}`;
1313
1348
  return "+00:00";
1314
1349
  }
1315
1350
  function getTZAbbr() {
1316
- if (numericTz && tz === 0) return "UTC";
1317
1351
  try {
1318
1352
  return new Intl.DateTimeFormat("en-US", { timeZone: tzName, timeZoneName: "short" }).formatToParts(date).find((p) => p.type === "timeZoneName")?.value || "";
1319
1353
  } catch {
@@ -3021,22 +3055,23 @@ ${err.message || err.toString()}`);
3021
3055
  if (xml[pos] !== "<") return parseText();
3022
3056
  pos++;
3023
3057
  if (xml[pos] === "?") {
3024
- parseDeclaration();
3025
- return parseNode();
3058
+ const declaration = parseDeclaration();
3059
+ return { ["?" + declaration]: "", ...parseNode() };
3026
3060
  }
3027
3061
  if (xml[pos] === "!") {
3028
3062
  parseComment();
3029
3063
  return parseNode();
3030
3064
  }
3031
3065
  const tagName = parseTagName();
3032
- const attributes = parseAttributes();
3066
+ parseAttributes();
3033
3067
  skipWhitespace();
3034
3068
  if (xml[pos] === "/" && xml[pos + 1] === ">") {
3035
3069
  pos += 2;
3036
- return { tag: tagName, attributes, children: [] };
3070
+ return { [tagName]: "" };
3037
3071
  }
3038
3072
  pos++;
3039
3073
  const children = [];
3074
+ let textContent = "";
3040
3075
  while (pos < xml.length) {
3041
3076
  skipWhitespace();
3042
3077
  if (xml[pos] === "<" && xml[pos + 1] === "/") {
@@ -3047,9 +3082,33 @@ ${err.message || err.toString()}`);
3047
3082
  break;
3048
3083
  }
3049
3084
  const child = parseNode();
3050
- if (child) children.push(child);
3085
+ if (typeof child === "string") {
3086
+ textContent += child;
3087
+ } else if (child) {
3088
+ children.push(child);
3089
+ }
3090
+ }
3091
+ if (children.length === 0 && textContent) {
3092
+ const value = isNumeric(textContent) ? Number(textContent) : textContent;
3093
+ return { [tagName]: value };
3051
3094
  }
3052
- return { tag: tagName, attributes, children };
3095
+ if (children.length === 0) {
3096
+ return { [tagName]: "" };
3097
+ }
3098
+ const result = {};
3099
+ for (const child of children) {
3100
+ for (const [key, value] of Object.entries(child)) {
3101
+ if (result[key]) {
3102
+ if (!Array.isArray(result[key])) {
3103
+ result[key] = [result[key]];
3104
+ }
3105
+ result[key].push(value);
3106
+ } else {
3107
+ result[key] = value;
3108
+ }
3109
+ }
3110
+ }
3111
+ return { [tagName]: result };
3053
3112
  }
3054
3113
  function parseTagName() {
3055
3114
  let name = "";
@@ -3082,8 +3141,14 @@ ${err.message || err.toString()}`);
3082
3141
  return text ? escapeXml(text, true) : null;
3083
3142
  }
3084
3143
  function parseDeclaration() {
3144
+ pos++;
3145
+ let name = "";
3146
+ while (pos < xml.length && xml[pos] !== " " && xml[pos] !== "?") {
3147
+ name += xml[pos++];
3148
+ }
3085
3149
  while (xml[pos] !== ">") pos++;
3086
3150
  pos++;
3151
+ return name;
3087
3152
  }
3088
3153
  function parseComment() {
3089
3154
  while (!(xml[pos] === "-" && xml[pos + 1] === "-" && xml[pos + 2] === ">")) pos++;
@@ -3092,6 +3157,9 @@ ${err.message || err.toString()}`);
3092
3157
  function skipWhitespace() {
3093
3158
  while (pos < xml.length && /\s/.test(xml[pos])) pos++;
3094
3159
  }
3160
+ function isNumeric(str) {
3161
+ return !isNaN(Number(str)) && !isNaN(parseFloat(str)) && str.trim() !== "";
3162
+ }
3095
3163
  return parseNode();
3096
3164
  }
3097
3165
  function toXml(obj, indent = "") {