Repository navigation
feat(model): report unknown arguments to framework declarations - #4393
Conversation
New strictArguments setting. "warn" (the development default) logs an argument that a declaration doesn't know, once per model or controller, function and argument, with a suggested name; "throw" raises Wheels.UnknownArgument; "off" (the default elsewhere) ignores it as before. Checked: associations, validations, callback registration, property(), table(), the finders (dynamic finders included), caches(), protectsFromForgery(), provides(), usesLayout() and migration column functions. Functions that turn unknown arguments into something (property values, route params, HTML attributes, view variables, filter arguments) are not. Framework calls that passed their own arguments on are trimmed so they don't report: count() no longer passes ifNull to findAll(), addColumn()/changeColumn() pass only column options, and findOrCreateBy() passes only finder options to findOne(). Two core specs passed arguments findAll() ignores (orderby, result); they now use order or drop it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
|
rev1-r3 review @ c718388: code APPROVE (final sign-off after matrix run 37364909140 and PR CI)
Notes, not blocking:
|
Argument names can come from a request (argumentCollection = params), so "warn" stops recording after 500 distinct unknown arguments and logs one line saying so. The guide says to pick request keys rather than pass params straight into a framework function. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
Wheels Test Results35 880 tests 35 155 ✅ 11m 49s ⏱️ Results for commit 4f21e7f. ♻️ This comment has been updated with latest results. |
…ents Signed-off-by: Peter Amiri <peter@alurium.com> # Conflicts: # vendor/wheels/migrator/TableDefinition.cfc
With the null alias merged, t.string(null = false) under strictArguments = "throw" neither throws nor warns and still sets allowNull; the unknown-option spec and the docs use `nullable` instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
|
rev1-r3 review @ 1e7a665: delta APPROVE (final pending narrowed 37389454351 + PR CI) I compared the PR's diff against
The final reads the narrowed run 37389454351 (all engines plus RustCFML × SQLite, which covers both |
|
rev1-r3 @ 1e7a665: matrix side green, final held on the docs-harness
This becomes the final once |
|
rev1-r3 review @ 4f21e7f: APPROVE (final) This head is a develop merge. The PR's own changed lines against
Ready to merge. |
New setting:
strictArgumentsA Wheels function ignores a named argument it doesn't know, so a typo or another framework's name fails silently:
hasMany(foreign_key = "postId"),findAll(orderby = "name"),t.string(nullable = false). The call runs without the option, and the mistake shows up later as wrong data.strictArgumentsreports those arguments:"warn"wheels.logwarning per model or controller, function and argument, for the life of the application, with a suggested namedevelopment"throw"Wheels.UnknownArgumentwith the same text"off"testing,production,maintenanceWhat is checked
Only functions with a fixed set of arguments:
belongsTo(),hasMany(),hasOne(),nestedProperties();validate*();beforeSave(),afterCommit()and the others;property()andtable();findAll(),findOne(),findByKey(),findFirst(),findLastOne()and the dynamic finders;caches(),protectsFromForgery(),provides(),usesLayout();t.string()and the others.Not checked are functions that turn unknown arguments into something: property values, route parameters, HTML attributes, view variables.
filters()is also left out, because its extra named arguments become the filter's arguments.The declared parameters are read from the framework's own definitions (a bare
wheels.Model, or the controller component), so an app override doesn't change them. They're cached for the application's lifetime. When a definition's metadata can't be read, nothing is checked. Documented aliases are accepted:property,method,associations,format. So arefindAll()'sreturnType/keyColumn, and a property passed by name to a dynamic finder.The finders pass arguments on to each other, so an unknown argument is reported once, under the finder the app called (
findOneByEmail(), notfindAll()). A model method that overrides a finder and passes its own arguments on withargumentCollection = argumentsis reported too. The message says to remove them first, and the new guide page and the overriding guide show how.With the setting
"off", a checked call only reads the setting (one small function call) and returns; nothing is cached or looked up.Framework calls that forwarded their own arguments
Running the core suite with the check on found five places where the framework itself passed arguments a function doesn't take. Each is fixed here, and none changes behaviour:
count()passedifNull(appended from its function defaults) through$calculate()tofindAll().$calculate()now keeps it locally.Migration.addColumn()/changeColumn()passed their owntable,referenceNameandaddColumnsintot.<type>(). They now pass only the column options.findOrCreateBy*()passed the property values meant forcreate()tofindOne(). With the check on, it passes only finder options.findOneByEmail(email = ...)) was forwarded after being read into thewhereclause. With the check on, it's dropped first, unless the property is also a finder option.Follow-ups after review
"warn"records.findAll(argumentCollection = params)turns request keys into argument names, so"warn"stops recording after 500 distinct unknown arguments and logs one line saying so. A spec covers it.paramsstraight through".nullalias from fix(migrator): read the pre-3.0 null column option as an alias of allowNull #4395 runs before the strict check.Two specs that passed ignored arguments
callbacksSpec.cfccalledfindAll(orderby = "views DESC");orderbywas ignored. It now usesorder = "views DESC, id".crudSpec.cfccalledfindAll(..., result = "result"); nothing readsresult. Removed.Measured false positives
"warn"forced on in every environment: 0 warnings after the fixes above, 6820 specs passing.wheels-dev/cfwheels-example-app): it's a 2.x layout that can't boot on 4.2, so I scanned it statically with the same accepted lists. 69 checked calls and 18 unknown arguments, allnull=on migration columns. They were true positives when measured: 2.x's column option wasnull, and 3.0 renamed it toallowNullwith no alias, so a 2.xnull = falsecreated a nullable column. fix(migrator): read the pre-3.0 null column option as an alias of allowNull #4395 (merged) restoresnullas a deprecated alias and adds awheels upgrade checkadvisory.$addTypedColumns()mapsnulltoallowNullbefore the strict check runs, so with this PRnullgets the deprecation warning, not an unknown-argument report. A spec pins thatt.string(null = false)under"throw"neither throws nor warns and still setsallowNull.wheels newand generator templates: 0.Specs
vendor/wheels/tests/specs/global/strictArgumentsSpec.cfc:"throw":count(),exists(),findFirst(property),findLastOne(properties), a dynamic finder with a named property;$arguments are ignored."warn": logged once per class, function and argument, with no throw; a finder argument is logged once."off": nothing.The specs that use
"throw"fail before anything is registered, so no shared model class changes.Docs
digging-deeper/strict-arguments.environments-and-configurationand inoverriding-core-methods..ai/models.mdand.ai/migrations.md: consumer copy andwheels newtemplate.addedfragment.Verification
"warn"forced on: 6949/6949. The only warnings logged come from the strict spec's own"warn"cases.🤖 Generated with Claude Code