Skip to content

Commit 220feb9

Browse files
author
QuantCode Agent
committed
fix: repair failing utility tests and implement missing functionality
- calculator: divide now throws on division by zero instead of returning Infinity - string-utils: fix wordCount for consecutive spaces; implement word-boundary truncate with ellipsis - task-manager: implement remove, update, and sortBy (priority/createdAt) - date-utils: fix formatRelative rounding so 36h reads '2 days ago' and no '24 hours ago' output - validator: accept long TLDs in isEmail and host:port URLs in isUrl
1 parent 2354bc5 commit 220feb9

5 files changed

Lines changed: 33 additions & 29 deletions

File tree

src/calculator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function multiply(a: number, b: number): number {
1515
return a * b
1616
}
1717

18-
// BUG: Division by zero is not handled
1918
export function divide(a: number, b: number): number {
19+
if (b === 0) throw new Error("Division by zero")
2020
return a / b
2121
}

src/date-utils.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,21 @@
55
/**
66
* Format a date as a human-readable relative string.
77
* e.g. "2 days ago", "just now", "in 3 hours"
8-
*
9-
* BUG: off-by-one — uses Math.floor where Math.round is needed for days,
10-
* causing "1 day ago" to appear for anything from 12h to 47h.
118
*/
129
export function formatRelative(date: Date, now: Date = new Date()): string {
1310
const diffMs = now.getTime() - date.getTime()
1411
const diffSec = diffMs / 1000
1512
const diffMin = diffSec / 60
1613
const diffHours = diffMin / 60
17-
const diffDays = Math.floor(diffHours / 24) // BUG: should be Math.round
14+
const diffDays = Math.round(diffHours / 24)
1815

1916
if (Math.abs(diffSec) < 60) return "just now"
2017
if (Math.abs(diffMin) < 60) {
2118
const m = Math.round(Math.abs(diffMin))
2219
return diffMs > 0 ? `${m} minute${m !== 1 ? "s" : ""} ago` : `in ${m} minute${m !== 1 ? "s" : ""}`
2320
}
24-
if (Math.abs(diffHours) < 24) {
25-
const h = Math.round(Math.abs(diffHours))
21+
const h = Math.round(Math.abs(diffHours))
22+
if (h < 24) {
2623
return diffMs > 0 ? `${h} hour${h !== 1 ? "s" : ""} ago` : `in ${h} hour${h !== 1 ? "s" : ""}`
2724
}
2825
const d = Math.abs(diffDays)

src/string-utils.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ export function reverse(str: string): string {
1111
return str.split("").reverse().join("")
1212
}
1313

14-
// TODO: implement truncate — should truncate at a word boundary, with "..."
15-
// counting toward maxLength. Return unchanged if str.length <= maxLength.
1614
export function truncate(str: string, maxLength: number): string {
17-
throw new Error("not implemented")
15+
if (str.length <= maxLength) return str
16+
const ellipsis = "..."
17+
if (maxLength <= ellipsis.length) return str.slice(0, maxLength)
18+
const budget = maxLength - ellipsis.length
19+
const cut = str.slice(0, budget)
20+
const lastSpace = cut.lastIndexOf(" ")
21+
const trimmed = lastSpace >= 0 ? cut.slice(0, lastSpace) : cut
22+
return trimmed + ellipsis
1823
}
1924

2025
export function slugify(str: string): string {
@@ -24,8 +29,7 @@ export function slugify(str: string): string {
2429
.replace(/^-|-$/g, "")
2530
}
2631

27-
// BUG: This doesn't handle multiple consecutive spaces
2832
export function wordCount(str: string): number {
2933
if (!str.trim()) return 0
30-
return str.split(" ").length
34+
return str.trim().split(/\s+/).length
3135
}

src/task-manager.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,30 @@ export class TaskManager {
5252
return true
5353
}
5454

55-
// TODO: implement — remove a task by id, return true if removed, false if not found
5655
remove(id: string): boolean {
57-
throw new Error("not implemented")
56+
if (!this.tasks.has(id)) return false
57+
this.tasks.delete(id)
58+
return true
5859
}
5960

60-
// TODO: implement — update title/description/priority of a task
61-
// return true if updated, false if not found
6261
update(id: string, changes: Partial<Pick<Task, "title" | "description" | "priority">>): boolean {
63-
throw new Error("not implemented")
62+
const task = this.tasks.get(id)
63+
if (!task) return false
64+
if (changes.title !== undefined) task.title = changes.title
65+
if (changes.description !== undefined) task.description = changes.description
66+
if (changes.priority !== undefined) task.priority = changes.priority
67+
return true
6468
}
6569

66-
// TODO: implement — return all tasks sorted by the given field
67-
// priority sort order: high > medium > low
6870
sortBy(field: "priority" | "createdAt" | "status"): Task[] {
69-
throw new Error("not implemented")
71+
const tasks = Array.from(this.tasks.values())
72+
if (field === "priority") {
73+
const order: Record<Priority, number> = { high: 0, medium: 1, low: 2 }
74+
return tasks.slice().sort((a, b) => order[a.priority] - order[b.priority])
75+
}
76+
if (field === "createdAt") {
77+
return tasks.slice().sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())
78+
}
79+
return tasks.slice().sort((a, b) => a.status.localeCompare(b.status))
7080
}
7181
}

src/validator.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,18 @@
44

55
/**
66
* Returns true if the string is a valid email address.
7-
*
8-
* BUG: the regex does not allow subdomains (e.g. user@mail.example.com fails)
9-
* and rejects valid TLDs longer than 4 chars (e.g. .museum, .travel).
107
*/
118
export function isEmail(value: string): boolean {
12-
// BUG: too restrictive — missing subdomain support and long TLDs
13-
return /^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,4}$/.test(value)
9+
return /^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}$/.test(value)
1410
}
1511

1612
/**
1713
* Returns true if the string is a valid URL (http or https).
18-
*
19-
* BUG: rejects URLs with ports (e.g. http://localhost:3000)
2014
*/
2115
export function isUrl(value: string): boolean {
2216
try {
2317
const url = new URL(value)
24-
// BUG: only allows http/https but also rejects valid port usage
25-
return (url.protocol === "http:" || url.protocol === "https:") && url.port === ""
18+
return url.protocol === "http:" || url.protocol === "https:"
2619
} catch {
2720
return false
2821
}

0 commit comments

Comments
 (0)