Skip to content

CLI: commands flatten-and-reparse LuCLI args instead of reading argCollection directly (tech debt behind #2855) #2861

Description

@bpamiri

Background

#2856 fixed the --no-* flag family (--no-sqlite, --no-routes, --no-test-db, --no-open-browser) by re-emitting --no-<key> for false values in Module.cfc::argsFromCollection(). That is the correct, minimal bug fix for #2855 and it is shipping. This issue tracks the underlying architectural smell it exposed, which was deliberately out of scope for a bug fix.

The smell

LuCLI parses the command line into a structured argCollection map before dispatching to a module. For wheels new myapp --no-sqlite, the module's new() receives:

argumentCollection = { arg1: "myapp", sqlite: "false" }

(--no-<key> is normalized to <key>=false; see LuceeScriptEngine.parseArguments() in the LuCLI runtime, lines ~335–365.)

cli/lucli/Module.cfc then discards that structure: getArgs()argsFromCollection() flattens the map back into a flat argv string array (["myapp", "--no-sqlite"]), and each command re-parses it with a hand-rolled token loop:

} else if (arg == "--no-sqlite") {
    options.noSQLite = true;
}

So the data flows structured → flattened → re-parsed. getArgs(arguments) is used by ~18 commands.

Why it matters

Proposed direction

Have commands consume argCollection directly (named-arg access: coll.sqlite, coll.arg1) through a small shared typed-arg helper, instead of round-tripping through argv. This removes both the flatten/re-parse layer and the lossy false handling in one move. Large blast radius (~18 commands), hence tracked separately rather than bolted onto the #2856 bug fix.

Related: close the test-robustness gap (smaller, near-term — independent of the refactor)

#2856's unit test hand-builds {sqlite:"false"}, so it validates the re-emit logic but bypasses LuCLI entirely — it cannot catch an upstream LuCLI change to --no-* handling. This is the exact assumption that propagated unverified through triage and both bot reviews. Two cheap improvements:

  • Add an end-to-end assertion in tools/test-onboarding.sh: wheels new <app> --no-sqlite → no db/*.sqlite files, and lucee.json configuration.datasources == {}.
  • Add a comment in argsFromCollection() pinning the LuCLI key=false contract it depends on (LuceeScriptEngine.parseArguments()), so the cross-runtime dependency is discoverable by the next maintainer.

Refs #2855, #2856.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions