Initial commit: add .gitignore and README

This commit is contained in:
defiQUG
2026-02-09 21:51:55 -08:00
commit d904c04c2d
52 changed files with 1613 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
{
"name": "@workspace/shared-utils",
"version": "1.0.0",
"description": "Shared utility functions",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "vitest",
"lint": "eslint src",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"date-fns": "^3.3.1",
"uuid": "^9.0.1"
},
"devDependencies": {
"typescript": "^5.5.4",
"@types/uuid": "^9.0.7",
"vitest": "^1.2.0"
},
"files": [
"dist"
],
"publishConfig": {
"access": "restricted"
}
}

View File

@@ -0,0 +1,35 @@
/**
* Date utility functions
*/
import { format, parseISO, isValid } from 'date-fns';
/**
* Format date to ISO string
*/
export function formatDate(date: Date | string, formatStr: string = 'yyyy-MM-dd'): string {
const dateObj = typeof date === 'string' ? parseISO(date) : date;
if (!isValid(dateObj)) {
throw new Error('Invalid date');
}
return format(dateObj, formatStr);
}
/**
* Format date to ISO 8601
*/
export function formatISO(date: Date | string): string {
const dateObj = typeof date === 'string' ? parseISO(date) : date;
if (!isValid(dateObj)) {
throw new Error('Invalid date');
}
return dateObj.toISOString();
}
/**
* Check if date is valid
*/
export function isValidDate(date: unknown): date is Date {
return date instanceof Date && isValid(date);
}

View File

@@ -0,0 +1,10 @@
/**
* @workspace/shared-utils
* Shared utility functions
*/
export * from './date';
export * from './string';
export * from './validation';
export * from './uuid';

View File

@@ -0,0 +1,58 @@
/**
* String utility functions
*/
/**
* Capitalize first letter
*/
export function capitalize(str: string): string {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
/**
* Convert string to camelCase
*/
export function toCamelCase(str: string): string {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
})
.replace(/\s+/g, '');
}
/**
* Convert string to kebab-case
*/
export function toKebabCase(str: string): string {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase();
}
/**
* Convert string to snake_case
*/
export function toSnakeCase(str: string): string {
return str
.replace(/([a-z])([A-Z])/g, '$1_$2')
.replace(/[\s-]+/g, '_')
.toLowerCase();
}
/**
* Truncate string with ellipsis
*/
export function truncate(str: string, length: number, suffix: string = '...'): string {
if (str.length <= length) return str;
return str.slice(0, length - suffix.length) + suffix;
}
/**
* Remove whitespace
*/
export function removeWhitespace(str: string): string {
return str.replace(/\s+/g, '');
}

View File

@@ -0,0 +1,20 @@
/**
* UUID utility functions
*/
import { v4 as uuidv4, validate as validateUUID } from 'uuid';
/**
* Generate UUID v4
*/
export function generateUUID(): string {
return uuidv4();
}
/**
* Validate UUID
*/
export function isValidUUID(uuid: string): boolean {
return validateUUID(uuid);
}

View File

@@ -0,0 +1,49 @@
/**
* Validation utility functions
*/
/**
* Check if value is empty
*/
export function isEmpty(value: unknown): boolean {
if (value === null || value === undefined) return true;
if (typeof value === 'string') return value.trim().length === 0;
if (Array.isArray(value)) return value.length === 0;
if (typeof value === 'object') return Object.keys(value).length === 0;
return false;
}
/**
* Check if value is not empty
*/
export function isNotEmpty(value: unknown): boolean {
return !isEmpty(value);
}
/**
* Check if email is valid
*/
export function isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
/**
* Check if URL is valid
*/
export function isValidUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
/**
* Check if string is numeric
*/
export function isNumeric(str: string): boolean {
return !isNaN(Number(str)) && !isNaN(parseFloat(str));
}

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022"],
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}