Agent skill
delon-util
@delon/util skill - Utility functions library for array, string, date, number manipulation. For ng-events construction site progress tracking system.
Install this agent skill to your Project
npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/7spade/delon-util
SKILL.md
@delon/util - Utility Functions Library
Trigger patterns: "utility", "helper", "@delon/util", "format", "deepCopy", "deepMerge"
Overview
@delon/util provides a comprehensive collection of utility functions for common data manipulation tasks in ng-alain applications.
Package: @delon/util@20.1.0
Categories
1. Array Utilities (array/)
deepCopy - Deep Copy Arrays/Objects
import { deepCopy } from '@delon/util/array';
const original = { name: '任務', items: [1, 2, 3], meta: { id: 1 } };
const copy = deepCopy(original);
// Changes to copy won't affect original
copy.items.push(4);
console.log(original.items); // [1, 2, 3]
console.log(copy.items); // [1, 2, 3, 4]
Use Cases:
- Clone state objects for immutability
- Create independent copies before mutations
- Deep cloning form data
deepMerge - Deep Merge Objects
import { deepMerge } from '@delon/util/array';
const defaults = {
config: { theme: 'light', size: 'default' },
features: ['dashboard']
};
const custom = {
config: { theme: 'dark' },
features: ['reports']
};
const merged = deepMerge(defaults, custom);
// Result: {
// config: { theme: 'dark', size: 'default' },
// features: ['dashboard', 'reports']
// }
Other Array Functions
import {
groupBy, // Group array by property
uniq, // Remove duplicates
uniqBy, // Remove duplicates by property
orderBy // Sort array by properties
} from '@delon/util/array';
// Group tasks by status
const grouped = groupBy(tasks, 'status');
// { pending: [...], completed: [...] }
// Remove duplicate IDs
const uniqueIds = uniq([1, 2, 2, 3]); // [1, 2, 3]
// Remove duplicate tasks by ID
const uniqueTasks = uniqBy(tasks, 'id');
// Sort tasks
const sorted = orderBy(tasks, ['priority', 'createdAt'], ['asc', 'desc']);
2. String Utilities (string/)
format - String Formatting
import { format } from '@delon/util/string';
// Template interpolation
const message = format('任務 {0} 已指派給 {1}', taskName, userName);
// Named parameters
const message2 = format('任務 {name} 的狀態為 {status}', {
name: '地基施工',
status: '進行中'
});
Other String Functions
import {
toCamelCase, // Convert to camelCase
toPascalCase, // Convert to PascalCase
toKebabCase, // Convert to kebab-case
toSnakeCase, // Convert to snake_case
truncate // Truncate with ellipsis
} from '@delon/util/string';
toCamelCase('task-name'); // 'taskName'
toPascalCase('task-name'); // 'TaskName'
toKebabCase('TaskName'); // 'task-name'
toSnakeCase('TaskName'); // 'task_name'
truncate('Long text...', 10); // 'Long te...'
3. Date Utilities (date/)
getTimeDistance - Get Time Ranges
import { getTimeDistance } from '@delon/util/date';
// Get today's date range
const today = getTimeDistance('today');
// [Date(2024-12-25 00:00:00), Date(2024-12-25 23:59:59)]
// Get this week's date range
const week = getTimeDistance('week');
// Get this month's date range
const month = getTimeDistance('month');
// Get this year's date range
const year = getTimeDistance('year');
// Custom range with offset
const lastWeek = getTimeDistance('week', -1);
Supported Types:
'today'- Current day'week'- Current week (Sunday to Saturday)'month'- Current month'year'- Current year- Custom offset (negative for past, positive for future)
formatDistanceToNow - Relative Time
import { formatDistanceToNow } from '@delon/util/date';
const createdAt = new Date('2024-12-20');
const relative = formatDistanceToNow(createdAt);
// "5 days ago"
const futureDate = new Date('2024-12-30');
const future = formatDistanceToNow(futureDate);
// "in 5 days"
4. Number Utilities (number/)
currency - Currency Formatting
import { currency } from '@delon/util/number';
// Format as currency
currency(1234567.89); // "$1,234,567.89"
currency(1234567.89, { unit: '¥' }); // "¥1,234,567.89"
currency(1234.5, { precision: 0 }); // "$1,235"
Other Number Functions
import {
toFixed, // Round to fixed decimals
toPercent, // Convert to percentage
toThousands // Add thousands separators
} from '@delon/util/number';
toFixed(1.2345, 2); // "1.23"
toPercent(0.1234); // "12.34%"
toPercent(0.1234, 1); // "12.3%"
toThousands(1234567); // "1,234,567"
5. Browser Utilities (browser/)
copyToClipboard - Copy to Clipboard
import { copy } from '@delon/util/browser';
async copyTaskLink(taskId: string) {
const link = `${window.location.origin}/tasks/${taskId}`;
const success = await copy(link);
if (success) {
this.messageService.success('連結已複製');
} else {
this.messageService.error('複製失敗');
}
}
Other Browser Functions
import {
scrollToTop, // Smooth scroll to top
deepGet, // Get nested object property
deepSet, // Set nested object property
isEmpty, // Check if value is empty
isEqual, // Deep equality check
updateHostClass // Update host element classes
} from '@delon/util/browser';
scrollToTop();
scrollToTop({ duration: 500 });
const value = deepGet(obj, 'user.profile.name');
deepSet(obj, 'user.profile.name', 'New Name');
isEmpty(null); // true
isEmpty(''); // true
isEmpty([]); // true
isEmpty({}); // true
isEqual({ a: 1 }, { a: 1 }); // true
Real-World Examples
Task Management Utilities
import { Component, signal, computed, inject } from '@angular/core';
import { deepCopy, groupBy, orderBy } from '@delon/util/array';
import { format } from '@delon/util/string';
import { getTimeDistance } from '@delon/util/date';
import { copy } from '@delon/util/browser';
import { NzMessageService } from 'ng-zorro-antd/message';
@Component({
selector: 'app-task-list',
standalone: true,
template: `
<nz-card>
<div nz-row [nzGutter]="16">
@for (group of groupedTasks() | keyvalue; track group.key) {
<div nz-col [nzSpan]="8">
<h3>{{ group.key }} ({{ group.value.length }})</h3>
@for (task of group.value; track task.id) {
<nz-card>
<h4>{{ task.title }}</h4>
<p>{{ formatTaskInfo(task) }}</p>
<button nz-button (click)="copyTaskLink(task.id)">
複製連結
</button>
</nz-card>
}
</div>
}
</div>
</nz-card>
`
})
export class TaskListComponent {
private messageService = inject(NzMessageService);
// Original tasks from service
tasks = signal<Task[]>([]);
// Group tasks by status using @delon/util
groupedTasks = computed(() =>
groupBy(this.sortedTasks(), 'status')
);
// Sort tasks by priority and date
sortedTasks = computed(() =>
orderBy(
this.tasks(),
['priority', 'createdAt'],
['asc', 'desc']
)
);
// Format task information
formatTaskInfo(task: Task): string {
return format(
'優先級: {priority}, 建立於 {date}',
{
priority: task.priority,
date: this.formatDate(task.createdAt)
}
);
}
// Copy task link to clipboard
async copyTaskLink(taskId: string): Promise<void> {
const link = `${window.location.origin}/tasks/${taskId}`;
const success = await copy(link);
if (success) {
this.messageService.success('任務連結已複製');
} else {
this.messageService.error('複製失敗,請手動複製');
}
}
// Clone task for editing
cloneTaskForEdit(task: Task): Task {
return deepCopy(task);
}
// Get this week's tasks
getThisWeekTasks(): Task[] {
const [start, end] = getTimeDistance('week');
return this.tasks().filter(t =>
t.createdAt >= start && t.createdAt <= end
);
}
private formatDate(date: Date): string {
return format(
'{year}-{month}-{day}',
{
year: date.getFullYear(),
month: String(date.getMonth() + 1).padStart(2, '0'),
day: String(date.getDate()).padStart(2, '0')
}
);
}
}
Form Data Utilities
import { Component, signal } from '@angular/core';
import { deepCopy, deepMerge } from '@delon/util/array';
import { isEmpty } from '@delon/util/browser';
@Component({
selector: 'app-task-form',
standalone: true,
template: `
<form nz-form (ngSubmit)="handleSubmit()">
<!-- form fields -->
<button nz-button [disabled]="hasEmptyRequired()">
提交
</button>
</form>
`
})
export class TaskFormComponent {
// Default form values
private defaults = {
priority: 'medium',
status: 'pending',
assignee: null,
tags: []
};
// Form data with defaults
formData = signal(deepCopy(this.defaults));
// Original task (for editing)
originalTask = signal<Task | null>(null);
// Load task for editing
loadTask(task: Task): void {
// Merge task data with defaults
const merged = deepMerge(this.defaults, task);
this.formData.set(merged);
this.originalTask.set(deepCopy(task));
}
// Check if required fields are empty
hasEmptyRequired(): boolean {
const data = this.formData();
return isEmpty(data.title) || isEmpty(data.assignee);
}
// Check if form has changes
hasChanges(): boolean {
const original = this.originalTask();
if (!original) return true;
return !isEqual(original, this.formData());
}
handleSubmit(): void {
if (!this.hasEmptyRequired()) {
// Create clean copy for submission
const submitData = deepCopy(this.formData());
// Submit...
}
}
}
Best Practices
1. Use Utilities for Immutability
✅ DO:
const taskCopy = deepCopy(task);
taskCopy.status = 'completed';
this.tasks.update(tasks => [...tasks, taskCopy]);
❌ DON'T:
task.status = 'completed';
this.tasks.update(tasks => [...tasks, task]); // Mutates original
2. Leverage Computed Signals with Utilities
✅ DO:
groupedTasks = computed(() => groupBy(this.tasks(), 'status'));
sortedTasks = computed(() => orderBy(this.tasks(), ['priority'], ['asc']));
3. Use Type-Safe Utilities
✅ DO:
import { deepCopy } from '@delon/util/array';
const copy: Task = deepCopy<Task>(originalTask);
Performance Considerations
- deepCopy: Expensive for large objects - use sparingly
- groupBy/orderBy: Wrap in computed() to avoid recalculation
- getTimeDistance: Cache results if used frequently
- copy: Async operation - handle loading states
Integration Checklist
- Install @delon/util@20.1.0
- Import specific utilities (tree-shaking friendly)
- Use with Angular Signals for reactivity
- Add TypeScript generics for type safety
- Handle async operations (copy)
- Test edge cases (null, undefined, empty)
Cross-References
- angular-component - Signals integration
- delon-form - Form utilities for validation
- firebase-repository - deepCopy for state management
Version: 1.0
Created: 2025-12-25
Maintainer: ng-events(GigHub) Development Team
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
perigon-backend
Perigon ASP.NET Core + EF Core + Aspire conventions
perigon-agent
Pointers for Copilot/agents to apply Perigon conventions
perigon-angular
Angular 21+ standalone/Material/signal conventions for Perigon WebApp
fastapi-mastery
Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.
context7-efficient
Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.
browser-use
Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.
Didn't find tool you were looking for?