code refactor

This commit is contained in:
MaysWind
2025-06-08 02:10:11 +08:00
parent 8c71f03f6f
commit ce4bca8272
14 changed files with 364 additions and 467 deletions
+51 -165
View File
@@ -1,197 +1,87 @@
import type { TypeAndDisplayName } from '@/core/base.ts';
import type { UnixTimeRange } from './datetime';
import type { UnixTimeRange } from './datetime.ts';
export class FiscalYearStart {
public static readonly Default = new FiscalYearStart(1, 1);
public static readonly JanuaryFirstDay = new FiscalYearStart(1, 1);
public static readonly Default = FiscalYearStart.JanuaryFirstDay;
private static readonly MONTH_MAX_DAYS: number[] = [
31, // January
28, // February (Disallow fiscal year start on leap day)
31, // March
30, // April
31, // May
30, // June
31, // July
31, // August
30, // September
31, // October
30, // November
31 // December
];
public readonly day: number;
public readonly month: number;
public readonly day: number;
public readonly value: number;
private constructor(month: number, day: number) {
const [validMonth, validDay] = validateMonthDay(month, day);
this.day = validDay;
this.month = validMonth;
this.value = (validMonth << 8) | validDay;
this.month = month;
this.day = day;
this.value = (month << 8) | day;
}
public static of(month: number, day: number): FiscalYearStart {
public static of(month: number, day: number): FiscalYearStart | undefined {
if (!FiscalYearStart.isValidMonthDay(month, day)) {
return undefined;
}
return new FiscalYearStart(month, day);
}
public static valueOf(value: number): FiscalYearStart {
return FiscalYearStart.strictFromNumber(value);
}
public static valuesFromNumber(value: number): number[] {
return FiscalYearStart.strictFromNumber(value).values();
}
public values(): number[] {
return [
this.month,
this.day
];
}
public static parse(valueString: string): FiscalYearStart | undefined {
return FiscalYearStart.strictFromMonthDashDayString(valueString);
}
public static isValidType(value: number): boolean {
if (value < 0x0101 || value > 0x0C1F) {
return false;
}
const month = (value >> 8) & 0xFF;
const day = value & 0xFF;
try {
validateMonthDay(month, day);
return true;
} catch (error) {
return false;
}
}
public isValid(): boolean {
try {
FiscalYearStart.validateMonthDay(this.month, this.day);
return true;
} catch (error) {
return false;
}
}
public isDefault(): boolean {
return this.month === 1 && this.day === 1;
}
public static validateMonthDay(month: number, day: number): [number, number] {
return validateMonthDay(month, day);
}
public static strictFromMonthDayValues(month: number, day: number): FiscalYearStart {
return FiscalYearStart.of(month, day);
}
/**
* Create a FiscalYearStart from a uint16 value (two bytes - month high, day low)
* @param value uint16 value (month in high byte, day in low byte)
* @returns FiscalYearStart instance
* @returns FiscalYearStart instance or undefined if the value is out of range
*/
public static strictFromNumber(value: number): FiscalYearStart {
if (value < 0 || value > 0xFFFF) {
throw new Error('Invalid uint16 value');
public static valueOf(value: number): FiscalYearStart | undefined {
if (value < 0x0101 || value > 0x0C1F) {
return undefined;
}
const month = (value >> 8) & 0xFF; // high byte
const day = value & 0xFF; // low byte
try {
const [validMonth, validDay] = validateMonthDay(month, day);
return FiscalYearStart.of(validMonth, validDay);
} catch (error) {
throw new Error('Invalid uint16 value');
}
return FiscalYearStart.of(month, day);
}
/**
* Create a FiscalYearStart from a month/day string
* @param input MM-dd string (e.g. "04-01" = 1 April)
* @returns FiscalYearStart instance
* @param monthDay MM-dd string (e.g. "04-01" = 1 April)
* @returns FiscalYearStart instance or undefined if the monthDay is invalid
*/
public static strictFromMonthDashDayString(input: string): FiscalYearStart {
if (!input || !input.includes('-')) {
throw new Error('Invalid input string');
public static parse(monthDay: string): FiscalYearStart | undefined {
if (!monthDay || !monthDay.includes('-')) {
return undefined;
}
const parts = input.split('-');
const parts = monthDay.split('-');
if (parts.length !== 2) {
throw new Error('Invalid input string');
return undefined;
}
const month = parseInt(parts[0], 10);
const day = parseInt(parts[1], 10);
if (isNaN(month) || isNaN(day)) {
throw new Error('Invalid input string');
}
try {
const [validMonth, validDay] = validateMonthDay(month, day);
return FiscalYearStart.of(validMonth, validDay);
} catch (error) {
throw new Error('Invalid input string');
}
}
public static fromMonthDashDayString(input: string): FiscalYearStart | null {
try {
return FiscalYearStart.strictFromMonthDashDayString(input);
} catch (error) {
return null;
}
}
public static fromNumber(value: number): FiscalYearStart | null {
try {
return FiscalYearStart.strictFromNumber(value);
} catch (error) {
return null;
}
}
public static fromMonthDayValues(month: number, day: number): FiscalYearStart | null {
try {
return FiscalYearStart.strictFromMonthDayValues(month, day);
} catch (error) {
return null;
}
return FiscalYearStart.of(month, day);
}
public toMonthDashDayString(): string {
return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}`;
}
public toMonthDayValues(): [string, string] {
return [
`${this.month.toString().padStart(2, '0')}`,
`${this.day.toString().padStart(2, '0')}`
]
private static isValidMonthDay(month: number, day: number): boolean {
return 1 <= month && month <= 12 && 1 <= day && day <= FiscalYearStart.MONTH_MAX_DAYS[month - 1];
}
public toString(): string {
return this.toMonthDashDayString();
}
}
function validateMonthDay(month: number, day: number): [number, number] {
if (month < 1 || month > 12 || day < 1) {
throw new Error('Invalid month or day');
}
let maxDays = 31;
switch (month) {
// January, March, May, July, August, October, December
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
maxDays = 31;
break;
// April, June, September, November
case 4: case 6: case 9: case 11:
maxDays = 30;
break;
// February
case 2:
maxDays = 28; // Disallow fiscal year start on leap day
break;
}
if (day > maxDays) {
throw new Error('Invalid day for given month');
}
return [month, day];
}
export class FiscalYearUnixTime implements UnixTimeRange {
@@ -212,7 +102,7 @@ export class FiscalYearUnixTime implements UnixTimeRange {
export const LANGUAGE_DEFAULT_FISCAL_YEAR_FORMAT_VALUE: number = 0;
export class FiscalYearFormat implements TypeAndDisplayName {
export class FiscalYearFormat {
private static readonly allInstances: FiscalYearFormat[] = [];
private static readonly allInstancesByType: Record<number, FiscalYearFormat> = {};
private static readonly allInstancesByTypeName: Record<string, FiscalYearFormat> = {};
@@ -226,19 +116,15 @@ export class FiscalYearFormat implements TypeAndDisplayName {
public static readonly Default = FiscalYearFormat.EndYYYY;
public readonly type: number;
public readonly displayName: string;
public readonly typeName: string;
private constructor(type: number, displayName: string) {
private constructor(type: number, typeName: string) {
this.type = type;
this.displayName = displayName;
this.typeName = typeName;
FiscalYearFormat.allInstances.push(this);
FiscalYearFormat.allInstancesByType[type] = this;
FiscalYearFormat.allInstancesByTypeName[displayName] = this;
}
public static all(): Record<string, FiscalYearFormat> {
return FiscalYearFormat.allInstancesByTypeName;
FiscalYearFormat.allInstancesByTypeName[typeName] = this;
}
public static values(): FiscalYearFormat[] {
@@ -249,7 +135,7 @@ export class FiscalYearFormat implements TypeAndDisplayName {
return FiscalYearFormat.allInstancesByType[type];
}
public static parse(displayName: string): FiscalYearFormat | undefined {
return FiscalYearFormat.allInstancesByTypeName[displayName];
public static parse(typeName: string): FiscalYearFormat | undefined {
return FiscalYearFormat.allInstancesByTypeName[typeName];
}
}