v1.2.0 — 9 new utilities, tests, bug fixes#8
Conversation
New functions: - slugify, truncate, sleep, chunk, formatNumber - debounce, capitalize, isEmpty, deepClone Fixes: - shuffleArray no longer mutates original - uniqueArrayitems → uniqueArrayItems (typo) - randomString security warning added Added: - Vitest test suite - CHANGELOG.md
Summary by CodeRabbit
WalkthroughBumps package to v1.2.0; adds utilities (slugify, truncate, sleep, chunk, formatNumber, debounce, capitalize, isEmpty, deepClone); makes shuffleArray non‑mutating; renames uniqueArrayitems → uniqueArrayItems with deprecated alias; updates randomString JSDoc; adds Vitest tests and CHANGELOG.md. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| return text | ||
| .toLowerCase() | ||
| .trim() | ||
| .replace(/[^\w\s-]/g, '') | ||
| .replace(/[\s_-]+/g, '-') | ||
| .replace(/^-+|-+$/g, ''); |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8d65e7a366
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| randomString, randomNumber, binary, shuffleArray, | ||
| randomArrayItem, randomItemsArray, uniqueArrayItems, | ||
| slugify, truncate, chunk, formatNumber, debounce, |
There was a problem hiding this comment.
Remove unused test imports to restore TypeScript build
With noUnusedLocals enabled in tsconfig.json, tsc fails on this test file because several imported helpers are never referenced (randomNumber, binary, randomArrayItem, randomItemsArray, uniqueArrayItems, debounce). Since npm run build runs tsc first, this blocks normal builds/publishing for the package until the unused imports are removed or used.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CHANGELOG.md`:
- Line 7: The markdown headings like "### Added" (and the other H3 headings
flagged) need a blank line immediately after them to satisfy the linter; update
the CHANGELOG.md by inserting a single empty line after each "### ..." heading
(e.g., after "### Added") so there is a blank line between the heading and the
following content.
In `@src/__tests__/main.test.ts`:
- Around line 2-7: Add missing unit tests for the imported utilities: import and
test randomNumber (assert value within min/max and integer/float behavior),
binary (returns only 0 or 1 over many samples), randomArrayItem (returns an
element from a given array), randomItemsArray (returns specified count of items
from array and respects bounds), uniqueArrayItems (removes duplicates and
preserves expected length/content), and sleep (import sleep and await it
resolves after the given ms). For debounce, add a timing-based test using Jest
fake timers: wrap a mock function with debounce, call it multiple times rapidly,
advance timers and assert the wrapped function is invoked only once after the
debounce delay. Use the function names randomNumber, binary, randomArrayItem,
randomItemsArray, uniqueArrayItems, debounce, and sleep to locate code.
In `@src/main.ts`:
- Around line 120-123: The deepClone function uses
JSON.parse(JSON.stringify(obj)) which silently loses undefined and function
properties, converts Date objects to ISO strings, cannot clone
Map/Set/RegExp/TypedArray, and will throw on circular references; update the
JSDoc for deepClone to list these limitations explicitly (mention undefined,
functions, Dates -> strings, Map/Set/RegExp/TypedArray not supported, and
circular reference errors) and add a short recommendation (e.g., use a
specialized cloning utility or structuredClone when available) so callers know
the caveats for function deepClone.
- Around line 27-31: The current shuffleArray function uses [...array].sort(()
=> Math.random() - 0.5) which yields a biased distribution; replace it with an
unbiased Fisher-Yates implementation: make a shallow copy of the input (to avoid
mutating original), then perform an in-place Fisher-Yates shuffle by iterating
from the end to the start, swapping each element with a random earlier index
(use Math.floor(Math.random() * (i + 1))). Update the function
shuffleArray<T>(array: T[]): T[] to return the shuffled copy.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 67d6e753-8006-4820-a194-94b6f11574b1
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
CHANGELOG.mdjsr.jsonpackage.jsonsrc/__tests__/main.test.tssrc/main.ts
📜 Review details
🧰 Additional context used
🪛 GitHub Check: CodeQL
src/main.ts
[failure] 61-66: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings with many repetitions of '-'.
🪛 markdownlint-cli2 (0.22.0)
CHANGELOG.md
[warning] 7-7: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 19-19: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 26-26: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
🔇 Additional comments (21)
package.json (1)
3-3: LGTM!Version bump to 1.2.0 aligns with the changelog, and the Vitest integration is properly configured with both
runandwatchmodes.Also applies to: 23-24, 48-49
jsr.json (1)
6-6: LGTM!Version bump to 1.2.0 is consistent with
package.json.src/__tests__/main.test.ts (9)
9-13: LGTM!The
randomStringtest validates the output length correctly.
15-22: LGTM!Good test for verifying the non-mutation fix to
shuffleArray.
24-29: LGTM!Covers both basic slugification and edge cases with spaces and special characters.
31-38: LGTM!Tests both truncation and the pass-through case for short strings.
40-44: LGTM!Tests chunking including the remainder case.
46-53: LGTM!Good coverage of K/M/B suffixes and the pass-through case for small numbers.
55-59: LGTM!Basic capitalization test is adequate.
61-71: LGTM!Comprehensive coverage of empty value detection for various types.
73-80: LGTM!Correctly verifies that the clone is independent from the original.
src/main.ts (10)
5-5: LGTM!Good addition of a security warning clarifying that
randomStringis not suitable for cryptographic purposes.
52-57: LGTM!Good approach maintaining backward compatibility with the deprecated alias while fixing the casing inconsistency.
70-73: LGTM!Clean implementation with proper boundary check.
75-78: LGTM!Standard async sleep implementation.
81-88: LGTM!Good validation for chunk size with clear error message.
91-96: LGTM!Clean number formatting with appropriate suffixes and decimal handling.
99-105: LGTM!Standard debounce implementation. Note that it doesn't return the function's result, which is typical for debounce utilities focused on side effects.
108-110: LGTM!Simple and correct capitalization.
113-118: LGTM!Handles the common empty value cases appropriately.
59-67: The ReDoS vulnerability claim is unsubstantiated.The regex
[\s_-]+is a character class with a single quantifier. Character classes are atomic—they don't backtrack internally. ReDoS vulnerabilities require nested quantifiers (e.g.,(a+)+) or overlapping alternation (e.g.,(a|a)+), neither of which exist here. The pattern is used in a sequential.replace()context without anchoring that would force re-matching from multiple positions, making it linear time O(n). While CodeQL may conservatively flag patterns as precautionary, this specific pattern is not vulnerable to polynomial backtracking in this context.
- Remove unused imports from test file (fixes tsc build) - Use Fisher-Yates shuffle for uniform distribution - Add blank lines after CHANGELOG headings - Document deepClone limitations in JSDoc
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/__tests__/main.test.ts`:
- Around line 27-31: The test mutates arrays by calling sort() directly; update
the assertion to avoid in-place mutation by sorting copies instead (e.g., sort
cloned arrays) so neither original nor shuffled is mutated; locate the test
around the shuffleArray invocation in the spec (function name shuffleArray) and
replace expect(shuffled.sort()).toEqual(original.sort()) with an assertion that
compares sorted clones (or uses array-contains matchers) to ensure immutability
during the assertion.
In `@src/main.ts`:
- Around line 103-110: The debounce function should expose cancellation (and
optionally flush) capabilities; modify export function debounce<T>(fn: T, delay
= 300) to return a callable that also has methods cancel() to clear the pending
timeout and prevent the delayed call, and flush() to immediately invoke the
pending call if any and clear the timeout. Ensure the returned value is typed to
include these methods (e.g., a function with attached cancel/flush properties),
use the existing timeoutId variable to implement both cancel and flush, and
preserve the current behavior of the main debounced function.
🪄 Autofix (Beta)
✅ Autofix completed
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: be1104a1-a7d4-46e2-b88f-f61d14bebd47
📒 Files selected for processing (3)
CHANGELOG.mdsrc/__tests__/main.test.tssrc/main.ts
📜 Review details
🧰 Additional context used
🪛 GitHub Check: CodeQL
src/main.ts
[failure] 66-71: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings with many repetitions of '-'.
🔇 Additional comments (7)
CHANGELOG.md (1)
1-32: LGTM!The CHANGELOG follows the Keep a Changelog format well, documenting the new utilities, fixes, and version history appropriately. The blank line issue from the previous review has been addressed.
src/__tests__/main.test.ts (1)
1-12: Good test structure and coverage for the new utilities.The test suite covers the key behaviors of the newly added functions, including edge cases like invalid chunk sizes. The imports align with the tested functions.
src/main.ts (5)
27-37: LGTM!The Fisher–Yates shuffle is correctly implemented and the function now properly avoids mutating the original array. This addresses the previous review feedback.
125-128: LGTM!The JSDoc now properly documents the JSON-based cloning limitations (functions, undefined, Dates, circular refs). This addresses the previous review feedback.
57-62: Good deprecation pattern.The alias preserves backward compatibility while encouraging migration to the correctly-cased name.
85-93: LGTM!The chunk function correctly validates input and handles the edge case of arrays not evenly divisible by the chunk size.
64-72: No ReDoS concern with the slugify regex.The regex
/[\s_-]+/gat line 70 is safe from ReDoS—character classes with simple quantifiers do not exhibit catastrophic backtracking behavior. No input validation or documentation is needed for this reason.> Likely an incorrect or invalid review comment.
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Fixes Applied SuccessfullyFixed 2 file(s) based on 2 unresolved review comments. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 2 file(s) based on 2 unresolved review comments. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main.ts`:
- Around line 135-141: The isEmpty function currently treats Maps, Sets and
functions as empty because Object.keys() returns [] for them; update isEmpty to
explicitly handle these types: add checks in isEmpty for value instanceof Map
and value instanceof Set (use their .size to determine emptiness) and for typeof
value === 'function' (decide and document whether a function should be
considered empty—typically treat as not empty or return false), and adjust the
object branch to only treat plain objects (e.g., value !== null &&
value.constructor === Object) via Object.keys; also add a JSDoc comment on
isEmpty describing behavior for Map, Set, and functions so callers know the
edge-case decisions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5a8eee96-9ab3-4a04-9e6b-e212dc97ef22
📒 Files selected for processing (2)
src/__tests__/main.test.tssrc/main.ts
📜 Review details
🧰 Additional context used
🪛 GitHub Check: CodeQL
src/main.ts
[failure] 66-71: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings with many repetitions of '-'.
🔇 Additional comments (13)
src/__tests__/main.test.ts (2)
1-12: Missing test imports and coverage for several utilities.The test file imports 9 functions but the module exports additional utilities that lack test coverage:
randomNumber,binary,randomArrayItem,randomItemsArray,uniqueArrayItems,debounce, andsleep. These are imported but not tested, which was flagged previously.
14-93: LGTM!The test suite provides good coverage for the new utilities. The tests are well-structured with clear assertions:
shuffleArraycorrectly tests non-mutation using spread operatorschunktests both success and error casesisEmptycovers multiple edge cases (null, undefined, empty string, array, object)deepCloneproperly verifies isolation between original and clonesrc/main.ts (11)
3-11: LGTM!Good addition of the security warning. The JSDoc clearly communicates that
randomStringshould not be used for cryptographic purposes and suggestscrypto.randomUUID()as an alternative.
27-37: LGTM!The Fisher-Yates implementation is correct and provides uniform shuffle distribution. The function properly creates a copy to avoid mutating the original array.
57-62: LGTM!Good approach to the rename: the deprecated alias
uniqueArrayitemsmaintains backward compatibility while the correcteduniqueArrayItemsbecomes the canonical export.
74-78: LGTM!Clean implementation. The
trimEnd()before adding ellipsis is a nice touch to avoid awkward trailing spaces.
80-83: LGTM!Standard async sleep implementation using Promise and setTimeout.
85-93: LGTM!Correct chunking implementation with proper validation for the size parameter.
95-101: LGTM!Clean implementation with appropriate suffixes. The
.replace(/\.0$/, '')nicely handles whole number formatting (e.g.,2Minstead of2.0M).
103-128: LGTM!Well-implemented debounce with
cancel()andflush()methods. ThelastArgstracking enables proper flush behavior.
130-133: LGTM!Simple and correct implementation. Handles empty strings gracefully.
143-146: LGTM!The JSDoc now clearly documents the JSON-based cloning limitations (functions, undefined, Dates, circular references). Users can make informed decisions about when to use this utility.
64-72: The ReDoS concern is a false positive; no changes are required.The regex pattern
[\s_-]+is not vulnerable to catastrophic backtracking. ReDoS attacks require nested quantifiers or overlapping alternations to trigger exponential backtracking, but this pattern uses a simple character class with a single quantifier, which matches in O(n) linear time. The CodeQL warning can be safely dismissed.
| /** Check if value is empty (null, undefined, empty string, empty array, empty object) */ | ||
| export function isEmpty(value: unknown): boolean { | ||
| if (value == null) return true; | ||
| if (typeof value === 'string' || Array.isArray(value)) return value.length === 0; | ||
| if (typeof value === 'object') return Object.keys(value).length === 0; | ||
| return false; | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider documenting edge cases for Map, Set, and functions.
The current implementation returns true for new Map(), new Set(), and empty functions because Object.keys() returns an empty array for these. This may be unexpected behavior.
📝 Optional: Add JSDoc clarification
-/** Check if value is empty (null, undefined, empty string, empty array, empty object) */
+/** Check if value is empty (null, undefined, empty string, empty array, empty plain object)
+ * Note: Returns true for Map/Set/functions as they have no enumerable keys */
export function isEmpty(value: unknown): boolean {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main.ts` around lines 135 - 141, The isEmpty function currently treats
Maps, Sets and functions as empty because Object.keys() returns [] for them;
update isEmpty to explicitly handle these types: add checks in isEmpty for value
instanceof Map and value instanceof Set (use their .size to determine emptiness)
and for typeof value === 'function' (decide and document whether a function
should be considered empty—typically treat as not empty or return false), and
adjust the object branch to only treat plain objects (e.g., value !== null &&
value.constructor === Object) via Object.keys; also add a JSDoc comment on
isEmpty describing behavior for Map, Set, and functions so callers know the
edge-case decisions.
- Add tests for all 16 functions (25 tests total) - isEmpty now handles Map and Set - debounce cancel and flush already existed, added tests - Remove unused vi import
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/main.ts (1)
64-72:⚠️ Potential issue | 🟡 MinorAddress CodeQL warning: potential ReDoS on uncontrolled input.
Static analysis flags the regex chain as potentially slow with pathological inputs (many repetitions of
-). While the risk is mitigated because line 70 collapses consecutive hyphens before line 71 processes them, this function accepts uncontrolled library input.Consider adding an input length guard or simplifying the regex chain to eliminate the concern entirely.
🛡️ Option 1: Add length guard
/** Slugify a string for URLs */ export function slugify(text: string): string { + if (text.length > 1000) { + text = text.slice(0, 1000); + } return text .toLowerCase() .trim()🛡️ Option 2: Combine regex operations
export function slugify(text: string): string { return text .toLowerCase() .trim() - .replace(/[^\w\s-]/g, '') - .replace(/[\s_-]+/g, '-') - .replace(/^-+|-+$/g, ''); + .replace(/[^\w\s-]/g, '') + .replace(/[\s_-]+/g, '-') + .replace(/^-|-$/g, ''); }Note: Replacing
-+with-works because consecutive hyphens are already collapsed by the previous step.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main.ts` around lines 64 - 72, The slugify function is flagged for potential ReDoS due to chained regexes on uncontrolled input; add a defensive input-length guard at the start of slugify (e.g., if text.length > 2000 then truncate to a safe max or return early) and then run the existing transforms, or alternatively simplify the regex chain by combining the consecutive collapse steps into a single safe replace (use one .replace(/[\s_-]+/g, '-') before trimming with .replace(/^-+|-+$/g, '')). Update function slugify to include this length check or the combined regex to eliminate the ReDoS risk.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/__tests__/main.test.ts`:
- Around line 136-155: Add a test that verifies debounce(...).flush()
immediately invokes a pending call: create a local counter, call const fn =
debounce(() => { count++; }, 50); call fn() to schedule it, assert count is
still 0, call fn.flush(), then assert count is 1 (and optionally await
sleep(100) to ensure no double-invocation); also include a test that calling
flush after cancel does not run the function by using fn.cancel() followed by
fn.flush() and asserting count remains 0. Ensure you reference the debounce
function and its methods flush() and cancel() and reuse sleep() helper and the
count variable used in existing tests.
In `@src/main.ts`:
- Around line 95-101: The formatNumber function treats negatives as plain
numbers because its thresholds use num >= ..., so update formatNumber to compare
using the absolute value (e.g., const abs = Math.abs(num)) and determine the
sign (e.g., const sign = num < 0 ? '-' : ''), then format abs with the K/M/B
logic and return sign + formattedAbs (preserving the original zero/decimal
trimming behavior); locate the logic in the formatNumber function to implement
this change.
---
Duplicate comments:
In `@src/main.ts`:
- Around line 64-72: The slugify function is flagged for potential ReDoS due to
chained regexes on uncontrolled input; add a defensive input-length guard at the
start of slugify (e.g., if text.length > 2000 then truncate to a safe max or
return early) and then run the existing transforms, or alternatively simplify
the regex chain by combining the consecutive collapse steps into a single safe
replace (use one .replace(/[\s_-]+/g, '-') before trimming with
.replace(/^-+|-+$/g, '')). Update function slugify to include this length check
or the combined regex to eliminate the ReDoS risk.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: a47333ec-c788-4bdf-81b4-b2b5a82924c6
📒 Files selected for processing (2)
src/__tests__/main.test.tssrc/main.ts
📜 Review details
🧰 Additional context used
🪛 GitHub Check: CodeQL
src/main.ts
[failure] 66-71: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings with many repetitions of '-'.
🔇 Additional comments (11)
src/__tests__/main.test.ts (3)
1-19: LGTM!Imports are clean and comprehensive, covering all 16 exported utility functions from
main.ts.
50-62: LGTM!The mutation concern from the previous review has been properly addressed using spread operators in the assertion.
163-179: LGTM!Comprehensive
isEmptytests covering primitives, collections, and the newly addedMap/Setsupport.src/main.ts (8)
5-5: LGTM!Good addition of the security warning in the JSDoc. This helps users understand when to use
crypto.randomUUID()instead.
27-37: LGTM!Correctly implements Fisher-Yates shuffle, ensuring uniform distribution and non-mutating behavior as documented.
74-78: LGTM!Clean implementation with
trimEnd()ensuring no trailing whitespace before the ellipsis.
85-93: LGTM!Good input validation with a descriptive error message. The loop-based implementation is clear and efficient.
103-128: LGTM!Well-implemented debounce with
cancel()andflush()methods. ThelastArgstracking ensuresflush()can invoke the function with the most recent arguments.
135-142: LGTM!Comprehensive implementation covering all documented types including
MapandSet. The JSDoc accurately reflects the supported types.
144-147: LGTM!The JSDoc clearly documents the JSON-based limitations. This is appropriate for a simple utility library.
57-62: LGTM!Good backward compatibility approach with a clear
@deprecatedJSDoc tag for the old name.
| describe('debounce', () => { | ||
| it('delays function execution', async () => { | ||
| let count = 0; | ||
| const fn = debounce(() => { count++; }, 50); | ||
| fn(); | ||
| fn(); | ||
| fn(); | ||
| expect(count).toBe(0); | ||
| await sleep(100); | ||
| expect(count).toBe(1); | ||
| }); | ||
| it('cancel prevents execution', async () => { | ||
| let count = 0; | ||
| const fn = debounce(() => { count++; }, 50); | ||
| fn(); | ||
| fn.cancel(); | ||
| await sleep(100); | ||
| expect(count).toBe(0); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Missing test coverage for debounce.flush() method.
The debounce implementation in main.ts exposes both cancel() and flush() methods, but only cancel() is tested here. Consider adding a test case for flush() to ensure it immediately invokes the pending function.
🧪 Proposed test for flush()
it('cancel prevents execution', async () => {
let count = 0;
const fn = debounce(() => { count++; }, 50);
fn();
fn.cancel();
await sleep(100);
expect(count).toBe(0);
});
+ it('flush immediately invokes pending call', () => {
+ let count = 0;
+ const fn = debounce(() => { count++; }, 50);
+ fn();
+ expect(count).toBe(0);
+ fn.flush();
+ expect(count).toBe(1);
+ });
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| describe('debounce', () => { | |
| it('delays function execution', async () => { | |
| let count = 0; | |
| const fn = debounce(() => { count++; }, 50); | |
| fn(); | |
| fn(); | |
| fn(); | |
| expect(count).toBe(0); | |
| await sleep(100); | |
| expect(count).toBe(1); | |
| }); | |
| it('cancel prevents execution', async () => { | |
| let count = 0; | |
| const fn = debounce(() => { count++; }, 50); | |
| fn(); | |
| fn.cancel(); | |
| await sleep(100); | |
| expect(count).toBe(0); | |
| }); | |
| }); | |
| describe('debounce', () => { | |
| it('delays function execution', async () => { | |
| let count = 0; | |
| const fn = debounce(() => { count++; }, 50); | |
| fn(); | |
| fn(); | |
| fn(); | |
| expect(count).toBe(0); | |
| await sleep(100); | |
| expect(count).toBe(1); | |
| }); | |
| it('cancel prevents execution', async () => { | |
| let count = 0; | |
| const fn = debounce(() => { count++; }, 50); | |
| fn(); | |
| fn.cancel(); | |
| await sleep(100); | |
| expect(count).toBe(0); | |
| }); | |
| it('flush immediately invokes pending call', () => { | |
| let count = 0; | |
| const fn = debounce(() => { count++; }, 50); | |
| fn(); | |
| expect(count).toBe(0); | |
| fn.flush(); | |
| expect(count).toBe(1); | |
| }); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/__tests__/main.test.ts` around lines 136 - 155, Add a test that verifies
debounce(...).flush() immediately invokes a pending call: create a local
counter, call const fn = debounce(() => { count++; }, 50); call fn() to schedule
it, assert count is still 0, call fn.flush(), then assert count is 1 (and
optionally await sleep(100) to ensure no double-invocation); also include a test
that calling flush after cancel does not run the function by using fn.cancel()
followed by fn.flush() and asserting count remains 0. Ensure you reference the
debounce function and its methods flush() and cancel() and reuse sleep() helper
and the count variable used in existing tests.
| /** Format number with K/M/B suffixes */ | ||
| export function formatNumber(num: number): string { | ||
| if (num >= 1_000_000_000) return (num / 1_000_000_000).toFixed(1).replace(/\.0$/, '') + 'B'; | ||
| if (num >= 1_000_000) return (num / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M'; | ||
| if (num >= 1_000) return (num / 1_000).toFixed(1).replace(/\.0$/, '') + 'K'; | ||
| return num.toString(); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Negative numbers don't receive K/M/B suffixes.
The conditions check num >= 1_000 etc., so negative numbers like -1500 return "-1500" instead of "-1.5K". If this is intentional, consider documenting the behavior; otherwise, use Math.abs(num) for comparisons.
♻️ Optional fix to handle negative numbers
/** Format number with K/M/B suffixes */
export function formatNumber(num: number): string {
- if (num >= 1_000_000_000) return (num / 1_000_000_000).toFixed(1).replace(/\.0$/, '') + 'B';
- if (num >= 1_000_000) return (num / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M';
- if (num >= 1_000) return (num / 1_000).toFixed(1).replace(/\.0$/, '') + 'K';
+ const abs = Math.abs(num);
+ if (abs >= 1_000_000_000) return (num / 1_000_000_000).toFixed(1).replace(/\.0$/, '') + 'B';
+ if (abs >= 1_000_000) return (num / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M';
+ if (abs >= 1_000) return (num / 1_000).toFixed(1).replace(/\.0$/, '') + 'K';
return num.toString();
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** Format number with K/M/B suffixes */ | |
| export function formatNumber(num: number): string { | |
| if (num >= 1_000_000_000) return (num / 1_000_000_000).toFixed(1).replace(/\.0$/, '') + 'B'; | |
| if (num >= 1_000_000) return (num / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M'; | |
| if (num >= 1_000) return (num / 1_000).toFixed(1).replace(/\.0$/, '') + 'K'; | |
| return num.toString(); | |
| } | |
| /** Format number with K/M/B suffixes */ | |
| export function formatNumber(num: number): string { | |
| const abs = Math.abs(num); | |
| if (abs >= 1_000_000_000) return (num / 1_000_000_000).toFixed(1).replace(/\.0$/, '') + 'B'; | |
| if (abs >= 1_000_000) return (num / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M'; | |
| if (abs >= 1_000) return (num / 1_000).toFixed(1).replace(/\.0$/, '') + 'K'; | |
| return num.toString(); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main.ts` around lines 95 - 101, The formatNumber function treats
negatives as plain numbers because its thresholds use num >= ..., so update
formatNumber to compare using the absolute value (e.g., const abs =
Math.abs(num)) and determine the sign (e.g., const sign = num < 0 ? '-' : ''),
then format abs with the K/M/B logic and return sign + formattedAbs (preserving
the original zero/decimal trimming behavior); locate the logic in the
formatNumber function to implement this change.
Changes
New Functions (9)
slugify(text)— URL-safe slug generationtruncate(str, length)— String truncation with ellipsissleep(ms)— Async delay helperchunk(array, size)— Array chunkingformatNumber(num)— Number formatting (1.5K, 2M, 3.5B)debounce(fn, delay)— Function debouncingcapitalize(str)— First letter capitalizationisEmpty(value)— Empty value detectiondeepClone(obj)— Deep object cloningFixes
shuffleArray()no longer mutates the original arrayuniqueArrayitems→uniqueArrayItems(old name kept as deprecated alias)randomString()Added