|
| 1 | +# Utils Documentation |
| 2 | + |
| 3 | +This directory contains comprehensive documentation for all utility functions and shared functionality used throughout the TechDiary application. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +Utilities are pure functions and shared helpers that provide common functionality across components, services, and other parts of the application. They are designed to be reusable, testable, and framework-agnostic where possible. |
| 8 | + |
| 9 | +## Available Utilities |
| 10 | + |
| 11 | +### Core Utilities |
| 12 | +- **[fonts](./fonts.md)** - Font configuration and Bengali typography support |
| 13 | +- **[curry](./curry.md)** - Debounce utility for performance optimization |
| 14 | +- **[getFileUrl](./getFileUrl.md)** - Multi-provider file URL generation and optimization |
| 15 | + |
| 16 | +### Content Processing |
| 17 | +- **[markdoc-parser](./markdoc-parser.md)** - Markdown parsing with custom components |
| 18 | +- **[markdown-tags](./markdown-tags.md)** - React components for Markdoc integration |
| 19 | + |
| 20 | +## Quick Reference |
| 21 | + |
| 22 | +| Utility | Purpose | Key Features | |
| 23 | +|---------|---------|--------------| |
| 24 | +| `fonts` | Typography | Bengali font loading, Kohinoor Bangla variants | |
| 25 | +| `curry` | Performance | Debounce with cancel/flush, TypeScript support | |
| 26 | +| `getFileUrl` | Media | Multi-provider URLs, auto-optimization | |
| 27 | +| `markdoc-parser` | Content | Markdown to React, custom tags | |
| 28 | +| `markdown-tags` | Components | Interactive Markdoc components | |
| 29 | + |
| 30 | +## Common Patterns |
| 31 | + |
| 32 | +### 1. Font Usage Pattern |
| 33 | +```typescript |
| 34 | +import { fontKohinoorBanglaRegular } from '@/utils/fonts'; |
| 35 | + |
| 36 | +<div className={fontKohinoorBanglaRegular.className}> |
| 37 | + Bengali content with proper typography |
| 38 | +</div> |
| 39 | +``` |
| 40 | + |
| 41 | +### 2. Debounce Pattern |
| 42 | +```typescript |
| 43 | +import { debounce } from '@/utils/curry'; |
| 44 | + |
| 45 | +const debouncedSearch = debounce( |
| 46 | + (query: string) => performSearch(query), |
| 47 | + { delay: 300 } |
| 48 | +); |
| 49 | + |
| 50 | +// Use throughout component lifecycle |
| 51 | +debouncedSearch('search term'); |
| 52 | +debouncedSearch.cancel(); // Cancel if needed |
| 53 | +``` |
| 54 | + |
| 55 | +### 3. File URL Generation Pattern |
| 56 | +```typescript |
| 57 | +import getFileUrl from '@/utils/getFileUrl'; |
| 58 | + |
| 59 | +// Automatic provider detection and optimization |
| 60 | +const optimizedUrl = getFileUrl({ |
| 61 | + provider: 'cloudinary', |
| 62 | + key: 'image-public-id' |
| 63 | +}); |
| 64 | +``` |
| 65 | + |
| 66 | +### 4. Content Parsing Pattern |
| 67 | +```typescript |
| 68 | +import { markdocParser } from '@/utils/markdoc-parser'; |
| 69 | + |
| 70 | +const richContent = markdocParser(` |
| 71 | +# Title |
| 72 | +{% callout type="note" title="Important" %} |
| 73 | +Custom content with interactive components |
| 74 | +{% /callout %} |
| 75 | +`); |
| 76 | +``` |
| 77 | + |
| 78 | +## Design Principles |
| 79 | + |
| 80 | +### 1. Pure Functions |
| 81 | +```typescript |
| 82 | +// Predictable input/output |
| 83 | +export const processData = (input: DataType): ProcessedData => { |
| 84 | + // No side effects |
| 85 | + return transformedData; |
| 86 | +}; |
| 87 | +``` |
| 88 | + |
| 89 | +### 2. Type Safety |
| 90 | +```typescript |
| 91 | +// Comprehensive TypeScript interfaces |
| 92 | +export interface UtilityOptions { |
| 93 | + required: string; |
| 94 | + optional?: boolean; |
| 95 | +} |
| 96 | + |
| 97 | +export const utility = <T>( |
| 98 | + input: T, |
| 99 | + options: UtilityOptions |
| 100 | +): ProcessedResult<T> => { |
| 101 | + // Type-safe implementation |
| 102 | +}; |
| 103 | +``` |
| 104 | + |
| 105 | +### 3. Error Handling |
| 106 | +```typescript |
| 107 | +// Graceful error handling with fallbacks |
| 108 | +export const safeUtility = (input: unknown): Result => { |
| 109 | + try { |
| 110 | + return processInput(input); |
| 111 | + } catch (error) { |
| 112 | + console.warn('Utility error:', error); |
| 113 | + return fallbackValue; |
| 114 | + } |
| 115 | +}; |
| 116 | +``` |
| 117 | + |
| 118 | +### 4. Configuration-Driven |
| 119 | +```typescript |
| 120 | +// Configurable behavior |
| 121 | +export const configurableUtil = ( |
| 122 | + input: Input, |
| 123 | + config: Config = defaultConfig |
| 124 | +): Output => { |
| 125 | + return processWithConfig(input, { ...defaultConfig, ...config }); |
| 126 | +}; |
| 127 | +``` |
| 128 | + |
| 129 | +## Performance Considerations |
| 130 | + |
| 131 | +### Memory Management |
| 132 | +- Utilities avoid memory leaks through proper cleanup |
| 133 | +- Debounce functions include cancellation mechanisms |
| 134 | +- Large data processing uses streaming where applicable |
| 135 | + |
| 136 | +### Optimization Strategies |
| 137 | +- Memoization for expensive calculations |
| 138 | +- Lazy loading for heavy dependencies |
| 139 | +- Tree-shaking friendly exports |
| 140 | + |
| 141 | +### Bundle Size Impact |
| 142 | +```typescript |
| 143 | +// Tree-shakeable exports |
| 144 | +export { specificUtility } from './specific-module'; |
| 145 | + |
| 146 | +// Avoid barrel exports for large utilities |
| 147 | +// import { heavyUtil } from './heavy-utils'; // ❌ |
| 148 | +import { heavyUtil } from './heavy-utils/heavy-util'; // ✅ |
| 149 | +``` |
| 150 | + |
| 151 | +## Testing Strategies |
| 152 | + |
| 153 | +### Unit Testing Pattern |
| 154 | +```typescript |
| 155 | +describe('utilityFunction', () => { |
| 156 | + it('handles valid input correctly', () => { |
| 157 | + const result = utilityFunction(validInput); |
| 158 | + expect(result).toEqual(expectedOutput); |
| 159 | + }); |
| 160 | + |
| 161 | + it('handles edge cases gracefully', () => { |
| 162 | + const result = utilityFunction(edgeCase); |
| 163 | + expect(result).toBeDefined(); |
| 164 | + }); |
| 165 | + |
| 166 | + it('throws appropriate errors for invalid input', () => { |
| 167 | + expect(() => utilityFunction(invalidInput)).toThrow(); |
| 168 | + }); |
| 169 | +}); |
| 170 | +``` |
| 171 | + |
| 172 | +### Integration Testing |
| 173 | +```typescript |
| 174 | +// Test utilities in realistic scenarios |
| 175 | +describe('utility integration', () => { |
| 176 | + it('works with real component data', () => { |
| 177 | + const componentData = getTestComponentData(); |
| 178 | + const result = processComponentData(componentData); |
| 179 | + expect(result).toMatchSnapshot(); |
| 180 | + }); |
| 181 | +}); |
| 182 | +``` |
| 183 | + |
| 184 | +## Environment Integration |
| 185 | + |
| 186 | +### Environment Variables |
| 187 | +```typescript |
| 188 | +// Type-safe environment access |
| 189 | +import { env } from '@/env'; |
| 190 | + |
| 191 | +export const getCloudinaryUrl = (publicId: string) => { |
| 192 | + return `https://res.cloudinary.com/${env.CLOUDINARY_CLOUD_NAME}/image/upload/${publicId}`; |
| 193 | +}; |
| 194 | +``` |
| 195 | + |
| 196 | +### Provider Configuration |
| 197 | +```typescript |
| 198 | +// Multi-provider support with fallbacks |
| 199 | +const providers = { |
| 200 | + cloudinary: CloudinaryProvider, |
| 201 | + r2: R2Provider, |
| 202 | + local: LocalProvider |
| 203 | +}; |
| 204 | + |
| 205 | +export const getProvider = (type: ProviderType) => { |
| 206 | + return providers[type] || providers.local; |
| 207 | +}; |
| 208 | +``` |
| 209 | + |
| 210 | +## Internationalization Support |
| 211 | + |
| 212 | +### Language-Aware Utilities |
| 213 | +```typescript |
| 214 | +// Utilities that respect current language |
| 215 | +export const formatContent = (content: string, lang: Language) => { |
| 216 | + const formatter = getFormatterForLanguage(lang); |
| 217 | + return formatter.format(content); |
| 218 | +}; |
| 219 | +``` |
| 220 | + |
| 221 | +### Text Processing |
| 222 | +```typescript |
| 223 | +// Bengali text processing utilities |
| 224 | +export const processBengaliText = (text: string): ProcessedText => { |
| 225 | + return { |
| 226 | + normalized: normalizeBengaliText(text), |
| 227 | + wordCount: getBengaliWordCount(text), |
| 228 | + readingTime: calculateBengaliReadingTime(text) |
| 229 | + }; |
| 230 | +}; |
| 231 | +``` |
| 232 | + |
| 233 | +## Security Considerations |
| 234 | + |
| 235 | +### Input Sanitization |
| 236 | +```typescript |
| 237 | +// Sanitize user input before processing |
| 238 | +export const sanitizeInput = (input: string): string => { |
| 239 | + return DOMPurify.sanitize(input, { |
| 240 | + ALLOWED_TAGS: ['p', 'br', 'strong', 'em'], |
| 241 | + ALLOWED_ATTR: [] |
| 242 | + }); |
| 243 | +}; |
| 244 | +``` |
| 245 | + |
| 246 | +### URL Validation |
| 247 | +```typescript |
| 248 | +// Validate URLs before processing |
| 249 | +export const validateUrl = (url: string): boolean => { |
| 250 | + try { |
| 251 | + const parsed = new URL(url); |
| 252 | + return ['http:', 'https:'].includes(parsed.protocol); |
| 253 | + } catch { |
| 254 | + return false; |
| 255 | + } |
| 256 | +}; |
| 257 | +``` |
| 258 | + |
| 259 | +## Browser Compatibility |
| 260 | + |
| 261 | +### Feature Detection |
| 262 | +```typescript |
| 263 | +// Graceful degradation for browser features |
| 264 | +export const supportsWebP = (): boolean => { |
| 265 | + if (typeof window === 'undefined') return false; |
| 266 | + |
| 267 | + const canvas = document.createElement('canvas'); |
| 268 | + return canvas.toDataURL('image/webp').indexOf('webp') > -1; |
| 269 | +}; |
| 270 | +``` |
| 271 | + |
| 272 | +### Polyfill Integration |
| 273 | +```typescript |
| 274 | +// Conditional polyfill loading |
| 275 | +export const ensureIntersectionObserver = async (): Promise<void> => { |
| 276 | + if (!('IntersectionObserver' in window)) { |
| 277 | + await import('intersection-observer'); |
| 278 | + } |
| 279 | +}; |
| 280 | +``` |
| 281 | + |
| 282 | +## Contributing Guidelines |
| 283 | + |
| 284 | +### Creating New Utilities |
| 285 | + |
| 286 | +1. **Function Signature** |
| 287 | +```typescript |
| 288 | +// Clear, descriptive function signature |
| 289 | +export const descriptiveUtilityName = ( |
| 290 | + primaryInput: PrimaryType, |
| 291 | + options: UtilityOptions = {} |
| 292 | +): ReturnType => { |
| 293 | + // Implementation |
| 294 | +}; |
| 295 | +``` |
| 296 | + |
| 297 | +2. **Documentation Template** |
| 298 | +```markdown |
| 299 | +# UtilityName |
| 300 | + |
| 301 | +## Overview |
| 302 | +Brief description of utility purpose and use cases. |
| 303 | + |
| 304 | +## API Reference |
| 305 | +Function signatures, parameters, and return types. |
| 306 | + |
| 307 | +## Usage Examples |
| 308 | +Practical examples with common scenarios. |
| 309 | + |
| 310 | +## Performance Notes |
| 311 | +Performance characteristics and optimization tips. |
| 312 | +``` |
| 313 | + |
| 314 | +3. **Testing Requirements** |
| 315 | +- Unit tests for all code paths |
| 316 | +- Edge case handling tests |
| 317 | +- Performance benchmarks for critical utilities |
| 318 | +- Browser compatibility tests where applicable |
| 319 | + |
| 320 | +### Code Review Checklist |
| 321 | + |
| 322 | +- [ ] Function is pure (no side effects) |
| 323 | +- [ ] Comprehensive TypeScript typing |
| 324 | +- [ ] Error handling implemented |
| 325 | +- [ ] Performance optimized |
| 326 | +- [ ] Browser compatibility considered |
| 327 | +- [ ] Security implications reviewed |
| 328 | +- [ ] Documentation complete |
| 329 | +- [ ] Tests written and passing |
| 330 | + |
| 331 | +## Related Documentation |
| 332 | + |
| 333 | +- [Components Documentation](../components/README.md) - Components that use these utilities |
| 334 | +- [Hooks Documentation](../hooks/README.md) - Custom hooks that may wrap utilities |
| 335 | +- [API Documentation](../api/README.md) - Server-side utility usage |
| 336 | +- [Performance Guide](../performance/README.md) - Performance optimization strategies |
| 337 | + |
| 338 | +## Migration Guide |
| 339 | + |
| 340 | +### Updating Utilities |
| 341 | +When updating existing utilities, consider: |
| 342 | + |
| 343 | +1. **Backward Compatibility** |
| 344 | +```typescript |
| 345 | +// Maintain old signature while adding new features |
| 346 | +export const utility = ( |
| 347 | + input: Input, |
| 348 | + optionsOrLegacyParam?: Options | LegacyType |
| 349 | +): Output => { |
| 350 | + // Handle both old and new signatures |
| 351 | + const options = isLegacyParam(optionsOrLegacyParam) |
| 352 | + ? convertLegacyOptions(optionsOrLegacyParam) |
| 353 | + : optionsOrLegacyParam || {}; |
| 354 | + |
| 355 | + // Implementation |
| 356 | +}; |
| 357 | +``` |
| 358 | + |
| 359 | +2. **Deprecation Strategy** |
| 360 | +```typescript |
| 361 | +// Clear deprecation warnings |
| 362 | +export const oldUtility = (input: Input): Output => { |
| 363 | + console.warn('oldUtility is deprecated. Use newUtility instead.'); |
| 364 | + return newUtility(input); |
| 365 | +}; |
| 366 | +``` |
| 367 | + |
| 368 | +3. **Migration Path Documentation** |
| 369 | +```markdown |
| 370 | +## Migration from v1 to v2 |
| 371 | + |
| 372 | +### Breaking Changes |
| 373 | +- Function signature changed from `old(a, b)` to `new({ a, b })` |
| 374 | +- Return type now includes additional metadata |
| 375 | + |
| 376 | +### Migration Example |
| 377 | +```typescript |
| 378 | +// Old |
| 379 | +const result = oldFunction(param1, param2); |
| 380 | + |
| 381 | +// New |
| 382 | +const result = newFunction({ param1, param2 }); |
| 383 | +``` |
| 384 | + |
| 385 | +## Resources |
| 386 | + |
| 387 | +- [TypeScript Handbook](https://www.typescriptlang.org/docs/) |
| 388 | +- [JavaScript Performance Best Practices](https://web.dev/fast/) |
| 389 | +- [Web API Documentation](https://developer.mozilla.org/en-US/docs/Web/API) |
| 390 | +- [Next.js Utilities](https://nextjs.org/docs/basic-features/utilities) |
0 commit comments