Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/3180-cli-legacy-template-enums-leak.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- CLI: the legacy CommandBox-module generator (`cli/src/models/TemplateService.cfc`) substituted `{{belongsToRelationships}}`, `{{hasManyRelationships}}`, `{{hasOneRelationships}}`, and `{{validations}}` but had no branch for the `{{enums}}` placeholder that ships in its model template, so `box wheels generate model` leaked a literal `{{enums}}` into the generated `config()` body as invalid CFML. This legacy path has no enum codegen (unlike the LuCLI generator), so the placeholder is now stripped unconditionally, matching the no-validations fallback (#3180)
50 changes: 50 additions & 0 deletions cli/lucli/tests/specs/services/LegacyTemplateServiceEnumsSpec.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Regression spec for the legacy CommandBox-module generator (`cli/src/`).
*
* The legacy model template (`cli/src/templates/ModelContent.txt`) carries a
* `{{enums}}` placeholder, but `cli/src/models/TemplateService.cfc::processTemplate`
* historically substituted only `{{belongsToRelationships}}`, `{{hasManyRelationships}}`,
* `{{hasOneRelationships}}`, and `{{validations}}` — there was no `{{enums}}` branch, so
* the literal placeholder leaked into the generated `config()` body as invalid CFML.
*
* The legacy path has no enum codegen, so the safe fix is to STRIP the placeholder
* (matching the no-validations fallback). This spec pins that behavior.
*
* See https://github.com/wheels-dev/wheels/issues/3180.
*/
component extends="wheels.wheelstest.system.BaseSpec" {

function run() {

describe("Legacy TemplateService — {{enums}} placeholder", () => {

it("strips the {{enums}} placeholder so it never leaks into generated CFML", () => {
// Instantiate the legacy generator directly (resolves from the test webroot).
var svc = new cli.src.models.TemplateService();
makePublic(svc, "processTemplate");

// Mirror the model template body that ships with the legacy module.
var template = 'component extends="Model" {' & chr(10) &
chr(9) & "function config() {" & chr(10) &
chr(9) & chr(9) & "{{belongsToRelationships}}" & chr(10) &
chr(9) & chr(9) & "{{hasManyRelationships}}" & chr(10) &
chr(9) & chr(9) & "{{hasOneRelationships}}" & chr(10) &
chr(9) & chr(9) & "{{validations}}" & chr(10) &
chr(9) & chr(9) & "{{enums}}" & chr(10) &
chr(9) & "}" & chr(10) &
"}";

var result = svc.processTemplate(template, {});

// The placeholder must be gone — a leaked {{enums}} is invalid CFML.
expect(result).notToInclude("{{enums}}");
// Sanity: the sibling placeholders are still being handled (already stripped).
expect(result).notToInclude("{{validations}}");
expect(result).notToInclude("{{belongsToRelationships}}");
});

});

}

}
9 changes: 8 additions & 1 deletion cli/src/models/TemplateService.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,14 @@ component {
} else {
processed = reReplace(processed, "\{\{validations\}\}", "", "all");
}


// Process enums — this legacy CommandBox-module generator has no enum codegen
// (unlike the LuCLI generator at cli/lucli/services/CodeGen.cfc). The model
// template still carries an {{enums}} placeholder, so strip it unconditionally;
// otherwise the literal {{enums}} leaks into the generated config() body as
// invalid CFML (issue ##3180).
processed = reReplace(processed, "\{\{enums\}\}", "", "all");

// Process actions for controllers
if (structKeyExists(arguments.context, "actions") && isArray(arguments.context.actions)) {
var actionsCode = generateActionsCode(arguments.context.actions);
Expand Down
Loading