core: handle invalid input in formatDate without leaking 'Invalid Date'#9848
Open
calebcgates wants to merge 1 commit into
Open
core: handle invalid input in formatDate without leaking 'Invalid Date'#9848calebcgates wants to merge 1 commit into
calebcgates wants to merge 1 commit into
Conversation
Signed-off-by: Caleb Gates <calebcgates@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
packages/core/src/utils/date.ts:formatDate(date, options)declares its signature as:The signature explicitly accepts
nullandundefined, but the body doesn't honor that contract — it passes the argument straight intodayjs(date).format(...). The result depends on which "invalid" value the caller passes:dayjs(null).format(...)→ literal string"Invalid Date"dayjs(undefined).format(...)→ today's date (becausedayjs(undefined) === dayjs(), which returns "now")dayjs("").format(...)→"Invalid Date"dayjs("not-a-date").format(...)→"Invalid Date"So today, calling
formatDate(null)returns"Invalid Date", andformatDate(undefined)silently returns a fresh timestamp for today — neither of which matches the implicit contract suggested by accepting those types in the signature.Most callers in the repo are defensively guarded already (
note.expiryDate?.value && formatDate(...),apiKey.lastUsedAt ? formatDate(...) : "Never used", etc.), and the upstream TypeScript types claim most date fields are non-nullablenumber. So this isn't a user-reported bug — it's a contract-honesty fix. The function says it acceptsnull | undefined; this PR makes it actually do something sensible when it gets them.Solution
Two guards at the top of
formatDate:null/undefinedshort-circuit returning"". Needed becausedayjs(undefined)is the no-arg constructor, which returns the current time and reports.isValid() === true— so a single.isValid()check is not enough to coverundefined.dayjs(date).isValid()check returning""for unparseable strings, empty strings, andNaN.The fix mirrors the
.isValid()pattern already used in this package atpackages/core/src/utils/query-transformer.ts:116(return date?.isValid() ? date.toDate().getTime() : null;).The
dayjs(date)construction is hoisted to aconst dand reused across all six switch branches — small side-effect win, also keeps the diff visually localised.Empty string
""is chosen as the sentinel because every existing caller consumes the return value directly into a template literal or a Reacttextprop, both of which render""invisibly. Returningnullwould change the type fromstringtostring | nulland break ~12 call sites in 4 files.No signature change. No new imports. No new dependencies. Valid inputs produce byte-identical output.
Type of Change
Visuals
Testing
If tests were not added, explain why
Tests were added at
packages/core/src/utils/__tests__/date.test.tscovering:Dateinstance → date formatnullinput →""undefinedinput →""(regression guard for thedayjs(undefined) === dayjs()idiosyncrasy)""options.type(date,time,timezone)"Invalid"Run with
npm run test:core(ornpx vitest run src/utils/__tests__/date.test.tsfrom insidepackages/core). All 8 new tests pass; fullpackages/core/src/utils/__tests__/suite passes 99/99 (no regression to fuzzy, query-transformer, content-block, internal-link, set, html-diff, title-format, virtualized-grouping).Platform
(
@notesnook/coreships in all three apps; this fix takes effect everywhereformatDateis called.)Sign-off