vueless
Version:
Vue Styleless UI Component Library, powered by Tailwind CSS.
188 lines (146 loc) • 4.75 kB
text/typescript
import { revFormat, formats } from "./utilFormatting";
import { getDateFromUnixTimestamp } from "./utilDate";
import { SEPARATOR, TOKEN_REG_EXP } from "./constants";
import type { DateLocale } from "./utilFormatting";
type UnknownFunction = (...args: unknown[]) => unknown;
type Operation = {
fn: UnknownFunction;
val: string;
};
export function getInitialActiveDate<TLocale>(localValue: TLocale) {
if (Array.isArray(localValue) && localValue.length) {
return localValue[localValue.length - 1];
}
if (localValue instanceof Date) {
return localValue;
}
return new Date();
}
export function formatDate<TLocale>(date: Date | null, format = "Y-m-d H:i:S", locale: TLocale) {
if (date === null) {
return "";
}
return format
.split("")
.map((char, i, arr) => {
if (char in formats && arr[i - 1] !== "\\") {
return formats[char as keyof typeof formats](date, locale as DateLocale);
}
if (char !== "\\") {
return char;
}
return "";
})
.join("");
}
export function isNumeric(char: string | number) {
return /^\d+$/.test(String(char));
}
export function parseDate<TLocale extends DateLocale>(
date: Date | string | null,
format: string = "Y-m-d H:i:S",
locale: TLocale,
) {
if (date === null) {
return null;
}
let timeless = false;
let parsedDate: Date | null = null;
const originalDate = date;
const isDateObject = date instanceof Date;
const isTimestamp = typeof date === "number";
const isString = typeof date === "string";
if (isDateObject) {
parsedDate = new Date(date.getTime());
}
if (isTimestamp) {
parsedDate = getDateFromUnixTimestamp(date);
}
if (isString) {
const dateString = String(date).trim();
if (dateString === "today") {
parsedDate = new Date();
timeless = true;
} else {
parsedDate = parseStringDate(date, format, locale) || null;
}
}
if (!(parsedDate instanceof Date && !isNaN(parsedDate.getTime()))) {
throw new Error(`Invalid date provided: ${originalDate}`);
}
if (timeless === true) {
parsedDate.setHours(0, 0, 0, 0);
}
return parsedDate;
}
export function parseStringDate<TLocale extends DateLocale>(
dateString: string,
format = "Y-m-d H:i:S",
locale: TLocale,
) {
const isWithinTimezone = /Z$/.test(dateString) || /GMT$/.test(dateString);
if (isWithinTimezone) {
return new Date(dateString);
} else {
let parsedDate = new Date(new Date().getFullYear(), 0, 1, 0, 0, 0, 0);
const isRelativeDay = [locale.tomorrow, locale.today, locale.tomorrow].some((word) => {
return word && dateString.toLowerCase().includes(word.toLowerCase());
});
if (!isRelativeDay) {
format = format.replaceAll("r", "").trim();
}
let matched;
const operations: Operation[] = [];
for (let i = 0, matchIndex = 0, regexStr = ""; i < format.length; i += 1) {
const token2 = format[i] as keyof typeof TOKEN_REG_EXP | "\\";
const isBackSlash = token2 === "\\";
const escaped = format[i - 1] === "\\" || isBackSlash;
if (TOKEN_REG_EXP[token2 as keyof typeof TOKEN_REG_EXP] && !escaped) {
regexStr += TOKEN_REG_EXP[token2];
const match = new RegExp(regexStr).exec(dateString);
if (match) {
matched = true;
operations[token2 !== "Y" ? "push" : "unshift"]({
fn: revFormat[token2 as keyof typeof revFormat] as UnknownFunction,
val: match[(matchIndex += 1)],
});
}
} else if (!isBackSlash) {
regexStr += ".";
}
}
operations.forEach((operation) => {
const { fn, val } = operation;
parsedDate = (fn(parsedDate, String(val), locale as DateLocale) || parsedDate) as Date;
});
return matched ? parsedDate : undefined;
}
}
export function dateIsOutOfRange<TLocale extends DateLocale>(
date: Date,
min: Date | string | undefined,
max: Date | string | undefined,
locale: TLocale,
dateFormat: string | null = null,
) {
if ((!dateFormat && typeof min === "string") || (!dateFormat && typeof max === "string")) {
throw new Error("strings needs a date format");
}
const minDate =
typeof min === "string" ? parseDate<TLocale>(min, String(dateFormat), locale) : min;
const maxDate =
typeof max === "string" ? parseDate<TLocale>(max, String(dateFormat), locale) : max;
if (minDate && maxDate) {
return date < minDate || date > maxDate;
}
if (minDate) {
return date < minDate;
}
if (maxDate) {
return date > maxDate;
}
return false;
}
export function getYearsRangeLabel(years: Date[]) {
return `${years.at(0)?.getFullYear()} ${SEPARATOR} ${years.at(-1)?.getFullYear()}`;
}