Conversation
Expose the same JSX-friendly ReactDayPicker API on Melange and native so shared code can render on both targets without separate module names or prop shapes.
Pin server-reason-react to the git source and update the native date construction/docs so this package still builds against that runtime API.
📝 WalkthroughWalkthroughThis pull request refactors the day-picker library to support both JavaScript and native platforms via conditional compilation. It introduces a platform-aware component that delegates to platform-specific implementations, adds a complete native day-picker renderer, updates build configuration to use Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant RDP as ReactDayPicker<br/>(Wrapper)
participant PlatformCheck as Platform Detection
participant ClientImpl as ClientImpl<br/>(JS Binding)
participant ServerImpl as ServerImpl<br/>(Native)
participant JSLib as react-day-picker<br/>(JS Library)
participant NativeRenderer as ReactDayPickerNative<br/>(Native Impl)
App->>RDP: Render with typed props<br/>(selected, onSelect, etc.)
RDP->>PlatformCheck: switch%platform (Runtime.platform)
alt JS Platform
PlatformCheck->>ClientImpl: Delegate to JS path
ClientImpl->>ClientImpl: Convert variants to<br/>Obj.magic raw values
ClientImpl->>ClientImpl: Map selected/onSelect<br/>via toJsRangeDate
ClientImpl->>JSLib: React.createElement<br/>with converted props
JSLib-->>ClientImpl: Returns JS element
ClientImpl-->>RDP: Returns element
else Native Platform
PlatformCheck->>ServerImpl: Delegate to native path
ServerImpl->>ServerImpl: Convert variants to<br/>ReactDayPickerNative types
ServerImpl->>ServerImpl: Map dates via<br/>toNativeRangeDate
ServerImpl->>NativeRenderer: Render with<br/>converted props
NativeRenderer->>NativeRenderer: Compute month grids,<br/>day cells, ARIA attrs
NativeRenderer-->>ServerImpl: Returns React element
ServerImpl-->>RDP: Returns element
end
RDP-->>App: Rendered component
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (12)
reason-react-day-picker.opam.template (1)
1-3: Consider pinning to a specific commit or tag for reproducibility.Pinning
server-reason-react.devto the repository HEAD without a specific commit hash or tag means builds may produce different results over time as the upstream repo changes. If this is intentional during active development, consider documenting that this should be pinned to a release tag before publishing a stable version.♻️ Example with commit pinning
pin-depends: [ - [ "server-reason-react.dev" "git+https://github.com/ml-in-barcelona/server-reason-react.git" ] + [ "server-reason-react.dev" "git+https://github.com/ml-in-barcelona/server-reason-react.git#<commit-sha>" ] ]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@reason-react-day-picker.opam.template` around lines 1 - 3, The pin-depends entry currently references "server-reason-react.dev" at repository HEAD; change the pin-depends value to reference a specific commit hash or release tag (e.g., replace the git+https URL with git+https://...#<commit-hash-or-tag>) to ensure reproducible builds, and if leaving it unpinned during active development is intentional, add a short comment in the template noting it must be pinned to a release tag before publishing; update the pin-depends array and the "server-reason-react.dev" entry accordingly.ReactDayPickerNative.re (1)
332-337: Week number calculation may differ from ISO 8601.The
getWeekNumberimplementation uses a simplified algorithm based on the first day of the year. ISO 8601 week numbering has specific rules (week 1 contains the first Thursday). If strict ISO compliance is needed, this may require adjustment. For most calendar UIs, this approximation is acceptable.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ReactDayPickerNative.re` around lines 332 - 337, The getWeekNumber function currently computes weeks by dividing days since year start using dateYear, newDate, dayOfWeek and getDayOfYear, which does not follow ISO 8601 (week 1 contains the year's first Thursday); to fix, replace or augment getWeekNumber to implement ISO rules: determine the Thursday-based week anchor (adjust the date by (4 - dayOfWeek) days), compute the year of that anchor, then compute week number as 1 + floor((dayOfYear(anchor) - 1) / 7); update getWeekNumber to use this algorithm (keeping helpers dateYear, newDate, dayOfWeek, getDayOfYear) so week numbers match ISO 8601 when required.ReactDayPicker.re (1)
93-106:Obj.magicusage is appropriate for JS interop but inherently unsafe.The use of
Obj.magicto convert polymorphic variants to the raw values expected by react-day-picker is a common pattern in Melange FFI. However, this bypasses type checking:
- If react-day-picker's API changes, these conversions will silently produce incorrect values
- Consider adding inline comments documenting the expected JS shapes
This is acceptable for library bindings where the alternative would be much more verbose.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ReactDayPicker.re` around lines 93 - 106, The Obj.magic conversions in toJsSelected and toJsOnSelect (and the use of toJsRangeDate/fromJsRangeDate) are unsafe for JS interop; add concise inline comments above toJsSelected and toJsOnSelect documenting the exact JS shapes and callback signatures expected by react-day-picker for `Single`, `Multiple`, and `Range` (e.g., Single -> Date, Multiple -> Array<Date>, Range -> { from?: Date, to?: Date }, and the Range callback receives that shape), and note that Obj.magic is used intentionally for brevity so future API changes are easier to spot; keep the comments next to the function definitions for quick discovery.example/shared/ExampleDayPickers.re (1)
3-12: UnusedmakeDatehelper function.This helper function is defined but never called in this file. The date construction on lines 14-24 uses inline
Js.Date.makecalls instead.🧹 Either remove or use the helper
Option 1 - Remove unused code:
-let makeDate = (~year: int, ~month: int, ~day: int): Js.Date.t => - Js.Date.make( - ~year=float_of_int(year), - ~month=float_of_int(month), - ~date=float_of_int(day), - ~hours=12.0, - ~minutes=0.0, - ~seconds=0.0, - (), - ); -Option 2 - Use the helper for
closeDate:-let closeDate = Js.Date.make( - ~year=Js.Date.getFullYear(today), - ~month=Js.Date.getMonth(today), - ~date=Js.Date.getDate(today) +. 4.0, - ~hours=12.0, - ~minutes=0.0, - ~seconds=0.0, - (), -); +let closeDate = makeDate( + ~year=int_of_float(Js.Date.getFullYear(today)), + ~month=int_of_float(Js.Date.getMonth(today)), + ~day=int_of_float(Js.Date.getDate(today)) + 4, +);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/shared/ExampleDayPickers.re` around lines 3 - 12, The function makeDate is defined but unused; either remove it or replace the inline Js.Date.make call used for closeDate with the helper. Locate makeDate and the closeDate construction in ExampleDayPickers.re, then either delete the makeDate declaration or refactor closeDate to call makeDate(~year, ~month, ~day) (keep the existing hours/minutes/seconds behavior by ensuring makeDate produces noon) so there’s no unused helper left behind.example/fuzz/FuzzRenderer.re (2)
54-68: Partial range handling differs from RangeRenderer.re.This logic returns
Js.Undefined.fromOption(None)when onlyfromis present (withoutto), or when onlytowould be present (not handled). In contrast,RangeRenderer.re(lines 12-24) constructs a valid range object with one bound set and the other undefined.If partial range selection should be testable via fuzz, consider aligning the logic:
♻️ Handle partial ranges consistently
| "range" => let range = switch (config.rangeFrom) { | Some(from) => switch (config.rangeTo) { | Some(to_) => Js.Undefined.return({ ReactDayPicker.from: Js.Undefined.return(from), ReactDayPicker.to_: Js.Undefined.return(to_), - }); - | None => Js.Undefined.fromOption(None) + }) + | None => + Js.Undefined.return({ + ReactDayPicker.from: Js.Undefined.return(from), + ReactDayPicker.to_: Js.Undefined.fromOption(None), + }) }; - | None => Js.Undefined.fromOption(None) + | None => + switch (config.rangeTo) { + | Some(to_) => + Js.Undefined.return({ + ReactDayPicker.from: Js.Undefined.fromOption(None), + ReactDayPicker.to_: Js.Undefined.return(to_), + }) + | None => Js.Undefined.fromOption(None) + } }; `Range(range);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/fuzz/FuzzRenderer.re` around lines 54 - 68, The "range" branch in FuzzRenderer.re currently returns Js.Undefined.fromOption(None) when only one bound is present, which prevents creating partial ranges; update the logic to mirror RangeRenderer.re by constructing a range object even when only from or only to is present: when config.rangeFrom is Some(from) and config.rangeTo is None, return a Range where ReactDayPicker.from is Js.Undefined.return(from) and ReactDayPicker.to_ is Js.Undefined.fromOption(None); likewise when rangeTo is Some(to_) and rangeFrom is None construct a Range with ReactDayPicker.to_ set and ReactDayPicker.from as Js.Undefined.fromOption(None); keep the existing full-range case unchanged so partial selections are testable by the fuzzer.
19-31: Redundant identity transformations can be simplified.The switch statements for
captionLayoutandnavLayoutare identity transformations that map each variant to itself. Sinceconfig.captionLayoutis already of typeoption(Scenario.captionLayout), this can be simplified.♻️ Suggested simplification
- let captionLayout = switch (config.captionLayout) { - | Some(`Label) => Some(`Label) - | Some(`Dropdown) => Some(`Dropdown) - | Some(`DropdownMonths) => Some(`DropdownMonths) - | Some(`DropdownYears) => Some(`DropdownYears) - | None => None - }; - let navLayout = switch (config.navLayout) { - | Some(`Around) => Some(`Around) - | Some(`After) => Some(`After) - | None => None - }; + let captionLayout = config.captionLayout; + let navLayout = config.navLayout;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/fuzz/FuzzRenderer.re` around lines 19 - 31, The switch blocks in renderFuzzConfig (for captionLayout and navLayout) are identity mappings; replace the switch logic by directly using the existing option values: assign captionLayout = config.captionLayout and navLayout = config.navLayout (i.e., remove the redundant switch over config.captionLayout and config.navLayout and use the fields as-is) so the function is simpler and equivalent.example/shared/RangeScenario.re (3)
8-17: Consider extractingmakeDateto a shared utility module.This helper is duplicated verbatim in
FuzzTestRunner.re(lines 25-34). Extracting it to a shared module (e.g.,DateUtils.re) would improve maintainability and reduce duplication.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/shared/RangeScenario.re` around lines 8 - 17, The helper function makeDate is duplicated and should be extracted into a shared utility module; create a new module (e.g., DateUtils.re) that exports makeDate with the same signature (let makeDate = (~year:int, ~month:int, ~day:int): Js.Date.t => ...), replace the inline implementations in RangeScenario.re and FuzzTestRunner.re with imports/uses of DateUtils.makeDate, and update any module references or build entries so both modules use the single shared implementation.
19-21: Unused variablenextWeek.The
nextWeekconstant is defined but never used in this module. Consider removing it to avoid dead code, or use it in the scenario definitions if there's a "range-week-long" scenario planned.🧹 Proposed removal
let today = makeDate(~year=2026, ~month=2, ~day=21); let tomorrow = makeDate(~year=2026, ~month=2, ~day=22); -let nextWeek = makeDate(~year=2026, ~month=2, ~day=28);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/shared/RangeScenario.re` around lines 19 - 21, The constant `nextWeek` is declared via `makeDate(~year=2026, ~month=2, ~day=28)` but never used; either remove the `nextWeek` declaration to eliminate dead code or integrate `nextWeek` into your scenario definitions (e.g., a week-long range scenario) where `today` and `tomorrow` are used; update any scenario functions that should reference a week range to use `nextWeek` (or delete the `nextWeek` binding if no such scenario is needed).
30-40: Fallback case inbyNamesilently uses default values.The wildcard pattern at line 37 returns
(Some(today), Some(today))for unrecognized names without warning. Sincecurrent()already validates againstall, this is fine for internal use, but the function is public. Consider documenting this behavior or making the fallback explicit.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/shared/RangeScenario.re` around lines 30 - 40, The public function byName currently silently maps unknown names to (Some(today), Some(tomorrow)) via the wildcard branch; update byName to make this behavior explicit by either (A) replacing the wildcard branch with an explicit failure (e.g., raise/invalid argument including the unknown name) so callers get immediate feedback, or (B) keep the fallback but add a clear docstring/comment on byName describing that unknown names will map to (Some(today), Some(tomorrow)) and that current()/all validation is expected elsewhere; reference the byName function and the today/tomorrow identifiers when making the change.example/fuzz/FuzzTestRunner.re (1)
25-34: DuplicatemakeDatehelper.This function is identical to
RangeScenario.makeDate. Consider extracting to a shared utility module to avoid duplication.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/fuzz/FuzzTestRunner.re` around lines 25 - 34, The makeDate implementation in FuzzTestRunner.re duplicates RangeScenario.makeDate; extract the shared implementation into a common utility (e.g., DateHelpers.makeDate) and replace the local makeDate with an import/use of that shared function; update FuzzTestRunner.re to call DateHelpers.makeDate instead of its own makeDate and remove the duplicate definition, and update any other modules using the duplicated function to reference the single shared symbol (e.g., DateHelpers.makeDate) so only one implementation remains.example/shared/Scenario.re (1)
84-97: Consider extracting the CLI argument parsing pattern.This
current()function follows the same pattern asRangeScenario.current(): read last CLI arg, validate against an allow-list, fallback to default. Consider extracting a shared helper like:let currentScenarioName = (~all, ~default) => ...This would reduce duplication and ensure consistent CLI handling.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/shared/Scenario.re` around lines 84 - 97, The current() function duplicates the CLI-arg parsing found in RangeScenario.current(); extract that logic into a shared helper (e.g., currentScenarioName with signature like (~all, ~default) => string) then have current() and RangeScenario.current() call this helper and pass their allow-list and default; locate and replace the duplicated conditional that reads Sys.argv, picks the last arg, validates with Array.exists against all, and returns either the candidate or "default", and ensure you continue to pass the resulting name into byName(name) in current() and the equivalent call in RangeScenario.current().example/fuzz/FuzzGenerator.re (1)
133-148: Date rollover may produce unexpected month boundary crossings.When
fromDayis late in the month (e.g., day 28), adding up to 14 days (toDay = fromDay +. 14.0= 42) will causeJs.Dateto roll over into the next month. This may be acceptable for fuzz testing, but could produce ranges that span months unexpectedly.If you want to constrain
rangeToto the same month, clamptoDayto 28 (or calculate based on actual month length).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/fuzz/FuzzGenerator.re` around lines 133 - 148, The current rangeTo calculation (involving rangeTo, rangeFrom, fromDay, toDay, randomInt, Js.Date.make) can roll into the next month; to fix, compute the last day of the month for Js.Date.getMonth(from)/Js.Date.getFullYear(from) (e.g., by constructing the first day of the next month and subtracting one day or using the standard JS date trick) and clamp toDay to Math.min(toDay, lastDayOfMonth) before calling Js.Date.make so the generated range stays within the same month (alternatively, clamp to 28 if you intentionally want a fixed safe cap).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@example/fuzz/FuzzGenerator.re`:
- Around line 174-181: generateConfig currently uses Random.int(3) before
seeding the PRNG, making mode selection non-deterministic; seed the PRNG by
calling Random.init(seed) at the start of generateConfig (before Random.int(3))
so the selection is derived from the provided seed, and ensure the downstream
generators (generateSingleConfig, generateMultipleConfig, generateRangeConfig)
either rely on this seeded state or do not re-init the RNG in a conflicting way.
In `@example/fuzz/FuzzTestRunner.re`:
- Around line 19-23: The testFuzzConfig helper uses a tautological assertion
(Alcotest.check(Alcotest.bool) ... true, true) which never validates the
runNativeTest result; change testFuzzConfig to capture the value returned by
runNativeTest and assert on its contents instead (for example, call let output =
runNativeTest(config) and then use Alcotest.check(Alcotest.string) or
Alcotest.(check (list string)) to verify expected HTML substrings, DOM markers,
or compare against a stored snapshot); update references in testFuzzConfig and
any callers so assertions verify meaningful properties of output rather than
always-true literals.
In `@example/README.md`:
- Line 13: Update the skipped heading levels by changing the "### Run the native
renderer" heading to an h2 (## Run the native renderer) and likewise convert the
other top-level section headings currently using "###" (the headings at the
other section titles) to "##" so the document flows from the existing h1 to h2
before any h3s; ensure subsequent subheadings that are intended to be nested
remain at h3.
---
Nitpick comments:
In `@example/fuzz/FuzzGenerator.re`:
- Around line 133-148: The current rangeTo calculation (involving rangeTo,
rangeFrom, fromDay, toDay, randomInt, Js.Date.make) can roll into the next
month; to fix, compute the last day of the month for
Js.Date.getMonth(from)/Js.Date.getFullYear(from) (e.g., by constructing the
first day of the next month and subtracting one day or using the standard JS
date trick) and clamp toDay to Math.min(toDay, lastDayOfMonth) before calling
Js.Date.make so the generated range stays within the same month (alternatively,
clamp to 28 if you intentionally want a fixed safe cap).
In `@example/fuzz/FuzzRenderer.re`:
- Around line 54-68: The "range" branch in FuzzRenderer.re currently returns
Js.Undefined.fromOption(None) when only one bound is present, which prevents
creating partial ranges; update the logic to mirror RangeRenderer.re by
constructing a range object even when only from or only to is present: when
config.rangeFrom is Some(from) and config.rangeTo is None, return a Range where
ReactDayPicker.from is Js.Undefined.return(from) and ReactDayPicker.to_ is
Js.Undefined.fromOption(None); likewise when rangeTo is Some(to_) and rangeFrom
is None construct a Range with ReactDayPicker.to_ set and ReactDayPicker.from as
Js.Undefined.fromOption(None); keep the existing full-range case unchanged so
partial selections are testable by the fuzzer.
- Around line 19-31: The switch blocks in renderFuzzConfig (for captionLayout
and navLayout) are identity mappings; replace the switch logic by directly using
the existing option values: assign captionLayout = config.captionLayout and
navLayout = config.navLayout (i.e., remove the redundant switch over
config.captionLayout and config.navLayout and use the fields as-is) so the
function is simpler and equivalent.
In `@example/fuzz/FuzzTestRunner.re`:
- Around line 25-34: The makeDate implementation in FuzzTestRunner.re duplicates
RangeScenario.makeDate; extract the shared implementation into a common utility
(e.g., DateHelpers.makeDate) and replace the local makeDate with an import/use
of that shared function; update FuzzTestRunner.re to call DateHelpers.makeDate
instead of its own makeDate and remove the duplicate definition, and update any
other modules using the duplicated function to reference the single shared
symbol (e.g., DateHelpers.makeDate) so only one implementation remains.
In `@example/shared/ExampleDayPickers.re`:
- Around line 3-12: The function makeDate is defined but unused; either remove
it or replace the inline Js.Date.make call used for closeDate with the helper.
Locate makeDate and the closeDate construction in ExampleDayPickers.re, then
either delete the makeDate declaration or refactor closeDate to call
makeDate(~year, ~month, ~day) (keep the existing hours/minutes/seconds behavior
by ensuring makeDate produces noon) so there’s no unused helper left behind.
In `@example/shared/RangeScenario.re`:
- Around line 8-17: The helper function makeDate is duplicated and should be
extracted into a shared utility module; create a new module (e.g., DateUtils.re)
that exports makeDate with the same signature (let makeDate = (~year:int,
~month:int, ~day:int): Js.Date.t => ...), replace the inline implementations in
RangeScenario.re and FuzzTestRunner.re with imports/uses of DateUtils.makeDate,
and update any module references or build entries so both modules use the single
shared implementation.
- Around line 19-21: The constant `nextWeek` is declared via
`makeDate(~year=2026, ~month=2, ~day=28)` but never used; either remove the
`nextWeek` declaration to eliminate dead code or integrate `nextWeek` into your
scenario definitions (e.g., a week-long range scenario) where `today` and
`tomorrow` are used; update any scenario functions that should reference a week
range to use `nextWeek` (or delete the `nextWeek` binding if no such scenario is
needed).
- Around line 30-40: The public function byName currently silently maps unknown
names to (Some(today), Some(tomorrow)) via the wildcard branch; update byName to
make this behavior explicit by either (A) replacing the wildcard branch with an
explicit failure (e.g., raise/invalid argument including the unknown name) so
callers get immediate feedback, or (B) keep the fallback but add a clear
docstring/comment on byName describing that unknown names will map to
(Some(today), Some(tomorrow)) and that current()/all validation is expected
elsewhere; reference the byName function and the today/tomorrow identifiers when
making the change.
In `@example/shared/Scenario.re`:
- Around line 84-97: The current() function duplicates the CLI-arg parsing found
in RangeScenario.current(); extract that logic into a shared helper (e.g.,
currentScenarioName with signature like (~all, ~default) => string) then have
current() and RangeScenario.current() call this helper and pass their allow-list
and default; locate and replace the duplicated conditional that reads Sys.argv,
picks the last arg, validates with Array.exists against all, and returns either
the candidate or "default", and ensure you continue to pass the resulting name
into byName(name) in current() and the equivalent call in
RangeScenario.current().
In `@ReactDayPicker.re`:
- Around line 93-106: The Obj.magic conversions in toJsSelected and toJsOnSelect
(and the use of toJsRangeDate/fromJsRangeDate) are unsafe for JS interop; add
concise inline comments above toJsSelected and toJsOnSelect documenting the
exact JS shapes and callback signatures expected by react-day-picker for
`Single`, `Multiple`, and `Range` (e.g., Single -> Date, Multiple ->
Array<Date>, Range -> { from?: Date, to?: Date }, and the Range callback
receives that shape), and note that Obj.magic is used intentionally for brevity
so future API changes are easier to spot; keep the comments next to the function
definitions for quick discovery.
In `@ReactDayPickerNative.re`:
- Around line 332-337: The getWeekNumber function currently computes weeks by
dividing days since year start using dateYear, newDate, dayOfWeek and
getDayOfYear, which does not follow ISO 8601 (week 1 contains the year's first
Thursday); to fix, replace or augment getWeekNumber to implement ISO rules:
determine the Thursday-based week anchor (adjust the date by (4 - dayOfWeek)
days), compute the year of that anchor, then compute week number as 1 +
floor((dayOfYear(anchor) - 1) / 7); update getWeekNumber to use this algorithm
(keeping helpers dateYear, newDate, dayOfWeek, getDayOfYear) so week numbers
match ISO 8601 when required.
In `@reason-react-day-picker.opam.template`:
- Around line 1-3: The pin-depends entry currently references
"server-reason-react.dev" at repository HEAD; change the pin-depends value to
reference a specific commit hash or release tag (e.g., replace the git+https URL
with git+https://...#<commit-hash-or-tag>) to ensure reproducible builds, and if
leaving it unpinned during active development is intentional, add a short
comment in the template noting it must be pinned to a release tag before
publishing; update the pin-depends array and the "server-reason-react.dev" entry
accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 164c80de-768f-4775-9bb3-3451de12778c
📒 Files selected for processing (28)
.gitignoreREADME.mdReactDayPicker.reReactDayPickerNative.redunedune-projectexample/README.mdexample/check-parity.shexample/check-range-parity.shexample/fuzz-test.shexample/fuzz/FuzzGenerator.reexample/fuzz/FuzzRenderer.reexample/fuzz/FuzzTestRunner.reexample/fuzz/duneexample/js/JsRenderer.reexample/js/RangeJsRenderer.reexample/js/duneexample/native/NativeRenderer.reexample/native/RangeNativeRenderer.reexample/native/duneexample/shared/ExampleDayPickers.reexample/shared/RangeRenderer.reexample/shared/RangeScenario.reexample/shared/Scenario.reexample/shared/SharedFixture.renative/dunereason-react-day-picker.opamreason-react-day-picker.opam.template
| let generateConfig = (~seed, ~baseYear, ~baseMonth): fuzzConfig => { | ||
| let modeType = Random.int(3); | ||
| switch (modeType) { | ||
| | 0 => generateSingleConfig(~seed, ~baseYear, ~baseMonth) | ||
| | 1 => generateMultipleConfig(~seed, ~baseYear, ~baseMonth) | ||
| | _ => generateRangeConfig(~seed, ~baseYear, ~baseMonth) | ||
| }; | ||
| }; |
There was a problem hiding this comment.
Bug: Mode selection uses uninitialized PRNG state.
generateConfig calls Random.int(3) before any Random.init(seed) call. The mode selection is therefore based on whatever previous PRNG state exists, not the provided seed. This makes the mode selection non-deterministic across runs.
🐛 Proposed fix
let generateConfig = (~seed, ~baseYear, ~baseMonth): fuzzConfig => {
+ Random.init(seed);
let modeType = Random.int(3);
switch (modeType) {
| 0 => generateSingleConfig(~seed, ~baseYear, ~baseMonth)
| 1 => generateMultipleConfig(~seed, ~baseYear, ~baseMonth)
| _ => generateRangeConfig(~seed, ~baseYear, ~baseMonth)
};
};📝 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.
| let generateConfig = (~seed, ~baseYear, ~baseMonth): fuzzConfig => { | |
| let modeType = Random.int(3); | |
| switch (modeType) { | |
| | 0 => generateSingleConfig(~seed, ~baseYear, ~baseMonth) | |
| | 1 => generateMultipleConfig(~seed, ~baseYear, ~baseMonth) | |
| | _ => generateRangeConfig(~seed, ~baseYear, ~baseMonth) | |
| }; | |
| }; | |
| let generateConfig = (~seed, ~baseYear, ~baseMonth): fuzzConfig => { | |
| Random.init(seed); | |
| let modeType = Random.int(3); | |
| switch (modeType) { | |
| | 0 => generateSingleConfig(~seed, ~baseYear, ~baseMonth) | |
| | 1 => generateMultipleConfig(~seed, ~baseYear, ~baseMonth) | |
| | _ => generateRangeConfig(~seed, ~baseYear, ~baseMonth) | |
| }; | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@example/fuzz/FuzzGenerator.re` around lines 174 - 181, generateConfig
currently uses Random.int(3) before seeding the PRNG, making mode selection
non-deterministic; seed the PRNG by calling Random.init(seed) at the start of
generateConfig (before Random.int(3)) so the selection is derived from the
provided seed, and ensure the downstream generators (generateSingleConfig,
generateMultipleConfig, generateRangeConfig) either rely on this seeded state or
do not re-init the RNG in a conflicting way.
| let testFuzzConfig = (name, config) => | ||
| Alcotest.test_case(name, `Quick, () => { | ||
| let _output = runNativeTest(config); | ||
| Alcotest.check(Alcotest.bool)("Native renders successfully", true, true); | ||
| }); |
There was a problem hiding this comment.
Test assertion is a tautology and provides no real verification.
The check Alcotest.check(Alcotest.bool)("Native renders successfully", true, true) always passes. This only confirms that runNativeTest didn't throw an exception, but doesn't validate the rendered output content.
Consider adding meaningful assertions, such as verifying the output contains expected HTML structure or comparing against a snapshot.
💡 Suggested improvement
let testFuzzConfig = (name, config) =>
Alcotest.test_case(name, `Quick, () => {
let _output = runNativeTest(config);
- Alcotest.check(Alcotest.bool)("Native renders successfully", true, true);
+ /* At minimum, verify output is non-empty */
+ Alcotest.check(Alcotest.bool)("Native renders non-empty output", true, String.length(_output) > 0);
});📝 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.
| let testFuzzConfig = (name, config) => | |
| Alcotest.test_case(name, `Quick, () => { | |
| let _output = runNativeTest(config); | |
| Alcotest.check(Alcotest.bool)("Native renders successfully", true, true); | |
| }); | |
| let testFuzzConfig = (name, config) => | |
| Alcotest.test_case(name, `Quick, () => { | |
| let _output = runNativeTest(config); | |
| /* At minimum, verify output is non-empty */ | |
| Alcotest.check(Alcotest.bool)("Native renders non-empty output", true, String.length(_output) > 0); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@example/fuzz/FuzzTestRunner.re` around lines 19 - 23, The testFuzzConfig
helper uses a tautological assertion (Alcotest.check(Alcotest.bool) ... true,
true) which never validates the runNativeTest result; change testFuzzConfig to
capture the value returned by runNativeTest and assert on its contents instead
(for example, call let output = runNativeTest(config) and then use
Alcotest.check(Alcotest.string) or Alcotest.(check (list string)) to verify
expected HTML substrings, DOM markers, or compare against a stored snapshot);
update references in testFuzzConfig and any callers so assertions verify
meaningful properties of output rather than always-true literals.
| single picker and a range picker for the same fixture values in | ||
| `example/shared/SharedFixture.re`, including `footer` via `React.string(...)`. | ||
|
|
||
| ### Run the native renderer |
There was a problem hiding this comment.
Heading levels skip from h1 to h3.
The document jumps directly from # (h1) to ### (h3) without an intermediate ## (h2). This breaks the document outline hierarchy and can affect screen reader navigation.
Consider using ## for these section headings, or adding an intermediate h2 section header.
📝 Suggested fix
-### Run the native renderer
+## Run the native rendererApply similar changes to other ### headings (lines 19, 30, 42, 49).
📝 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.
| ### Run the native renderer | |
| ## Run the native renderer |
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 13-13: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3
(MD001, heading-increment)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@example/README.md` at line 13, Update the skipped heading levels by changing
the "### Run the native renderer" heading to an h2 (## Run the native renderer)
and likewise convert the other top-level section headings currently using "###"
(the headings at the other section titles) to "##" so the document flows from
the existing h1 to h2 before any h3s; ensure subsequent subheadings that are
intended to be nested remain at h3.
@coderabbitai review
Summary by CodeRabbit
New Features
Documentation
Tests