You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* fix(view): paginationNav rejects unknown sub-helper arguments
paginationNav() built a passthrough struct of unrecognized arguments and
handed it to every sub-helper via argumentCollection. CFML's dispatch
silently drops keys that aren't declared in the receiving signature, so
typos like prependToList="<ul>" had no effect and gave the caller no
signal that the argument was rejected.
After this change, paginationNav() validates the passthrough struct
against the union of its sub-helpers' declared arguments (and the
URL-building keys forwarded by $paginationLinkToArgs). Any leftover keys
throw Wheels.PaginationNav.InvalidArgument when
application.wheels.showErrorInformation is on; the message lists both
the rejected names and the full allowlist. Production environments
(showErrorInformation = false) keep the silent-drop behavior so live
traffic is unaffected.
Fixes#2717
Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
* docs: note paginationNav argument validation in CLAUDE.md
Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
* fix(view): address Reviewer A/B consensus findings (round 1)
- C1: filter out named-route segment variables (forwarded by
$paginationLinkToArgs at link-build time) from the unknown-args list
before throwing, so paginationNav(route="userTimeline", userId=...)
is no longer a false-positive InvalidArgument
(vendor/wheels/view/pagination.cfc)
- C2: hoist the unknown-args validation above the totalPages early
return so the check still fires on single-page (or empty) result
sets — previously a typo against a small dataset was invisible
(vendor/wheels/view/pagination.cfc)
- T1: add a regression spec covering paginationNav(route=..., <segmentVar>=...)
with showErrorInformation=true; verifies the C1 fix and would have
caught the regression
(vendor/wheels/tests/specs/view/paginationHelpersSpec.cfc)
Verified locally against Lucee 7 + SQLite: view layer 517 pass / 0 fail
(was 516 before this commit; the new T1 spec adds one).
Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
* refactor(view): gate paginationNav route-var lookup on showErrorInformation
Round 2 polish from Reviewer A: the $findRoute filter was entered
whenever local.unknownArgs was non-empty and a route was present, even
in production where the final throw is gated. Nest both the route-var
filter and the throw inside a single application.wheels.showErrorInformation
guard so the production path skips the $findRoute lookup entirely. Behavior
in dev mode is unchanged — same filter, same throw, same allowlist.
Also documents the route-variable exemption in CLAUDE.md so a reader of
the pagination section understands that named route segment variables
are auto-exempted from the unknown-arg check.
Local verification on Lucee 7 + SQLite (this worktree):
view layer: 517 pass, 0 fail, 0 error
security layer: 174 pass, 0 fail, 0 error
full core suite: 3557 pass, 0 fail, 0 error
Signed-off-by: Peter Amiri <peter@alurium.com>
---------
Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Signed-off-by: Peter Amiri <peter@alurium.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Peter Amiri <peter@alurium.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,7 @@ All historical references to "CFWheels" in this changelog have been preserved fo
34
34
35
35
### Fixed
36
36
37
+
-`paginationNav()` now throws `Wheels.PaginationNav.InvalidArgument` when passed an argument that none of its sub-helpers (`paginationInfo`, `firstPageLink`, `previousPageLink`, `pageNumberLinks`, `nextPageLink`, `lastPageLink`) accept. Previously, typos such as `prependToList="<ul>"` were silently dropped by CFML's `argumentCollection` dispatch, leaving users to wonder why a styling argument had no effect. The check is gated on `application.wheels.showErrorInformation` so production is unaffected; development environments fail fast and the error names both the rejected arguments and the full allowlist of accepted pass-through keys (#2717)
37
38
-`wheels --help` no longer summarises the `packages` command as `Install, update, search Wheels packages` — that phrasing nudged users to type `wheels packages install <name>`, which LuCLI's built-in extension installer intercepts before module dispatch and silently no-ops (`[INFO] No git or extension dependencies to install`, exit 0, nothing under `vendor/`). The summary now leads with the canonical verb (`Add, update, search ...`) and parenthesises the gotcha so the doc surface stops contradicting the runtime. Same trap that earlier renamed `wheels browser install` to `wheels browser setup` (#2706)
38
39
-`wheels.middleware.Cors` now emits `Vary: Origin` alongside the reflected `Access-Control-Allow-Origin` header so CDN, reverse-proxy, and browser disk caches key the response on the request Origin instead of serving a cached response with the wrong ACAO to a different origin. Matches the behavior of the legacy 3.x `Global.cfc::$setCORSHeaders` path (vendor/wheels/Global.cfc:3565). The header is only emitted when an origin is actually being reflected — wildcard (`allowOrigins="*"`) responses and disallowed-origin responses are unchanged (#2707)
39
40
-`wheels.middleware.Cors` no longer emits the raw comma-delimited `allowOrigins` list as the `Access-Control-Allow-Origin` header value when a request arrives with no `Origin` header (same-origin, server-to-server, or curl-without-`-H`). Previously, the default `local.allowOrigin = variables.allowOrigins` seeded the raw list, and the `Origin`-header guard only reassigned it when an `Origin` was present — so multi-origin configurations like `allowOrigins="https://a.com,https://b.com"` shipped that exact string in the response header, violating the CORS spec requirement that `Access-Control-Allow-Origin` be a single origin or `*`. Origin resolution is now extracted into `$resolveAllowOrigin()` and only returns a value when the incoming `Origin` is in the allowlist (or when `allowOrigins == "*"`); same-origin and S2S responses no longer carry the header at all (#2704)
Copy file name to clipboardExpand all lines: CLAUDE.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -476,6 +476,8 @@ Requires a paginated query: `findAll(page=params.page, perPage=25)`. The recomme
476
476
477
477
Disabled links render as `<span class="disabled">` by default. All helpers accept `handle` for named pagination queries.
478
478
479
+
In development (`showErrorInformation = true`), `paginationNav()` throws `Wheels.PaginationNav.InvalidArgument` if passed an argument not accepted by any of its sub-helpers. Accepted pass-through keys: `format`, `text`, `name`, `class`, `disabledClass`, `showDisabled`, `pageNumberAsParam`, `windowSize`, `classForCurrent`, `linkToCurrentPage`, `prependToPage`, `appendToPage`, `route`, `controller`, `action`, `key`, `anchor`, `onlyPath`, `host`, `protocol`, `port`, `params`. Named route segment variables (e.g., `userId` when `route="userTimeline"` and the pattern contains `[userId]`) are automatically exempted from this check. In production the unknown argument is silently dropped.
480
+
479
481
## Testing Quick Reference
480
482
481
483
**All new tests use WheelsTest BDD syntax.** RocketUnit (`test_` prefix, `assert()`) is legacy only — never use it for new tests.
0 commit comments