-
-
Notifications
You must be signed in to change notification settings - Fork 638
Keep original buildConsoleReplay parameter order (disable ESLint rule) #2097
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Fix ESLint default-param-last rule violation by reordering parameters in buildConsoleReplay and consoleReplay functions. **Changes:** - Reorder consoleReplay parameters: numberOfMessagesToSkip comes first - Reorder buildConsoleReplay parameters: numberOfMessagesToSkip, customConsoleHistory, nonce - Update all call sites in serverRenderReactComponent.ts - Update Pro package streaming to use correct parameter order - Update tests to use new parameter order **Why:** ESLint enforces that optional parameters with defaults must come last. The previous order had customConsoleHistory (with default) before numberOfMessagesToSkip (with default), violating this rule. **Testing:** - ✅ Build passes: yarn run build - ✅ Linting passes: bundle exec rubocop && yarn run eslint - ✅ No breaking changes - all call sites updated 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. WalkthroughImport pattern updated from default to named import for console replay utilities. Type annotations removed from function parameters while preserving default values. New test cases added to verify console message skipping and custom history handling during streaming. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
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 |
Code Review: Refactor buildConsoleReplay Parameter Ordering✅ Overall Assessment: LGTM with minor suggestionsThis is a well-executed refactoring that fixes an ESLint rule violation while improving API ergonomics. The changes are thorough, well-tested, and properly documented. Strengths1. Correctness
2. Breaking Change Handling
3. Documentation
Issues & Suggestions🔴 Critical: Debug Code Left in ProductionLocation: // DEBUG: Log to verify we're using the unwrapped version
if (consoleReplayScript && consoleReplayScript.startsWith('<script')) {
console.error('ERROR: Console replay is wrapped when it should be unwrapped\!');
console.error('First 100 chars:', consoleReplayScript.substring(0, 100));
}Issue: This debug code should be removed before merging. It will pollute server logs in production. Recommendation: Remove these lines entirely or convert to a conditional debug log: if (process.env.NODE_ENV === 'development' && consoleReplayScript?.startsWith('<script')) {
console.warn('Unexpected wrapped console replay:', consoleReplayScript.substring(0, 100));
}
|
- Remove debug console.error statements from streamingUtils.ts - Add documentation explaining why consoleReplay() is used instead of buildConsoleReplay() in streaming contexts (unwrapped JS for JSON payloads vs wrapped for HTML) - Use idiomatic TypeScript optional parameter syntax (nonce?: string) - Add comprehensive test coverage for numberOfMessagesToSkip and customConsoleHistory parameters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/react-on-rails/tests/buildConsoleReplay.test.js (1)
127-173: New consoleReplay tests give good coverage of skip/custom-history behaviorThe three added specs cleanly validate:
- Skipping an initial prefix of messages (
consoleReplay(2)),- Preferring a supplied
customHistoryoverconsole.history,- Combining skip count with a custom history (
consoleReplay(1, customHistory)).They align with the reordered
(numberOfMessagesToSkip, customConsoleHistory)API and assertions usetoContain/not.toContain, so they’re robust to formatting details.One follow‑up you might consider: the global
Console.history.leveltype inbuildConsoleReplay.tscurrently excludes'warn', but these tests (and earlier ones) use'warn'values; widening that union to include'warn'would better match actual usage.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/react-on-rails-pro/src/streamingUtils.ts(2 hunks)packages/react-on-rails/src/buildConsoleReplay.ts(2 hunks)packages/react-on-rails/src/serverRenderReactComponent.ts(3 hunks)packages/react-on-rails/tests/buildConsoleReplay.test.js(4 hunks)
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2025-09-16T08:01:11.146Z
Learnt from: justin808
Repo: shakacode/react_on_rails PR: 1770
File: lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx:2-2
Timestamp: 2025-09-16T08:01:11.146Z
Learning: React on Rails uses webpack CSS Modules configuration with namedExports: true, which requires the import syntax `import * as style from './file.module.css'` rather than the default export pattern. This configuration enables better tree shaking and bundle size optimization for CSS modules.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.tspackages/react-on-rails/src/serverRenderReactComponent.ts
📚 Learning: 2025-04-26T21:55:55.874Z
Learnt from: alexeyr-ci2
Repo: shakacode/react_on_rails PR: 1732
File: spec/dummy/client/app-react16/startup/ReduxSharedStoreApp.client.jsx:40-44
Timestamp: 2025-04-26T21:55:55.874Z
Learning: In the react_on_rails project, files under `app-react16` directories are copied/moved to corresponding `/app` directories during the conversion process (removing the `-react16` suffix), which affects their relative import paths at runtime.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.tspackages/react-on-rails/src/serverRenderReactComponent.ts
📚 Learning: 2024-10-08T20:53:47.076Z
Learnt from: theforestvn88
Repo: shakacode/react_on_rails PR: 1620
File: spec/dummy/client/app/startup/HelloTurboStream.jsx:3-3
Timestamp: 2024-10-08T20:53:47.076Z
Learning: The `RailsContext` import in `spec/dummy/client/app/startup/HelloTurboStream.jsx` is used later in the project, as clarified by the user theforestvn88.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.ts
📚 Learning: 2024-12-12T13:07:09.929Z
Learnt from: alexeyr-ci
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/ReactOnRailsRSC.ts:87-87
Timestamp: 2024-12-12T13:07:09.929Z
Learning: When handling errors in 'node_package/src/ReactOnRailsRSC.ts', include the error stack in error messages in development and test environments to aid debugging.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.tspackages/react-on-rails/src/serverRenderReactComponent.tspackages/react-on-rails/src/buildConsoleReplay.ts
📚 Learning: 2025-02-12T16:38:06.537Z
Learnt from: Romex91
Repo: shakacode/react_on_rails PR: 1697
File: package-scripts.yml:28-28
Timestamp: 2025-02-12T16:38:06.537Z
Learning: The file `node_package/lib/ReactOnRails.full.js` is autogenerated during the build process and should not be present in the repository.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.tspackages/react-on-rails/src/serverRenderReactComponent.ts
📚 Learning: 2025-02-13T19:09:15.991Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/RSCWebpackLoader.ts:0-0
Timestamp: 2025-02-13T19:09:15.991Z
Learning: In React Server Components webpack loader, using `new Function('return import("react-server-dom-webpack/node-loader")')()` is necessary as a workaround to bypass TypeScript compilation issues with direct dynamic imports.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.tspackages/react-on-rails/src/serverRenderReactComponent.ts
📚 Learning: 2025-02-13T16:50:47.848Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/clientStartup.ts:18-21
Timestamp: 2025-02-13T16:50:47.848Z
Learning: In the react_on_rails module, the `reactOnRailsPageUnloaded` function in clientStartup.ts is intentionally kept private as it's only used internally as a callback for `onPageUnloaded`.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.ts
📚 Learning: 2025-07-08T05:57:29.630Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1745
File: node_package/src/RSCRequestTracker.ts:8-14
Timestamp: 2025-07-08T05:57:29.630Z
Learning: The global `generateRSCPayload` function in React on Rails Pro (RORP) is provided by the framework during rendering requests, not implemented in application code. The `declare global` statements are used to document the expected interface that RORP will inject at runtime.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.ts
📚 Learning: 2025-02-18T13:08:01.477Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: lib/react_on_rails/helper.rb:190-197
Timestamp: 2025-02-18T13:08:01.477Z
Learning: RSC support validation in React on Rails Pro is handled through a chain of validations:
1. Pro version check in `run_stream_inside_fiber`
2. RSC support check during pack generation via `ReactOnRailsPro.configuration.enable_rsc_support`
3. RSC support validation during component registration
This makes additional validation in the helper methods unnecessary.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.ts
📚 Learning: 2025-02-18T13:08:01.477Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: lib/react_on_rails/helper.rb:190-197
Timestamp: 2025-02-18T13:08:01.477Z
Learning: RSC support validation is handled in deeper level calls of the React on Rails Pro codebase, so it doesn't need to be validated again in the `rsc_payload_react_component` helper method.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.ts
📚 Learning: 2025-09-15T21:24:48.207Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1781
File: node_package/src/ClientSideRenderer.ts:82-95
Timestamp: 2025-09-15T21:24:48.207Z
Learning: In React on Rails, the force_load feature includes both explicit `data-force-load="true"` usage and the ability to hydrate components during the page loading state (`document.readyState === 'loading'`). Both capabilities require a Pro license, so the condition `!railsContext.rorPro && (isComponentForceLoaded || document.readyState === 'loading')` correctly gates both scenarios.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.ts
📚 Learning: 2025-04-09T13:02:16.009Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1696
File: node_package/src/transformRSCNodeStream.ts:3-31
Timestamp: 2025-04-09T13:02:16.009Z
Learning: In the React Server Components (RSC) stream processing implementation, all chunks end with a newline character (`\n`), so the `lastIncompleteChunk` variable is expected to be empty by the time the stream ends, making a flush handler unnecessary in the Transform stream.
Applied to files:
packages/react-on-rails-pro/src/streamingUtils.ts
🧬 Code graph analysis (3)
packages/react-on-rails/tests/buildConsoleReplay.test.js (2)
packages/react-on-rails/src/buildConsoleReplay.ts (2)
buildConsoleReplay(57-67)consoleReplay(18-55)packages/react-on-rails/src/base/client.ts (1)
buildConsoleReplay(174-176)
packages/react-on-rails-pro/src/streamingUtils.ts (1)
packages/react-on-rails/src/buildConsoleReplay.ts (1)
consoleReplay(18-55)
packages/react-on-rails/src/serverRenderReactComponent.ts (3)
packages/react-on-rails/src/buildConsoleReplay.ts (1)
buildConsoleReplay(57-67)packages/react-on-rails/src/base/client.ts (1)
buildConsoleReplay(174-176)packages/react-on-rails/src/serverRenderUtils.ts (1)
createResultObject(9-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: dummy-app-integration-tests (3.4, 22, latest)
- GitHub Check: build
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: pro-lint-js-and-ruby
- GitHub Check: claude-review
🔇 Additional comments (7)
packages/react-on-rails/src/buildConsoleReplay.ts (2)
18-21: consoleReplay parameter reordering looks correct and preserves behavior
numberOfMessagesToSkipas the first (and defaulted) parameter reads well, and the function body still uses it consistently viaslice(numberOfMessagesToSkip). No behavioral change beyond the signature shape.
57-63: buildConsoleReplay signature and internal call aligned with new APIDefaulted
(numberOfMessagesToSkip = 0, customConsoleHistory = undefined, nonce?)combined withconsoleReplay(numberOfMessagesToSkip, customConsoleHistory)keeps prior semantics while fixing the parameter ordering rule; nonce handling is untouched.packages/react-on-rails/tests/buildConsoleReplay.test.js (1)
79-86: Updated buildConsoleReplay call sites match the new signatureThe changes to
buildConsoleReplay(0, undefined, 'abc123' | maliciousNonce)correctly map to(numberOfMessagesToSkip, customConsoleHistory, nonce)and preserve the previous behavior of “no skipping, default history, custom nonce”.Also applies to: 88-93, 111-125
packages/react-on-rails-pro/src/streamingUtils.ts (1)
20-20: Streaming now correctly uses unwrapped consoleReplay with new parameter orderUsing
{ consoleReplay }and calling it asconsoleReplay(previouslyReplayedConsoleMessages, consoleHistory)matches the new(skipCount, customHistory)signature and is appropriate for embedding plain JS into the streaming JSON payload, leaving script‑tag wrapping to the caller as documented in the comments.Also applies to: 115-121
packages/react-on-rails/src/serverRenderReactComponent.ts (3)
6-6: Import swap to default buildConsoleReplay is consistent with module exportsSwitching from a named
consoleReplayimport to the defaultbuildConsoleReplayaligns this file with the refactored module while keeping the public behavior identical.
109-118: Async result handling still correctly preserves console historyIn
createPromiseResult, callingbuildConsoleReplay(0, consoleHistory)in both the success and error branches continues to rely on the capturedconsoleHistoryreference taken before theawait. This preserves the prior guarantee that logs aren’t lost even if the globalconsole.historyis reset later.
131-132: Final synchronous result now uses buildConsoleReplay with defaulted parameters
buildConsoleReplay()increateFinalResultis a drop‑in replacement for the previousconsoleReplay()usage, adding the script‑tag wrapping while defaulting to “no skip, global history, no nonce”. Behavior for the sync path remains unchanged for callers.
The original parameter order (customConsoleHistory, numberOfMessagesToSkip) was changed to satisfy the ESLint rule @typescript-eslint/default-param-last. However, this change degraded API ergonomics: OLD (natural): consoleReplay(consoleHistory) NEW (forced): consoleReplay(0, consoleHistory) Analysis of all 6 call sites shows: - 3 call sites: Pass only customConsoleHistory (most common) - 2 call sites: Use defaults - 1 call site: Pass both parameters (rare) The new parameter order forces the most common use case to pass an ugly '0' parameter, while the supposed benefit (passing only numberOfMessagesToSkip) is never actually used in the codebase. Disable the ESLint rule for these functions since the original order better matches real-world usage patterns. See PARAMETER_ORDER_ANALYSIS.md for complete analysis.
These documents provide context and analysis for the parameter order refactoring work: - PARAMETER_ORDER_ANALYSIS.md: Detailed analysis of the parameter order issue and rationale for reverting to original order - REVIEW_CHANGES_SUMMARY.md: Summary of code review feedback that was addressed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@claude review this PR |
|
Claude finished @justin808's task —— View job Code Review for PR #2097Status: ✅ APPROVED - Excellent decision to prioritize API ergonomics over lint rules SummaryThis PR demonstrates excellent engineering judgment: it reverts a parameter reordering that would have satisfied an ESLint rule but degraded API usability. The final solution keeps the original, more natural parameter order and disables the ESLint rule with clear justification. 🎯 Key Strengths1. Data-Driven Decision MakingThe
The reordering would have forced the most common use case to become 2. Proper Lint Rule HandlingThe PR shows maturity in understanding when to disable lint rules: // eslint-disable-next-line @typescript-eslint/default-param-last
export function consoleReplay(
customConsoleHistory: (typeof console)['history'] | undefined = undefined,
numberOfMessagesToSkip = 0,
): stringThe rule is valuable in general, but this is a domain-specific case where it doesn't apply. This is the right decision. 3. All Previous Review Issues AddressedComparing to the earlier @claude review comment: ✅ Debug code removed - No 4. Excellent Documentation
📝 Code Quality AssessmentbuildConsoleReplay.tsStatus: ✅ Excellent // eslint-disable-next-line @typescript-eslint/default-param-last
export function consoleReplay(
customConsoleHistory: (typeof console)['history'] | undefined = undefined,
numberOfMessagesToSkip = 0,
): string
serverRenderReactComponent.tsStatus: ✅ Excellent All call sites use the clean, natural API: buildConsoleReplay(consoleHistory) // Clean - captures history before await
buildConsoleReplay() // Clean - uses global historyThis is much better than the forced streamingUtils.ts (Pro)Status: ✅ Excellent // Get unwrapped console replay JavaScript (not wrapped in <script> tags)
// We use consoleReplay() instead of buildConsoleReplay() because streaming
// contexts handle script tag wrapping separately (e.g., with CSP nonces).
// This returns pure JavaScript without wrapping, which is then embedded
// into the result object JSON payload.
const consoleReplayScript = consoleReplay(consoleHistory, previouslyReplayedConsoleMessages);Highlights:
Test CoverageStatus: ✅ Comprehensive Three new test cases added:
All tests use the original parameter order and verify correct behavior. 🔍 Technical ReviewSecurity✅ No concerns
Performance✅ No concerns
Type Safety✅ Excellent
Breaking Changes✅ None
💡 Suggestions (Optional, Non-Blocking)1. Consider Removing Analysis Documents Post-MergeThe analysis documents are excellent for the review process, but they might belong in the PR description or a comment rather than the repository: # Optional cleanup after merge:
git rm PARAMETER_ORDER_ANALYSIS.md REVIEW_CHANGES_SUMMARY.mdReasoning: These are PR-specific and may clutter the repository long-term. However, if you want to keep them for historical reference, consider moving them to 2. ESLint Configuration for Project-Wide PatternIf this parameter pattern occurs elsewhere, consider documenting it: // .eslintrc.js
rules: {
'@typescript-eslint/default-param-last': ['error', {
// Note: Disable on case-by-case basis when parameter order matches
// actual usage patterns better than the rule's assumption
}]
}🎓 Key TakeawayThis PR is a textbook example of:
The ESLint rule ✅ RecommendationAPPROVE AND MERGE - This PR improves the codebase by:
The decision to revert the parameter order and disable the ESLint rule is well-justified and correct. Files Changed (6)
Great work on this refactoring! The analysis and decision-making process is exemplary. | |
Reverted the parameter order changes from the ill-conceived PR #2097. The correct/original parameter order is: - customConsoleHistory first (most common usage pattern) - numberOfMessagesToSkip second (rarely used) This matches what's currently in master and provides better API ergonomics. Updated: - buildConsoleReplay.ts: Restored original parameter order - serverRenderReactComponent.ts: Updated call sites - buildConsoleReplay.test.js: Updated test calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The Rails helper wraps console replay script in <script> tags itself, so we need to use consoleReplay() which returns unwrapped JavaScript, not buildConsoleReplay() which adds <script> tags. This fixes all integration test failures where console replay was empty.
|
Closing this PR. After discussion, we decided to suppress the ESLint rule violation with a comment instead, as the parameter ordering change would be more disruptive than helpful. The rule is suppressed in PR #2094. |
These documents described intermediate refactoring steps that are no longer relevant. The final fix was simply using the unwrapped consoleReplay() function instead of buildConsoleReplay() in serverRenderReactComponent.ts.
After rebasing on master (which merged PR #2097 with parameter order fixes), the ESLint configuration now has the plain 'default-param-last' rule enabled, not the TypeScript version. The buildConsoleReplay function has default params before an optional param (nonce?), which violates the rule. Added block-level eslint-disable comments. The consoleReplay function doesn't violate the rule (all params have defaults), so no disable needed. Fixes CI error: error Default parameters should be last default-param-last 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Summary
REVERTED: After analysis, the parameter reordering was reverted to preserve better API ergonomics. The original parameter order
(customConsoleHistory, numberOfMessagesToSkip)is more natural for the actual usage patterns in the codebase.Problem & Analysis
Initially attempted to fix ESLint
default-param-lastrule violation by reordering parameters. However, analysis of all 6 call sites showed this degraded API quality:Usage Pattern Analysis:
customConsoleHistory(most common)Impact of Reordering:
The ESLint rule optimizes for passing only
numberOfMessagesToSkip, which never happens in the codebase.Final Solution
Kept original parameter order and disabled the ESLint rule with justification:
Changes
Commit 1: Initial Refactor (Reverted)
Commit 2: Code Review Fixes
console.errorstatements from production codeconsoleReplay()vsbuildConsoleReplay()nonceparameter to idiomatic TypeScript syntax (nonce?: string)Commit 3: Parameter Order Reversion ⭐
PARAMETER_ORDER_ANALYSIS.mdfor complete analysisFiles Changed
buildConsoleReplay(consoleHistory)consoleReplay(consoleHistory, skipCount)Testing
yarn run buildbundle exec rubocoprake lint:eslintyarn run type-checkBreaking Change?
No - These are internal functions. All call sites updated to use the original, more natural parameter order.
Key Takeaway
Sometimes lint rules don't fit the domain. This is a case where:
See
PARAMETER_ORDER_ANALYSIS.mdfor detailed analysis of all call sites and rationale.🤖 Generated with Claude Code
Summary by CodeRabbit
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.